block: implement BDRV_O_UNMAP
It is better to present homogeneous hardware independent of the storage technology that is chosen on the host, hence we make discard a host parameter; the user can choose whether to pass it down to the image format and protocol, or to ignore it. Using DISCARD with filesystems can cause very severe fragmentation, so it is left default-off for now. This can change later when we implement the "anchor" operation for efficient management of preallocated files. There is still one choice to make: whether DISCARD has an effect on the dirty bitmap or not. I chose yes, though there is a disadvantage: if the guest is buggy and issues discards for data that is in use, there will be no way to migrate storage for that guest without downgrading the machine type to an older one. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
9a665b2b86
commit
9e8f1835ea
25
block.c
25
block.c
@ -580,6 +580,26 @@ static int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set open flags for a given discard mode
|
||||||
|
*
|
||||||
|
* Return 0 on success, -1 if the discard mode was invalid.
|
||||||
|
*/
|
||||||
|
int bdrv_parse_discard_flags(const char *mode, int *flags)
|
||||||
|
{
|
||||||
|
*flags &= ~BDRV_O_UNMAP;
|
||||||
|
|
||||||
|
if (!strcmp(mode, "off") || !strcmp(mode, "ignore")) {
|
||||||
|
/* do nothing */
|
||||||
|
} else if (!strcmp(mode, "on") || !strcmp(mode, "unmap")) {
|
||||||
|
*flags |= BDRV_O_UNMAP;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set open flags for a given cache mode
|
* Set open flags for a given cache mode
|
||||||
*
|
*
|
||||||
@ -4191,6 +4211,11 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
|
|||||||
bdrv_reset_dirty(bs, sector_num, nb_sectors);
|
bdrv_reset_dirty(bs, sector_num, nb_sectors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Do nothing if disabled. */
|
||||||
|
if (!(bs->open_flags & BDRV_O_UNMAP)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (bs->drv->bdrv_co_discard) {
|
if (bs->drv->bdrv_co_discard) {
|
||||||
return bs->drv->bdrv_co_discard(bs, sector_num, nb_sectors);
|
return bs->drv->bdrv_co_discard(bs, sector_num, nb_sectors);
|
||||||
} else if (bs->drv->bdrv_aio_discard) {
|
} else if (bs->drv->bdrv_aio_discard) {
|
||||||
|
@ -84,6 +84,7 @@ typedef struct BlockDevOps {
|
|||||||
#define BDRV_O_INCOMING 0x0800 /* consistency hint for incoming migration */
|
#define BDRV_O_INCOMING 0x0800 /* consistency hint for incoming migration */
|
||||||
#define BDRV_O_CHECK 0x1000 /* open solely for consistency check */
|
#define BDRV_O_CHECK 0x1000 /* open solely for consistency check */
|
||||||
#define BDRV_O_ALLOW_RDWR 0x2000 /* allow reopen to change from r/o to r/w */
|
#define BDRV_O_ALLOW_RDWR 0x2000 /* allow reopen to change from r/o to r/w */
|
||||||
|
#define BDRV_O_UNMAP 0x4000 /* execute guest UNMAP/TRIM operations */
|
||||||
|
|
||||||
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH)
|
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH)
|
||||||
|
|
||||||
@ -133,6 +134,7 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old);
|
|||||||
void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top);
|
void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top);
|
||||||
void bdrv_delete(BlockDriverState *bs);
|
void bdrv_delete(BlockDriverState *bs);
|
||||||
int bdrv_parse_cache_flags(const char *mode, int *flags);
|
int bdrv_parse_cache_flags(const char *mode, int *flags);
|
||||||
|
int bdrv_parse_discard_flags(const char *mode, int *flags);
|
||||||
int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
|
int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
|
||||||
int bdrv_open_backing_file(BlockDriverState *bs);
|
int bdrv_open_backing_file(BlockDriverState *bs);
|
||||||
int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
|
int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
|
||||||
|
11
qemu-io.c
11
qemu-io.c
@ -1899,7 +1899,7 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
int readonly = 0;
|
int readonly = 0;
|
||||||
int growable = 0;
|
int growable = 0;
|
||||||
const char *sopt = "hVc:rsnmgkt:T:";
|
const char *sopt = "hVc:d:rsnmgkt:T:";
|
||||||
const struct option lopt[] = {
|
const struct option lopt[] = {
|
||||||
{ "help", 0, NULL, 'h' },
|
{ "help", 0, NULL, 'h' },
|
||||||
{ "version", 0, NULL, 'V' },
|
{ "version", 0, NULL, 'V' },
|
||||||
@ -1911,13 +1911,14 @@ int main(int argc, char **argv)
|
|||||||
{ "misalign", 0, NULL, 'm' },
|
{ "misalign", 0, NULL, 'm' },
|
||||||
{ "growable", 0, NULL, 'g' },
|
{ "growable", 0, NULL, 'g' },
|
||||||
{ "native-aio", 0, NULL, 'k' },
|
{ "native-aio", 0, NULL, 'k' },
|
||||||
|
{ "discard", 1, NULL, 'd' },
|
||||||
{ "cache", 1, NULL, 't' },
|
{ "cache", 1, NULL, 't' },
|
||||||
{ "trace", 1, NULL, 'T' },
|
{ "trace", 1, NULL, 'T' },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
int c;
|
int c;
|
||||||
int opt_index = 0;
|
int opt_index = 0;
|
||||||
int flags = 0;
|
int flags = BDRV_O_UNMAP;
|
||||||
|
|
||||||
progname = basename(argv[0]);
|
progname = basename(argv[0]);
|
||||||
|
|
||||||
@ -1929,6 +1930,12 @@ int main(int argc, char **argv)
|
|||||||
case 'n':
|
case 'n':
|
||||||
flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
|
flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
|
||||||
break;
|
break;
|
||||||
|
case 'd':
|
||||||
|
if (bdrv_parse_discard_flags(optarg, &flags) < 0) {
|
||||||
|
error_report("Invalid discard option: %s", optarg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
add_user_command(optarg);
|
add_user_command(optarg);
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user