Skip to content

Commit

Permalink
qemu-img.c: Re-factor img_create()
Browse files Browse the repository at this point in the history
This patch re-factors img_create() moving the code doing the actual
work into block.c where it can be shared with QEMU. This is needed to
be able to create images from QEMU to be used for live snapshots.

Signed-off-by: Jes Sorensen <[email protected]>
Signed-off-by: Kevin Wolf <[email protected]>
  • Loading branch information
Jes Sorensen authored and kevmw committed Dec 17, 2010
1 parent 53f76e5 commit f88e1a4
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 106 deletions.
141 changes: 141 additions & 0 deletions block.c
Original file line number Diff line number Diff line change
Expand Up @@ -2758,3 +2758,144 @@ int64_t bdrv_get_dirty_count(BlockDriverState *bs)
{
return bs->dirty_count;
}

int bdrv_img_create(const char *filename, const char *fmt,
const char *base_filename, const char *base_fmt,
char *options, uint64_t img_size, int flags)
{
QEMUOptionParameter *param = NULL, *create_options = NULL;
QEMUOptionParameter *backing_fmt;
BlockDriverState *bs = NULL;
BlockDriver *drv, *proto_drv;
int ret = 0;

/* Find driver and parse its options */
drv = bdrv_find_format(fmt);
if (!drv) {
error_report("Unknown file format '%s'", fmt);
ret = -1;
goto out;
}

proto_drv = bdrv_find_protocol(filename);
if (!proto_drv) {
error_report("Unknown protocol '%s'", filename);
ret = -1;
goto out;
}

create_options = append_option_parameters(create_options,
drv->create_options);
create_options = append_option_parameters(create_options,
proto_drv->create_options);

/* Create parameter list with default values */
param = parse_option_parameters("", create_options, param);

set_option_parameter_int(param, BLOCK_OPT_SIZE, img_size);

/* Parse -o options */
if (options) {
param = parse_option_parameters(options, create_options, param);
if (param == NULL) {
error_report("Invalid options for file format '%s'.", fmt);
ret = -1;
goto out;
}
}

if (base_filename) {
if (set_option_parameter(param, BLOCK_OPT_BACKING_FILE,
base_filename)) {
error_report("Backing file not supported for file format '%s'",
fmt);
ret = -1;
goto out;
}
}

if (base_fmt) {
if (set_option_parameter(param, BLOCK_OPT_BACKING_FMT, base_fmt)) {
error_report("Backing file format not supported for file "
"format '%s'", fmt);
ret = -1;
goto out;
}
}

backing_fmt = get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
if (backing_fmt && backing_fmt->value.s) {
if (!bdrv_find_format(backing_fmt->value.s)) {
error_report("Unknown backing file format '%s'",
backing_fmt->value.s);
ret = -1;
goto out;
}
}

// The size for the image must always be specified, with one exception:
// If we are using a backing file, we can obtain the size from there
if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) {
QEMUOptionParameter *backing_file =
get_option_parameter(param, BLOCK_OPT_BACKING_FILE);

if (backing_file && backing_file->value.s) {
uint64_t size;
const char *fmt = NULL;
char buf[32];

if (backing_fmt && backing_fmt->value.s) {
fmt = backing_fmt->value.s;
}

bs = bdrv_new("");

ret = bdrv_open(bs, backing_file->value.s, flags, drv);
if (ret < 0) {
error_report("Could not open '%s'", filename);
ret = -1;
goto out;
}
bdrv_get_geometry(bs, &size);
size *= 512;

snprintf(buf, sizeof(buf), "%" PRId64, size);
set_option_parameter(param, BLOCK_OPT_SIZE, buf);
} else {
error_report("Image creation needs a size parameter");
ret = -1;
goto out;
}
}

printf("Formatting '%s', fmt=%s ", filename, fmt);
print_option_parameters(param);
puts("");

ret = bdrv_create(drv, filename, param);

if (ret < 0) {
if (ret == -ENOTSUP) {
error_report("Formatting or formatting option not supported for "
"file format '%s'", fmt);
} else if (ret == -EFBIG) {
error_report("The image size is too large for file format '%s'",
fmt);
} else {
error_report("%s: error while creating %s: %s", filename, fmt,
strerror(-ret));
}
}

out:
free_option_parameters(create_options);
free_option_parameters(param);

if (bs) {
bdrv_delete(bs);
}
if (ret) {
return 1;
}
return 0;
}
4 changes: 4 additions & 0 deletions block.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,10 @@ int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
int64_t pos, int size);

int bdrv_img_create(const char *filename, const char *fmt,
const char *base_filename, const char *base_fmt,
char *options, uint64_t img_size, int flags);

#define BDRV_SECTORS_PER_DIRTY_CHUNK 2048

void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable);
Expand Down
108 changes: 2 additions & 106 deletions qemu-img.c
Original file line number Diff line number Diff line change
Expand Up @@ -288,9 +288,6 @@ static int img_create(int argc, char **argv)
const char *base_fmt = NULL;
const char *filename;
const char *base_filename = NULL;
BlockDriver *drv, *proto_drv;
QEMUOptionParameter *param = NULL, *create_options = NULL;
QEMUOptionParameter *backing_fmt = NULL;
char *options = NULL;

for(;;) {
Expand Down Expand Up @@ -351,110 +348,9 @@ static int img_create(int argc, char **argv)
goto out;
}

/* Find driver and parse its options */
drv = bdrv_find_format(fmt);
if (!drv) {
error("Unknown file format '%s'", fmt);
ret = -1;
goto out;
}

proto_drv = bdrv_find_protocol(filename);
if (!proto_drv) {
error("Unknown protocol '%s'", filename);
ret = -1;
goto out;
}

create_options = append_option_parameters(create_options,
drv->create_options);
create_options = append_option_parameters(create_options,
proto_drv->create_options);

/* Create parameter list with default values */
param = parse_option_parameters("", create_options, param);

set_option_parameter_int(param, BLOCK_OPT_SIZE, img_size);

/* Parse -o options */
if (options) {
param = parse_option_parameters(options, create_options, param);
if (param == NULL) {
error("Invalid options for file format '%s'.", fmt);
ret = -1;
goto out;
}
}

/* Add old-style options to parameters */
ret = add_old_style_options(fmt, param, base_filename, base_fmt);
if (ret < 0) {
goto out;
}

backing_fmt = get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
if (backing_fmt && backing_fmt->value.s) {
if (!bdrv_find_format(backing_fmt->value.s)) {
error("Unknown backing file format '%s'",
backing_fmt->value.s);
ret = -1;
goto out;
}
}

// The size for the image must always be specified, with one exception:
// If we are using a backing file, we can obtain the size from there
if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) {

QEMUOptionParameter *backing_file =
get_option_parameter(param, BLOCK_OPT_BACKING_FILE);

if (backing_file && backing_file->value.s) {
BlockDriverState *bs;
uint64_t size;
const char *fmt = NULL;
char buf[32];

if (backing_fmt && backing_fmt->value.s) {
fmt = backing_fmt->value.s;
}

bs = bdrv_new_open(backing_file->value.s, fmt, BDRV_O_FLAGS);
if (!bs) {
ret = -1;
goto out;
}
bdrv_get_geometry(bs, &size);
size *= 512;
bdrv_delete(bs);

snprintf(buf, sizeof(buf), "%" PRId64, size);
set_option_parameter(param, BLOCK_OPT_SIZE, buf);
} else {
error("Image creation needs a size parameter");
ret = -1;
goto out;
}
}

printf("Formatting '%s', fmt=%s ", filename, fmt);
print_option_parameters(param);
puts("");

ret = bdrv_create(drv, filename, param);

if (ret < 0) {
if (ret == -ENOTSUP) {
error("Formatting or formatting option not supported for file format '%s'", fmt);
} else if (ret == -EFBIG) {
error("The image size is too large for file format '%s'", fmt);
} else {
error("%s: error while creating %s: %s", filename, fmt, strerror(-ret));
}
}
ret = bdrv_img_create(filename, fmt, base_filename, base_fmt,
options, img_size, BDRV_O_FLAGS);
out:
free_option_parameters(create_options);
free_option_parameters(param);
if (ret) {
return 1;
}
Expand Down

0 comments on commit f88e1a4

Please sign in to comment.