version 1.1.1.12, 2018/04/24 18:34:02
|
version 1.1.1.13, 2018/04/24 18:56:18
|
Line 40 typedef struct img_cmd_t {
|
Line 40 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) |
{ |
{ |
Line 64 static void help(void)
|
Line 65 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" |
Line 77 static void help(void)
|
Line 80 static void help(void)
|
" match exactly. The image doesn't need a working backing file before\n" |
" match exactly. The image doesn't need a working backing file before\n" |
" rebasing in this case (useful for renaming the backing file)\n" |
" rebasing in this case (useful for renaming the backing file)\n" |
" '-h' with or without a command shows this help and lists the supported formats\n" |
" '-h' with or without a command shows this help and lists the supported formats\n" |
|
" '-p' show progress of command (only certain commands)\n" |
"\n" |
"\n" |
"Parameters to snapshot subcommand:\n" |
"Parameters to snapshot subcommand:\n" |
" 'snapshot' is the name of the snapshot to create, apply or delete\n" |
" 'snapshot' is the name of the snapshot to create, apply or delete\n" |
Line 179 static int read_password(char *buf, int
|
Line 183 static int read_password(char *buf, int
|
} |
} |
#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; |
Line 303 static int img_create(int argc, char **a
|
Line 328 static int img_create(int argc, char **a
|
fmt = optarg; |
fmt = optarg; |
break; |
break; |
case 'e': |
case 'e': |
error_report("qemu-img: option -e is deprecated, please use \'-o " |
error_report("option -e is deprecated, please use \'-o " |
"encryption\' instead!"); |
"encryption\' instead!"); |
return 1; |
return 1; |
case '6': |
case '6': |
error_report("qemu-img: option -6 is deprecated, please use \'-o " |
error_report("option -6 is deprecated, please use \'-o " |
"compat6\' instead!"); |
"compat6\' instead!"); |
return 1; |
return 1; |
case 'o': |
case 'o': |
Line 440 static int img_check(int argc, char **ar
|
Line 465 static int img_check(int argc, char **ar
|
|
|
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; |
} |
} |
Line 458 static int img_commit(int argc, char **a
|
Line 484 static int img_commit(int argc, char **a
|
case 'f': |
case 'f': |
fmt = optarg; |
fmt = optarg; |
break; |
break; |
|
case 't': |
|
cache = optarg; |
|
break; |
} |
} |
} |
} |
if (optind >= argc) { |
if (optind >= argc) { |
Line 465 static int img_commit(int argc, char **a
|
Line 494 static int img_commit(int argc, char **a
|
} |
} |
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; |
} |
} |
Line 495 static int img_commit(int argc, char **a
|
Line 531 static int img_commit(int argc, char **a
|
return 0; |
return 0; |
} |
} |
|
|
|
/* |
|
* Checks whether the sector is not a zero sector. |
|
* |
|
* Attention! The len must be a multiple of 4 * sizeof(long) due to |
|
* restriction of optimizations in this function. |
|
*/ |
static int is_not_zero(const uint8_t *sector, int len) |
static int is_not_zero(const uint8_t *sector, int len) |
{ |
{ |
|
/* |
|
* Use long as the biggest available internal data type that fits into the |
|
* CPU register and unroll the loop to smooth out the effect of memory |
|
* latency. |
|
*/ |
|
|
int i; |
int i; |
len >>= 2; |
long d0, d1, d2, d3; |
for(i = 0;i < len; i++) { |
const long * const data = (const long *) sector; |
if (((uint32_t *)sector)[i] != 0) |
|
|
len /= sizeof(long); |
|
|
|
for(i = 0; i < len; i += 4) { |
|
d0 = data[i + 0]; |
|
d1 = data[i + 1]; |
|
d2 = data[i + 2]; |
|
d3 = data[i + 3]; |
|
|
|
if (d0 || d1 || d2 || d3) { |
return 1; |
return 1; |
|
} |
} |
} |
|
|
return 0; |
return 0; |
} |
} |
|
|
Line 567 static int compare_sectors(const uint8_t
|
Line 626 static int compare_sectors(const uint8_t
|
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; |
const char *fmt, *out_fmt, *out_baseimg, *out_filename; |
int progress = 0, flags; |
|
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; |
Line 579 static int img_convert(int argc, char **
|
Line 639 static int img_convert(int argc, char **
|
QEMUOptionParameter *out_baseimg_param; |
QEMUOptionParameter *out_baseimg_param; |
char *options = NULL; |
char *options = NULL; |
const char *snapshot_name = NULL; |
const char *snapshot_name = NULL; |
|
float local_progress; |
|
|
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:"); |
c = getopt(argc, argv, "f:O:B:s:hce6o:pt:"); |
if (c == -1) { |
if (c == -1) { |
break; |
break; |
} |
} |
Line 607 static int img_convert(int argc, char **
|
Line 669 static int img_convert(int argc, char **
|
compress = 1; |
compress = 1; |
break; |
break; |
case 'e': |
case 'e': |
error_report("qemu-img: option -e is deprecated, please use \'-o " |
error_report("option -e is deprecated, please use \'-o " |
"encryption\' instead!"); |
"encryption\' instead!"); |
return 1; |
return 1; |
case '6': |
case '6': |
error_report("qemu-img: option -6 is deprecated, please use \'-o " |
error_report("option -6 is deprecated, please use \'-o " |
"compat6\' instead!"); |
"compat6\' instead!"); |
return 1; |
return 1; |
case 'o': |
case 'o': |
Line 620 static int img_convert(int argc, char **
|
Line 682 static int img_convert(int argc, char **
|
case 's': |
case 's': |
snapshot_name = optarg; |
snapshot_name = optarg; |
break; |
break; |
|
case 'p': |
|
progress = 1; |
|
break; |
|
case 't': |
|
cache = optarg; |
|
break; |
} |
} |
} |
} |
|
|
Line 642 static int img_convert(int argc, char **
|
Line 710 static int img_convert(int argc, char **
|
goto out; |
goto out; |
} |
} |
|
|
|
qemu_progress_init(progress, 2.0); |
|
qemu_progress_print(0, 100); |
|
|
bs = qemu_mallocz(bs_n * sizeof(BlockDriverState *)); |
bs = qemu_mallocz(bs_n * sizeof(BlockDriverState *)); |
|
|
total_sectors = 0; |
total_sectors = 0; |
Line 658 static int img_convert(int argc, char **
|
Line 729 static int img_convert(int argc, char **
|
|
|
if (snapshot_name != NULL) { |
if (snapshot_name != NULL) { |
if (bs_n > 1) { |
if (bs_n > 1) { |
error_report("No support for concatenating multiple snapshot\n"); |
error_report("No support for concatenating multiple snapshot"); |
ret = -1; |
ret = -1; |
goto out; |
goto out; |
} |
} |
if (bdrv_snapshot_load_tmp(bs[0], snapshot_name) < 0) { |
if (bdrv_snapshot_load_tmp(bs[0], snapshot_name) < 0) { |
error_report("Failed to load snapshot\n"); |
error_report("Failed to load snapshot"); |
ret = -1; |
ret = -1; |
goto out; |
goto out; |
} |
} |
Line 747 static int img_convert(int argc, char **
|
Line 818 static int img_convert(int argc, char **
|
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; |
Line 773 static int img_convert(int argc, char **
|
Line 850 static int img_convert(int argc, char **
|
} |
} |
cluster_sectors = cluster_size >> 9; |
cluster_sectors = cluster_size >> 9; |
sector_num = 0; |
sector_num = 0; |
|
|
|
nb_sectors = total_sectors; |
|
local_progress = (float)100 / |
|
(nb_sectors / MIN(nb_sectors, cluster_sectors)); |
|
|
for(;;) { |
for(;;) { |
int64_t bs_num; |
int64_t bs_num; |
int remainder; |
int remainder; |
Line 832 static int img_convert(int argc, char **
|
Line 914 static int img_convert(int argc, char **
|
} |
} |
} |
} |
sector_num += n; |
sector_num += n; |
|
qemu_progress_print(local_progress, 100); |
} |
} |
/* signal EOF to align */ |
/* signal EOF to align */ |
bdrv_write_compressed(out_bs, 0, NULL, 0); |
bdrv_write_compressed(out_bs, 0, NULL, 0); |
Line 839 static int img_convert(int argc, char **
|
Line 922 static int img_convert(int argc, char **
|
int has_zero_init = bdrv_has_zero_init(out_bs); |
int has_zero_init = bdrv_has_zero_init(out_bs); |
|
|
sector_num = 0; // total number of sectors converted so far |
sector_num = 0; // total number of sectors converted so far |
|
nb_sectors = total_sectors - sector_num; |
|
local_progress = (float)100 / |
|
(nb_sectors / MIN(nb_sectors, IO_BUF_SIZE / 512)); |
|
|
for(;;) { |
for(;;) { |
nb_sectors = total_sectors - sector_num; |
nb_sectors = total_sectors - sector_num; |
if (nb_sectors <= 0) { |
if (nb_sectors <= 0) { |
Line 912 static int img_convert(int argc, char **
|
Line 999 static int img_convert(int argc, char **
|
n -= n1; |
n -= n1; |
buf1 += n1 * 512; |
buf1 += n1 * 512; |
} |
} |
|
qemu_progress_print(local_progress, 100); |
} |
} |
} |
} |
out: |
out: |
|
qemu_progress_end(); |
free_option_parameters(create_options); |
free_option_parameters(create_options); |
free_option_parameters(param); |
free_option_parameters(param); |
qemu_free(buf); |
qemu_free(buf); |
Line 935 out:
|
Line 1024 out:
|
return 0; |
return 0; |
} |
} |
|
|
#ifdef _WIN32 |
|
static int64_t get_allocated_file_size(const char *filename) |
|
{ |
|
typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high); |
|
get_compressed_t get_compressed; |
|
struct _stati64 st; |
|
|
|
/* WinNT support GetCompressedFileSize to determine allocate size */ |
|
get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA"); |
|
if (get_compressed) { |
|
DWORD high, low; |
|
low = get_compressed(filename, &high); |
|
if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR) |
|
return (((int64_t) high) << 32) + low; |
|
} |
|
|
|
if (_stati64(filename, &st) < 0) |
|
return -1; |
|
return st.st_size; |
|
} |
|
#else |
|
static int64_t get_allocated_file_size(const char *filename) |
|
{ |
|
struct stat st; |
|
if (stat(filename, &st) < 0) |
|
return -1; |
|
return (int64_t)st.st_blocks * 512; |
|
} |
|
#endif |
|
|
|
static void dump_snapshots(BlockDriverState *bs) |
static void dump_snapshots(BlockDriverState *bs) |
{ |
{ |
Line 1023 static int img_info(int argc, char **arg
|
Line 1083 static int img_info(int argc, char **arg
|
bdrv_get_format(bs, fmt_name, sizeof(fmt_name)); |
bdrv_get_format(bs, fmt_name, sizeof(fmt_name)); |
bdrv_get_geometry(bs, &total_sectors); |
bdrv_get_geometry(bs, &total_sectors); |
get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512); |
get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512); |
allocated_size = get_allocated_file_size(filename); |
allocated_size = bdrv_get_allocated_file_size(bs); |
if (allocated_size < 0) { |
if (allocated_size < 0) { |
snprintf(dsize_buf, sizeof(dsize_buf), "unavailable"); |
snprintf(dsize_buf, sizeof(dsize_buf), "unavailable"); |
} else { |
} else { |
Line 1181 static int img_rebase(int argc, char **a
|
Line 1241 static int img_rebase(int argc, char **a
|
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; |
|
|
/* 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:"); |
c = getopt(argc, argv, "uhf:F:b:pt:"); |
if (c == -1) { |
if (c == -1) { |
break; |
break; |
} |
} |
Line 1212 static int img_rebase(int argc, char **a
|
Line 1273 static int img_rebase(int argc, char **a
|
case 'u': |
case 'u': |
unsafe = 1; |
unsafe = 1; |
break; |
break; |
|
case 'p': |
|
progress = 1; |
|
break; |
|
case 't': |
|
cache = optarg; |
|
break; |
} |
} |
} |
} |
|
|
if ((optind >= argc) || !out_baseimg) { |
if ((optind >= argc) || (!unsafe && !out_baseimg)) { |
help(); |
help(); |
} |
} |
filename = argv[optind++]; |
filename = argv[optind++]; |
|
|
|
qemu_progress_init(progress, 2.0); |
|
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; |
Line 1295 static int img_rebase(int argc, char **a
|
Line 1371 static int img_rebase(int argc, char **a
|
int n; |
int n; |
uint8_t * buf_old; |
uint8_t * buf_old; |
uint8_t * buf_new; |
uint8_t * buf_new; |
|
float local_progress; |
|
|
buf_old = qemu_malloc(IO_BUF_SIZE); |
buf_old = qemu_malloc(IO_BUF_SIZE); |
buf_new = qemu_malloc(IO_BUF_SIZE); |
buf_new = qemu_malloc(IO_BUF_SIZE); |
|
|
bdrv_get_geometry(bs, &num_sectors); |
bdrv_get_geometry(bs, &num_sectors); |
|
|
|
local_progress = (float)100 / |
|
(num_sectors / MIN(num_sectors, IO_BUF_SIZE / 512)); |
for (sector = 0; sector < num_sectors; sector += n) { |
for (sector = 0; sector < num_sectors; sector += n) { |
|
|
/* How many sectors can we handle with the next read? */ |
/* How many sectors can we handle with the next read? */ |
Line 1348 static int img_rebase(int argc, char **a
|
Line 1427 static int img_rebase(int argc, char **a
|
|
|
written += pnum; |
written += pnum; |
} |
} |
|
qemu_progress_print(local_progress, 100); |
} |
} |
|
|
qemu_free(buf_old); |
qemu_free(buf_old); |
Line 1368 static int img_rebase(int argc, char **a
|
Line 1448 static int img_rebase(int argc, char **a
|
out_baseimg, strerror(-ret)); |
out_baseimg, strerror(-ret)); |
} |
} |
|
|
|
qemu_progress_print(100, 0); |
/* |
/* |
* TODO At this point it is possible to check if any clusters that are |
* TODO At this point it is possible to check if any clusters that are |
* allocated in the COW file are the same in the backing file. If so, they |
* allocated in the COW file are the same in the backing file. If so, they |
Line 1375 static int img_rebase(int argc, char **a
|
Line 1456 static int img_rebase(int argc, char **a
|
* backing file, in case of a crash this would lead to corruption. |
* backing file, in case of a crash this would lead to corruption. |
*/ |
*/ |
out: |
out: |
|
qemu_progress_end(); |
/* Cleanup */ |
/* Cleanup */ |
if (!unsafe) { |
if (!unsafe) { |
bdrv_delete(bs_old_backing); |
if (bs_old_backing != NULL) { |
bdrv_delete(bs_new_backing); |
bdrv_delete(bs_old_backing); |
|
} |
|
if (bs_new_backing != NULL) { |
|
bdrv_delete(bs_new_backing); |
|
} |
} |
} |
|
|
bdrv_delete(bs); |
bdrv_delete(bs); |
Line 1404 static int img_resize(int argc, char **a
|
Line 1490 static int img_resize(int argc, char **a
|
{ NULL } |
{ NULL } |
}; |
}; |
|
|
|
/* Remove size from argv manually so that negative numbers are not treated |
|
* as options by getopt. */ |
|
if (argc < 3) { |
|
help(); |
|
return 1; |
|
} |
|
|
|
size = argv[--argc]; |
|
|
|
/* Parse getopt arguments */ |
fmt = NULL; |
fmt = NULL; |
for(;;) { |
for(;;) { |
c = getopt(argc, argv, "f:h"); |
c = getopt(argc, argv, "f:h"); |
Line 1420 static int img_resize(int argc, char **a
|
Line 1516 static int img_resize(int argc, char **a
|
break; |
break; |
} |
} |
} |
} |
if (optind + 1 >= argc) { |
if (optind >= argc) { |
help(); |
help(); |
} |
} |
filename = argv[optind++]; |
filename = argv[optind++]; |
size = argv[optind++]; |
|
|
|
/* Choose grow, shrink, or absolute resize mode */ |
/* Choose grow, shrink, or absolute resize mode */ |
switch (size[0]) { |
switch (size[0]) { |