qemu-img: Add cache command line option

qemu-img currently writes disk images using writeback and filling
up the cache buffers which are then flushed by the kernel preventing
other processes from accessing the storage.
This is particularly bad in cluster environments where time-based
algorithms might be in place and accessing the storage within
certain timeouts is critical.
This patch adds the option to choose a cache method when writing
disk images.

Signed-off-by: Federico Simoncelli <fsimonce@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Federico Simoncelli 2011-06-20 12:48:19 -04:00 committed by Kevin Wolf
parent 02854532c2
commit 661a0f712b
2 changed files with 70 additions and 16 deletions

View File

@ -22,13 +22,13 @@ STEXI
ETEXI ETEXI
DEF("commit", img_commit, DEF("commit", img_commit,
"commit [-f fmt] filename") "commit [-f fmt] [-t cache] filename")
STEXI STEXI
@item commit [-f @var{fmt}] @var{filename} @item commit [-f @var{fmt}] @var{filename}
ETEXI ETEXI
DEF("convert", img_convert, DEF("convert", img_convert,
"convert [-c] [-p] [-f fmt] [-O output_fmt] [-o options] [-s snapshot_name] filename [filename2 [...]] output_filename") "convert [-c] [-p] [-f fmt] [-t cache] [-O output_fmt] [-o options] [-s snapshot_name] filename [filename2 [...]] output_filename")
STEXI STEXI
@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename} @item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename}
ETEXI ETEXI
@ -46,7 +46,7 @@ STEXI
ETEXI ETEXI
DEF("rebase", img_rebase, DEF("rebase", img_rebase,
"rebase [-f fmt] [-p] [-u] -b backing_file [-F backing_fmt] filename") "rebase [-f fmt] [-t cache] [-p] [-u] -b backing_file [-F backing_fmt] filename")
STEXI STEXI
@item rebase [-f @var{fmt}] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename} @item rebase [-f @var{fmt}] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
ETEXI ETEXI

View File

@ -40,6 +40,7 @@ typedef struct img_cmd_t {
/* Default to cache=writeback as data integrity is not important for qemu-tcg. */ /* Default to cache=writeback as data integrity is not important for qemu-tcg. */
#define BDRV_O_FLAGS BDRV_O_CACHE_WB #define BDRV_O_FLAGS BDRV_O_CACHE_WB
#define BDRV_DEFAULT_CACHE "writeback"
static void format_print(void *opaque, const char *name) static void format_print(void *opaque, const char *name)
{ {
@ -64,6 +65,8 @@ static void help(void)
"Command parameters:\n" "Command parameters:\n"
" 'filename' is a disk image filename\n" " 'filename' is a disk image filename\n"
" 'fmt' is the disk image format. It is guessed automatically in most cases\n" " 'fmt' is the disk image format. It is guessed automatically in most cases\n"
" 'cache' is the cache mode used to write the output disk image, the valid\n"
" options are: 'none', 'writeback' (default), 'writethrough' and 'unsafe'\n"
" 'size' is the disk image size in bytes. Optional suffixes\n" " 'size' is the disk image size in bytes. Optional suffixes\n"
" 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n" " 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n"
" and T (terabyte, 1024G) are supported. 'b' is ignored.\n" " and T (terabyte, 1024G) are supported. 'b' is ignored.\n"
@ -180,6 +183,27 @@ static int read_password(char *buf, int buf_size)
} }
#endif #endif
static int set_cache_flag(const char *mode, int *flags)
{
*flags &= ~BDRV_O_CACHE_MASK;
if (!strcmp(mode, "none") || !strcmp(mode, "off")) {
*flags |= BDRV_O_CACHE_WB;
*flags |= BDRV_O_NOCACHE;
} else if (!strcmp(mode, "writeback")) {
*flags |= BDRV_O_CACHE_WB;
} else if (!strcmp(mode, "unsafe")) {
*flags |= BDRV_O_CACHE_WB;
*flags |= BDRV_O_NO_FLUSH;
} else if (!strcmp(mode, "writethrough")) {
/* this is the default */
} else {
return -1;
}
return 0;
}
static int print_block_option_help(const char *filename, const char *fmt) static int print_block_option_help(const char *filename, const char *fmt)
{ {
BlockDriver *drv, *proto_drv; BlockDriver *drv, *proto_drv;
@ -441,13 +465,14 @@ static int img_check(int argc, char **argv)
static int img_commit(int argc, char **argv) static int img_commit(int argc, char **argv)
{ {
int c, ret; int c, ret, flags;
const char *filename, *fmt; const char *filename, *fmt, *cache;
BlockDriverState *bs; BlockDriverState *bs;
fmt = NULL; fmt = NULL;
cache = BDRV_DEFAULT_CACHE;
for(;;) { for(;;) {
c = getopt(argc, argv, "f:h"); c = getopt(argc, argv, "f:ht:");
if (c == -1) { if (c == -1) {
break; break;
} }
@ -459,6 +484,9 @@ static int img_commit(int argc, char **argv)
case 'f': case 'f':
fmt = optarg; fmt = optarg;
break; break;
case 't':
cache = optarg;
break;
} }
} }
if (optind >= argc) { if (optind >= argc) {
@ -466,7 +494,14 @@ static int img_commit(int argc, char **argv)
} }
filename = argv[optind++]; filename = argv[optind++];
bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR); flags = BDRV_O_RDWR;
ret = set_cache_flag(cache, &flags);
if (ret < 0) {
error_report("Invalid cache option: %s", cache);
return -1;
}
bs = bdrv_new_open(filename, fmt, flags);
if (!bs) { if (!bs) {
return 1; return 1;
} }
@ -591,8 +626,8 @@ static int compare_sectors(const uint8_t *buf1, const uint8_t *buf2, int n,
static int img_convert(int argc, char **argv) static int img_convert(int argc, char **argv)
{ {
int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size, cluster_sectors; int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size, cluster_sectors;
int progress = 0; int progress = 0, flags;
const char *fmt, *out_fmt, *out_baseimg, *out_filename; const char *fmt, *out_fmt, *cache, *out_baseimg, *out_filename;
BlockDriver *drv, *proto_drv; BlockDriver *drv, *proto_drv;
BlockDriverState **bs = NULL, *out_bs = NULL; BlockDriverState **bs = NULL, *out_bs = NULL;
int64_t total_sectors, nb_sectors, sector_num, bs_offset; int64_t total_sectors, nb_sectors, sector_num, bs_offset;
@ -608,10 +643,11 @@ static int img_convert(int argc, char **argv)
fmt = NULL; fmt = NULL;
out_fmt = "raw"; out_fmt = "raw";
cache = "unsafe";
out_baseimg = NULL; out_baseimg = NULL;
compress = 0; compress = 0;
for(;;) { for(;;) {
c = getopt(argc, argv, "f:O:B:s:hce6o:p"); c = getopt(argc, argv, "f:O:B:s:hce6o:pt:");
if (c == -1) { if (c == -1) {
break; break;
} }
@ -649,6 +685,9 @@ static int img_convert(int argc, char **argv)
case 'p': case 'p':
progress = 1; progress = 1;
break; break;
case 't':
cache = optarg;
break;
} }
} }
@ -779,8 +818,14 @@ static int img_convert(int argc, char **argv)
goto out; goto out;
} }
out_bs = bdrv_new_open(out_filename, out_fmt, flags = BDRV_O_RDWR;
BDRV_O_FLAGS | BDRV_O_RDWR | BDRV_O_NO_FLUSH); ret = set_cache_flag(cache, &flags);
if (ret < 0) {
error_report("Invalid cache option: %s", cache);
return -1;
}
out_bs = bdrv_new_open(out_filename, out_fmt, flags);
if (!out_bs) { if (!out_bs) {
ret = -1; ret = -1;
goto out; goto out;
@ -1225,18 +1270,18 @@ static int img_rebase(int argc, char **argv)
BlockDriverState *bs, *bs_old_backing = NULL, *bs_new_backing = NULL; BlockDriverState *bs, *bs_old_backing = NULL, *bs_new_backing = NULL;
BlockDriver *old_backing_drv, *new_backing_drv; BlockDriver *old_backing_drv, *new_backing_drv;
char *filename; char *filename;
const char *fmt, *out_basefmt, *out_baseimg; const char *fmt, *cache, *out_basefmt, *out_baseimg;
int c, flags, ret; int c, flags, ret;
int unsafe = 0; int unsafe = 0;
int progress = 0; int progress = 0;
/* Parse commandline parameters */ /* Parse commandline parameters */
fmt = NULL; fmt = NULL;
cache = BDRV_DEFAULT_CACHE;
out_baseimg = NULL; out_baseimg = NULL;
out_basefmt = NULL; out_basefmt = NULL;
for(;;) { for(;;) {
c = getopt(argc, argv, "uhf:F:b:p"); c = getopt(argc, argv, "uhf:F:b:pt:");
if (c == -1) { if (c == -1) {
break; break;
} }
@ -1260,6 +1305,9 @@ static int img_rebase(int argc, char **argv)
case 'p': case 'p':
progress = 1; progress = 1;
break; break;
case 't':
cache = optarg;
break;
} }
} }
@ -1271,13 +1319,19 @@ static int img_rebase(int argc, char **argv)
qemu_progress_init(progress, 2.0); qemu_progress_init(progress, 2.0);
qemu_progress_print(0, 100); qemu_progress_print(0, 100);
flags = BDRV_O_RDWR | (unsafe ? BDRV_O_NO_BACKING : 0);
ret = set_cache_flag(cache, &flags);
if (ret < 0) {
error_report("Invalid cache option: %s", cache);
return -1;
}
/* /*
* Open the images. * Open the images.
* *
* Ignore the old backing file for unsafe rebase in case we want to correct * Ignore the old backing file for unsafe rebase in case we want to correct
* the reference to a renamed or moved backing file. * the reference to a renamed or moved backing file.
*/ */
flags = BDRV_O_FLAGS | BDRV_O_RDWR | (unsafe ? BDRV_O_NO_BACKING : 0);
bs = bdrv_new_open(filename, fmt, flags); bs = bdrv_new_open(filename, fmt, flags);
if (!bs) { if (!bs) {
return 1; return 1;