diff options
43 files changed, 1096 insertions, 1203 deletions
@@ -424,7 +424,7 @@ BlockDriver *bdrv_find_whitelisted_format(const char *format_name, typedef struct CreateCo { BlockDriver *drv; char *filename; - QEMUOptionParameter *options; + QemuOpts *opts; int ret; Error *err; } CreateCo; @@ -437,7 +437,7 @@ static void coroutine_fn bdrv_create_co_entry(void *opaque) CreateCo *cco = opaque; assert(cco->drv); - ret = cco->drv->bdrv_create(cco->filename, cco->options, &local_err); + ret = cco->drv->bdrv_create(cco->filename, cco->opts, &local_err); if (local_err) { error_propagate(&cco->err, local_err); } @@ -445,7 +445,7 @@ static void coroutine_fn bdrv_create_co_entry(void *opaque) } int bdrv_create(BlockDriver *drv, const char* filename, - QEMUOptionParameter *options, Error **errp) + QemuOpts *opts, Error **errp) { int ret; @@ -453,7 +453,7 @@ int bdrv_create(BlockDriver *drv, const char* filename, CreateCo cco = { .drv = drv, .filename = g_strdup(filename), - .options = options, + .opts = opts, .ret = NOT_DONE, .err = NULL, }; @@ -489,8 +489,7 @@ out: return ret; } -int bdrv_create_file(const char* filename, QEMUOptionParameter *options, - Error **errp) +int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp) { BlockDriver *drv; Error *local_err = NULL; @@ -502,7 +501,7 @@ int bdrv_create_file(const char* filename, QEMUOptionParameter *options, return -ENOENT; } - ret = bdrv_create(drv, filename, options, &local_err); + ret = bdrv_create(drv, filename, opts, &local_err); if (local_err) { error_propagate(errp, local_err); } @@ -1247,7 +1246,7 @@ void bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp) char *tmp_filename = g_malloc0(PATH_MAX + 1); int64_t total_size; BlockDriver *bdrv_qcow2; - QEMUOptionParameter *create_options; + QemuOpts *opts = NULL; QDict *snapshot_options; BlockDriverState *bs_snapshot; Error *local_err; @@ -1272,13 +1271,11 @@ void bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp) } bdrv_qcow2 = bdrv_find_format("qcow2"); - create_options = parse_option_parameters("", bdrv_qcow2->create_options, - NULL); - - set_option_parameter_int(create_options, BLOCK_OPT_SIZE, total_size); - - ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options, &local_err); - free_option_parameters(create_options); + opts = qemu_opts_create(bdrv_qcow2->create_opts, NULL, 0, + &error_abort); + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_size); + ret = bdrv_create(bdrv_qcow2, tmp_filename, opts, &local_err); + qemu_opts_del(opts); if (ret < 0) { error_setg_errno(errp, -ret, "Could not create temporary overlay " "'%s': %s", tmp_filename, @@ -5519,8 +5516,10 @@ void bdrv_img_create(const char *filename, const char *fmt, char *options, uint64_t img_size, int flags, Error **errp, bool quiet) { - QEMUOptionParameter *param = NULL, *create_options = NULL; - QEMUOptionParameter *backing_fmt, *backing_file, *size; + QemuOptsList *create_opts = NULL; + QemuOpts *opts = NULL; + const char *backing_fmt, *backing_file; + int64_t size; BlockDriver *drv, *proto_drv; BlockDriver *backing_drv = NULL; Error *local_err = NULL; @@ -5539,28 +5538,23 @@ void bdrv_img_create(const char *filename, const char *fmt, return; } - create_options = append_option_parameters(create_options, - drv->create_options); - create_options = append_option_parameters(create_options, - proto_drv->create_options); + create_opts = qemu_opts_append(create_opts, drv->create_opts); + create_opts = qemu_opts_append(create_opts, proto_drv->create_opts); /* Create parameter list with default values */ - param = parse_option_parameters("", create_options, param); - - set_option_parameter_int(param, BLOCK_OPT_SIZE, img_size); + opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size); /* Parse -o options */ if (options) { - param = parse_option_parameters(options, create_options, param); - if (param == NULL) { - error_setg(errp, "Invalid options for file format '%s'.", fmt); + if (qemu_opts_do_parse(opts, options, NULL) != 0) { + error_setg(errp, "Invalid options for file format '%s'", fmt); goto out; } } if (base_filename) { - if (set_option_parameter(param, BLOCK_OPT_BACKING_FILE, - base_filename)) { + if (qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename)) { error_setg(errp, "Backing file not supported for file format '%s'", fmt); goto out; @@ -5568,37 +5562,37 @@ void bdrv_img_create(const char *filename, const char *fmt, } if (base_fmt) { - if (set_option_parameter(param, BLOCK_OPT_BACKING_FMT, base_fmt)) { + if (qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt)) { error_setg(errp, "Backing file format not supported for file " "format '%s'", fmt); goto out; } } - backing_file = get_option_parameter(param, BLOCK_OPT_BACKING_FILE); - if (backing_file && backing_file->value.s) { - if (!strcmp(filename, backing_file->value.s)) { + backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE); + if (backing_file) { + if (!strcmp(filename, backing_file)) { error_setg(errp, "Error: Trying to create an image with the " "same filename as the backing file"); goto out; } } - backing_fmt = get_option_parameter(param, BLOCK_OPT_BACKING_FMT); - if (backing_fmt && backing_fmt->value.s) { - backing_drv = bdrv_find_format(backing_fmt->value.s); + backing_fmt = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT); + if (backing_fmt) { + backing_drv = bdrv_find_format(backing_fmt); if (!backing_drv) { error_setg(errp, "Unknown backing file format '%s'", - backing_fmt->value.s); + backing_fmt); 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 - size = get_option_parameter(param, BLOCK_OPT_SIZE); - if (size && size->value.n == -1) { - if (backing_file && backing_file->value.s) { + size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 0); + if (size == -1) { + if (backing_file) { BlockDriverState *bs; uint64_t size; char buf[32]; @@ -5609,11 +5603,11 @@ void bdrv_img_create(const char *filename, const char *fmt, flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING); bs = NULL; - ret = bdrv_open(&bs, backing_file->value.s, NULL, NULL, back_flags, + ret = bdrv_open(&bs, backing_file, NULL, NULL, back_flags, backing_drv, &local_err); if (ret < 0) { error_setg_errno(errp, -ret, "Could not open '%s': %s", - backing_file->value.s, + backing_file, error_get_pretty(local_err)); error_free(local_err); local_err = NULL; @@ -5623,7 +5617,7 @@ void bdrv_img_create(const char *filename, const char *fmt, size *= 512; snprintf(buf, sizeof(buf), "%" PRId64, size); - set_option_parameter(param, BLOCK_OPT_SIZE, buf); + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, size); bdrv_unref(bs); } else { @@ -5634,16 +5628,18 @@ void bdrv_img_create(const char *filename, const char *fmt, if (!quiet) { printf("Formatting '%s', fmt=%s ", filename, fmt); - print_option_parameters(param); + qemu_opts_print(opts); puts(""); } - ret = bdrv_create(drv, filename, param, &local_err); + + ret = bdrv_create(drv, filename, opts, &local_err); + if (ret == -EFBIG) { /* This is generally a better message than whatever the driver would * deliver (especially because of the cluster_size_hint), since that * is most probably not much different from "image too large". */ const char *cluster_size_hint = ""; - if (get_option_parameter(create_options, BLOCK_OPT_CLUSTER_SIZE)) { + if (qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE, 0)) { cluster_size_hint = " (try using a larger cluster size)"; } error_setg(errp, "The image size is too large for file format '%s'" @@ -5653,9 +5649,8 @@ void bdrv_img_create(const char *filename, const char *fmt, } out: - free_option_parameters(create_options); - free_option_parameters(param); - + qemu_opts_del(opts); + qemu_opts_free(create_opts); if (local_err) { error_propagate(errp, local_err); } @@ -5731,12 +5726,12 @@ void bdrv_add_before_write_notifier(BlockDriverState *bs, notifier_with_return_list_add(&bs->before_write_notifiers, notifier); } -int bdrv_amend_options(BlockDriverState *bs, QEMUOptionParameter *options) +int bdrv_amend_options(BlockDriverState *bs, QemuOpts *opts) { - if (bs->drv->bdrv_amend_options == NULL) { + if (!bs->drv->bdrv_amend_options) { return -ENOTSUP; } - return bs->drv->bdrv_amend_options(bs, options); + return bs->drv->bdrv_amend_options(bs, opts); } /* This function will be called by the bdrv_recurse_is_first_non_filter method diff --git a/block/cow.c b/block/cow.c index 164759f..a05a92c 100644 --- a/block/cow.c +++ b/block/cow.c @@ -324,31 +324,24 @@ static void cow_close(BlockDriverState *bs) { } -static int cow_create(const char *filename, QEMUOptionParameter *options, - Error **errp) +static int cow_create(const char *filename, QemuOpts *opts, Error **errp) { struct cow_header_v2 cow_header; struct stat st; int64_t image_sectors = 0; - const char *image_filename = NULL; + char *image_filename = NULL; Error *local_err = NULL; int ret; BlockDriverState *cow_bs; /* Read out options */ - while (options && options->name) { - if (!strcmp(options->name, BLOCK_OPT_SIZE)) { - image_sectors = options->value.n / 512; - } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) { - image_filename = options->value.s; - } - options++; - } + image_sectors = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / 512; + image_filename = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); - ret = bdrv_create_file(filename, options, &local_err); + ret = bdrv_create_file(filename, opts, &local_err); if (ret < 0) { error_propagate(errp, local_err); - return ret; + goto exit; } cow_bs = NULL; @@ -356,7 +349,7 @@ static int cow_create(const char *filename, QEMUOptionParameter *options, BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err); if (ret < 0) { error_propagate(errp, local_err); - return ret; + goto exit; } memset(&cow_header, 0, sizeof(cow_header)); @@ -389,22 +382,27 @@ static int cow_create(const char *filename, QEMUOptionParameter *options, } exit: + g_free(image_filename); bdrv_unref(cow_bs); return ret; } -static QEMUOptionParameter cow_create_options[] = { - { - .name = BLOCK_OPT_SIZE, - .type = OPT_SIZE, - .help = "Virtual disk size" - }, - { - .name = BLOCK_OPT_BACKING_FILE, - .type = OPT_STRING, - .help = "File name of a base image" - }, - { NULL } +static QemuOptsList cow_create_opts = { + .name = "cow-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(cow_create_opts.head), + .desc = { + { + .name = BLOCK_OPT_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Virtual disk size" + }, + { + .name = BLOCK_OPT_BACKING_FILE, + .type = QEMU_OPT_STRING, + .help = "File name of a base image" + }, + { /* end of list */ } + } }; static BlockDriver bdrv_cow = { @@ -421,7 +419,7 @@ static BlockDriver bdrv_cow = { .bdrv_write = cow_co_write, .bdrv_co_get_block_status = cow_co_get_block_status, - .create_options = cow_create_options, + .create_opts = &cow_create_opts, }; static void bdrv_cow_init(void) diff --git a/block/curl.c b/block/curl.c index 8c84141..79ff2f1 100644 --- a/block/curl.c +++ b/block/curl.c @@ -440,10 +440,8 @@ static void curl_detach_aio_context(BlockDriverState *bs) curl_easy_cleanup(s->states[i].curl); s->states[i].curl = NULL; } - if (s->states[i].orig_buf) { - g_free(s->states[i].orig_buf); - s->states[i].orig_buf = NULL; - } + g_free(s->states[i].orig_buf); + s->states[i].orig_buf = NULL; } if (s->multi) { curl_multi_cleanup(s->multi); @@ -638,8 +636,7 @@ static void curl_readv_bh_cb(void *p) acb->end = (acb->nb_sectors * SECTOR_SIZE); state->buf_off = 0; - if (state->orig_buf) - g_free(state->orig_buf); + g_free(state->orig_buf); state->buf_start = start; state->buf_len = acb->end + s->readahead_size; end = MIN(start + state->buf_len, s->len) - 1; diff --git a/block/gluster.c b/block/gluster.c index 114689e..9274dea 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -478,13 +478,14 @@ static inline int qemu_gluster_zerofill(struct glfs_fd *fd, int64_t offset, #endif static int qemu_gluster_create(const char *filename, - QEMUOptionParameter *options, Error **errp) + QemuOpts *opts, Error **errp) { struct glfs *glfs; struct glfs_fd *fd; int ret = 0; int prealloc = 0; int64_t total_size = 0; + char *tmp = NULL; GlusterConf *gconf = g_malloc0(sizeof(GlusterConf)); glfs = qemu_gluster_init(gconf, filename, errp); @@ -493,24 +494,21 @@ static int qemu_gluster_create(const char *filename, goto out; } - while (options && options->name) { - if (!strcmp(options->name, BLOCK_OPT_SIZE)) { - total_size = options->value.n / BDRV_SECTOR_SIZE; - } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) { - if (!options->value.s || !strcmp(options->value.s, "off")) { - prealloc = 0; - } else if (!strcmp(options->value.s, "full") && - gluster_supports_zerofill()) { - prealloc = 1; - } else { - error_setg(errp, "Invalid preallocation mode: '%s'" - " or GlusterFS doesn't support zerofill API", - options->value.s); - ret = -EINVAL; - goto out; - } - } - options++; + total_size = + qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE; + + tmp = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); + if (!tmp || !strcmp(tmp, "off")) { + prealloc = 0; + } else if (!strcmp(tmp, "full") && + gluster_supports_zerofill()) { + prealloc = 1; + } else { + error_setg(errp, "Invalid preallocation mode: '%s'" + " or GlusterFS doesn't support zerofill API", + tmp); + ret = -EINVAL; + goto out; } fd = glfs_creat(glfs, gconf->image, @@ -532,6 +530,7 @@ static int qemu_gluster_create(const char *filename, } } out: + g_free(tmp); qemu_gluster_gconf_free(gconf); if (glfs) { glfs_fini(glfs); @@ -698,18 +697,22 @@ static int qemu_gluster_has_zero_init(BlockDriverState *bs) return 0; } -static QEMUOptionParameter qemu_gluster_create_options[] = { - { - .name = BLOCK_OPT_SIZE, - .type = OPT_SIZE, - .help = "Virtual disk size" - }, - { - .name = BLOCK_OPT_PREALLOC, - .type = OPT_STRING, - .help = "Preallocation mode (allowed values: off, full)" - }, - { NULL } +static QemuOptsList qemu_gluster_create_opts = { + .name = "qemu-gluster-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(qemu_gluster_create_opts.head), + .desc = { + { + .name = BLOCK_OPT_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Virtual disk size" + }, + { + .name = BLOCK_OPT_PREALLOC, + .type = QEMU_OPT_STRING, + .help = "Preallocation mode (allowed values: off, full)" + }, + { /* end of list */ } + } }; static BlockDriver bdrv_gluster = { @@ -736,7 +739,7 @@ static BlockDriver bdrv_gluster = { #ifdef CONFIG_GLUSTERFS_ZEROFILL .bdrv_co_write_zeroes = qemu_gluster_co_write_zeroes, #endif - .create_options = qemu_gluster_create_options, + .create_opts = &qemu_gluster_create_opts, }; static BlockDriver bdrv_gluster_tcp = { @@ -763,7 +766,7 @@ static BlockDriver bdrv_gluster_tcp = { #ifdef CONFIG_GLUSTERFS_ZEROFILL .bdrv_co_write_zeroes = qemu_gluster_co_write_zeroes, #endif - .create_options = qemu_gluster_create_options, + .create_opts = &qemu_gluster_create_opts, }; static BlockDriver bdrv_gluster_unix = { @@ -790,7 +793,7 @@ static BlockDriver bdrv_gluster_unix = { #ifdef CONFIG_GLUSTERFS_ZEROFILL .bdrv_co_write_zeroes = qemu_gluster_co_write_zeroes, #endif - .create_options = qemu_gluster_create_options, + .create_opts = &qemu_gluster_create_opts, }; static BlockDriver bdrv_gluster_rdma = { @@ -817,7 +820,7 @@ static BlockDriver bdrv_gluster_rdma = { #ifdef CONFIG_GLUSTERFS_ZEROFILL .bdrv_co_write_zeroes = qemu_gluster_co_write_zeroes, #endif - .create_options = qemu_gluster_create_options, + .create_opts = &qemu_gluster_create_opts, }; static void bdrv_gluster_init(void) diff --git a/block/iscsi.c b/block/iscsi.c index 877b877..6f87605 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -1434,9 +1434,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, out: qemu_opts_del(opts); - if (initiator_name != NULL) { - g_free(initiator_name); - } + g_free(initiator_name); if (iscsi_url != NULL) { iscsi_destroy_url(iscsi_url); } @@ -1532,8 +1530,7 @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset) return 0; } -static int iscsi_create(const char *filename, QEMUOptionParameter *options, - Error **errp) +static int iscsi_create(const char *filename, QemuOpts *opts, Error **errp) { int ret = 0; int64_t total_size = 0; @@ -1544,13 +1541,8 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options, bs = bdrv_new("", &error_abort); /* Read out options */ - while (options && options->name) { - if (!strcmp(options->name, "size")) { - total_size = options->value.n / BDRV_SECTOR_SIZE; - } - options++; - } - + total_size = + qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE; bs->opaque = g_malloc0(sizeof(struct IscsiLun)); iscsilun = bs->opaque; @@ -1592,13 +1584,17 @@ static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) return 0; } -static QEMUOptionParameter iscsi_create_options[] = { - { - .name = BLOCK_OPT_SIZE, - .type = OPT_SIZE, - .help = "Virtual disk size" - }, - { NULL } +static QemuOptsList iscsi_create_opts = { + .name = "iscsi-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(iscsi_create_opts.head), + .desc = { + { + .name = BLOCK_OPT_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Virtual disk size" + }, + { /* end of list */ } + } }; static BlockDriver bdrv_iscsi = { @@ -1610,7 +1606,7 @@ static BlockDriver bdrv_iscsi = { .bdrv_file_open = iscsi_open, .bdrv_close = iscsi_close, .bdrv_create = iscsi_create, - .create_options = iscsi_create_options, + .create_opts = &iscsi_create_opts, .bdrv_reopen_prepare = iscsi_reopen_prepare, .bdrv_getlength = iscsi_getlength, diff --git a/block/nfs.c b/block/nfs.c index bd9177f..ec43201 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -95,6 +95,7 @@ static void nfs_co_init_task(NFSClient *client, NFSRPC *task) static void nfs_co_generic_bh_cb(void *opaque) { NFSRPC *task = opaque; + task->complete = 1; qemu_bh_delete(task->bh); qemu_coroutine_enter(task->co, NULL); } @@ -104,7 +105,6 @@ nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data, void *private_data) { NFSRPC *task = private_data; - task->complete = 1; task->ret = ret; if (task->ret > 0 && task->iov) { if (task->ret <= task->iov->size) { @@ -123,6 +123,8 @@ nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data, task->bh = aio_bh_new(task->client->aio_context, nfs_co_generic_bh_cb, task); qemu_bh_schedule(task->bh); + } else { + task->complete = 1; } } @@ -389,8 +391,7 @@ static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags, return 0; } -static int nfs_file_create(const char *url, QEMUOptionParameter *options, - Error **errp) +static int nfs_file_create(const char *url, QemuOpts *opts, Error **errp) { int ret = 0; int64_t total_size = 0; @@ -399,12 +400,7 @@ static int nfs_file_create(const char *url, QEMUOptionParameter *options, client->aio_context = qemu_get_aio_context(); /* Read out options */ - while (options && options->name) { - if (!strcmp(options->name, "size")) { - total_size = options->value.n; - } - options++; - } + total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); ret = nfs_client_open(client, url, O_CREAT, errp); if (ret < 0) { diff --git a/block/qcow.c b/block/qcow.c index 7fd57d7..1f2bac8 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -693,35 +693,29 @@ static void qcow_close(BlockDriverState *bs) error_free(s->migration_blocker); } -static int qcow_create(const char *filename, QEMUOptionParameter *options, - Error **errp) +static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) { int header_size, backing_filename_len, l1_size, shift, i; QCowHeader header; uint8_t *tmp; int64_t total_size = 0; - const char *backing_file = NULL; + char *backing_file = NULL; int flags = 0; Error *local_err = NULL; int ret; BlockDriverState *qcow_bs; /* Read out options */ - while (options && options->name) { - if (!strcmp(options->name, BLOCK_OPT_SIZE)) { - total_size = options->value.n / 512; - } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) { - backing_file = options->value.s; - } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) { - flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0; - } - options++; + total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / 512; + backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); + if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) { + flags |= BLOCK_FLAG_ENCRYPT; } - ret = bdrv_create_file(filename, options, &local_err); + ret = bdrv_create_file(filename, opts, &local_err); if (ret < 0) { error_propagate(errp, local_err); - return ret; + goto cleanup; } qcow_bs = NULL; @@ -729,7 +723,7 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options, BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err); if (ret < 0) { error_propagate(errp, local_err); - return ret; + goto cleanup; } ret = bdrv_truncate(qcow_bs, 0); @@ -800,6 +794,8 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options, ret = 0; exit: bdrv_unref(qcow_bs); +cleanup: + g_free(backing_file); return ret; } @@ -912,24 +908,28 @@ static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) return 0; } - -static QEMUOptionParameter qcow_create_options[] = { - { - .name = BLOCK_OPT_SIZE, - .type = OPT_SIZE, - .help = "Virtual disk size" - }, - { - .name = BLOCK_OPT_BACKING_FILE, - .type = OPT_STRING, - .help = "File name of a base image" - }, - { - .name = BLOCK_OPT_ENCRYPT, - .type = OPT_FLAG, - .help = "Encrypt the image" - }, - { NULL } +static QemuOptsList qcow_create_opts = { + .name = "qcow-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(qcow_create_opts.head), + .desc = { + { + .name = BLOCK_OPT_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Virtual disk size" + }, + { + .name = BLOCK_OPT_BACKING_FILE, + .type = QEMU_OPT_STRING, + .help = "File name of a base image" + }, + { + .name = BLOCK_OPT_ENCRYPT, + .type = QEMU_OPT_BOOL, + .help = "Encrypt the image", + .def_value_str = "off" + }, + { /* end of list */ } + } }; static BlockDriver bdrv_qcow = { @@ -938,8 +938,8 @@ static BlockDriver bdrv_qcow = { .bdrv_probe = qcow_probe, .bdrv_open = qcow_open, .bdrv_close = qcow_close, - .bdrv_reopen_prepare = qcow_reopen_prepare, - .bdrv_create = qcow_create, + .bdrv_reopen_prepare = qcow_reopen_prepare, + .bdrv_create = qcow_create, .bdrv_has_zero_init = bdrv_has_zero_init_1, .bdrv_co_readv = qcow_co_readv, @@ -951,7 +951,7 @@ static BlockDriver bdrv_qcow = { .bdrv_write_compressed = qcow_write_compressed, .bdrv_get_info = qcow_get_info, - .create_options = qcow_create_options, + .create_opts = &qcow_create_opts, }; static void bdrv_qcow_init(void) diff --git a/block/qcow2.c b/block/qcow2.c index a54d2ba..b9d2fa6 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -31,6 +31,7 @@ #include "qapi/qmp/qerror.h" #include "qapi/qmp/qbool.h" #include "trace.h" +#include "qemu/option_int.h" /* Differences with QCOW: @@ -1594,7 +1595,7 @@ static int preallocate(BlockDriverState *bs) static int qcow2_create2(const char *filename, int64_t total_size, const char *backing_file, const char *backing_format, int flags, size_t cluster_size, int prealloc, - QEMUOptionParameter *options, int version, + QemuOpts *opts, int version, Error **errp) { /* Calculate cluster_bits */ @@ -1626,7 +1627,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, Error *local_err = NULL; int ret; - ret = bdrv_create_file(filename, options, &local_err); + ret = bdrv_create_file(filename, opts, &local_err); if (ret < 0) { error_propagate(errp, local_err); return ret; @@ -1762,11 +1763,11 @@ out: return ret; } -static int qcow2_create(const char *filename, QEMUOptionParameter *options, - Error **errp) +static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp) { - const char *backing_file = NULL; - const char *backing_fmt = NULL; + char *backing_file = NULL; + char *backing_fmt = NULL; + char *buf = NULL; uint64_t sectors = 0; int flags = 0; size_t cluster_size = DEFAULT_CLUSTER_SIZE; @@ -1776,64 +1777,66 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options, int ret; /* Read out options */ - while (options && options->name) { - if (!strcmp(options->name, BLOCK_OPT_SIZE)) { - sectors = options->value.n / 512; - } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) { - backing_file = options->value.s; - } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FMT)) { - backing_fmt = options->value.s; - } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) { - flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0; - } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) { - if (options->value.n) { - cluster_size = options->value.n; - } - } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) { - if (!options->value.s || !strcmp(options->value.s, "off")) { - prealloc = 0; - } else if (!strcmp(options->value.s, "metadata")) { - prealloc = 1; - } else { - error_setg(errp, "Invalid preallocation mode: '%s'", - options->value.s); - return -EINVAL; - } - } else if (!strcmp(options->name, BLOCK_OPT_COMPAT_LEVEL)) { - if (!options->value.s) { - /* keep the default */ - } else if (!strcmp(options->value.s, "0.10")) { - version = 2; - } else if (!strcmp(options->value.s, "1.1")) { - version = 3; - } else { - error_setg(errp, "Invalid compatibility level: '%s'", - options->value.s); - return -EINVAL; - } - } else if (!strcmp(options->name, BLOCK_OPT_LAZY_REFCOUNTS)) { - flags |= options->value.n ? BLOCK_FLAG_LAZY_REFCOUNTS : 0; - } - options++; + sectors = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / 512; + backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); + backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT); + if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) { + flags |= BLOCK_FLAG_ENCRYPT; + } + cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, + DEFAULT_CLUSTER_SIZE); + buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); + if (!buf || !strcmp(buf, "off")) { + prealloc = 0; + } else if (!strcmp(buf, "metadata")) { + prealloc = 1; + } else { + error_setg(errp, "Invalid preallocation mode: '%s'", buf); + ret = -EINVAL; + goto finish; + } + g_free(buf); + buf = qemu_opt_get_del(opts, BLOCK_OPT_COMPAT_LEVEL); + if (!buf) { + /* keep the default */ + } else if (!strcmp(buf, "0.10")) { + version = 2; + } else if (!strcmp(buf, "1.1")) { + version = 3; + } else { + error_setg(errp, "Invalid compatibility level: '%s'", buf); + ret = -EINVAL; + goto finish; + } + + if (qemu_opt_get_bool_del(opts, BLOCK_OPT_LAZY_REFCOUNTS, false)) { + flags |= BLOCK_FLAG_LAZY_REFCOUNTS; } if (backing_file && prealloc) { error_setg(errp, "Backing file and preallocation cannot be used at " "the same time"); - return -EINVAL; + ret = -EINVAL; + goto finish; } if (version < 3 && (flags & BLOCK_FLAG_LAZY_REFCOUNTS)) { error_setg(errp, "Lazy refcounts only supported with compatibility " "level 1.1 and above (use compat=1.1 or greater)"); - return -EINVAL; + ret = -EINVAL; + goto finish; } ret = qcow2_create2(filename, sectors, backing_file, backing_fmt, flags, - cluster_size, prealloc, options, version, &local_err); + cluster_size, prealloc, opts, version, &local_err); if (local_err) { error_propagate(errp, local_err); } + +finish: + g_free(backing_file); + g_free(backing_fmt); + g_free(buf); return ret; } @@ -2198,64 +2201,72 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version) return 0; } -static int qcow2_amend_options(BlockDriverState *bs, - QEMUOptionParameter *options) +static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts) { BDRVQcowState *s = bs->opaque; int old_version = s->qcow_version, new_version = old_version; uint64_t new_size = 0; const char *backing_file = NULL, *backing_format = NULL; bool lazy_refcounts = s->use_lazy_refcounts; + const char *compat = NULL; + uint64_t cluster_size = s->cluster_size; + bool encrypt; int ret; - int i; + QemuOptDesc *desc = opts->list->desc; - for (i = 0; options[i].name; i++) - { - if (!options[i].assigned) { + while (desc && desc->name) { + if (!qemu_opt_find(opts, desc->name)) { /* only change explicitly defined options */ + desc++; continue; } - if (!strcmp(options[i].name, "compat")) { - if (!options[i].value.s) { + if (!strcmp(desc->name, "compat")) { + compat = qemu_opt_get(opts, "compat"); + if (!compat) { /* preserve default */ - } else if (!strcmp(options[i].value.s, "0.10")) { + } else if (!strcmp(compat, "0.10")) { new_version = 2; - } else if (!strcmp(options[i].value.s, "1.1")) { + } else if (!strcmp(compat, "1.1")) { new_version = 3; } else { - fprintf(stderr, "Unknown compatibility level %s.\n", - options[i].value.s); + fprintf(stderr, "Unknown compatibility level %s.\n", compat); return -EINVAL; } - } else if (!strcmp(options[i].name, "preallocation")) { + } else if (!strcmp(desc->name, "preallocation")) { fprintf(stderr, "Cannot change preallocation mode.\n"); return -ENOTSUP; - } else if (!strcmp(options[i].name, "size")) { - new_size = options[i].value.n; - } else if (!strcmp(options[i].name, "backing_file")) { - backing_file = options[i].value.s; - } else if (!strcmp(options[i].name, "backing_fmt")) { - backing_format = options[i].value.s; - } else if (!strcmp(options[i].name, "encryption")) { - if ((options[i].value.n != !!s->crypt_method)) { + } else if (!strcmp(desc->name, "size")) { + new_size = qemu_opt_get_size(opts, "size", 0); + } else if (!strcmp(desc->name, "backing_file")) { + backing_file = qemu_opt_get(opts, "backing_file"); + } else if (!strcmp(desc->name, "backing_fmt")) { + backing_format = qemu_opt_get(opts, "backing_fmt"); + } else if (!strcmp(desc->name, "encryption")) { + encrypt = qemu_opt_get_bool(opts, "encryption", s->crypt_method); + if (encrypt != !!s->crypt_method) { fprintf(stderr, "Changing the encryption flag is not " "supported.\n"); return -ENOTSUP; } - } else if (!strcmp(options[i].name, "cluster_size")) { - if (options[i].value.n != s->cluster_size) { + } else if (!strcmp(desc->name, "cluster_size")) { + cluster_size = qemu_opt_get_size(opts, "cluster_size", + cluster_size); + if (cluster_size != s->cluster_size) { fprintf(stderr, "Changing the cluster size is not " "supported.\n"); return -ENOTSUP; } - } else if (!strcmp(options[i].name, "lazy_refcounts")) { - lazy_refcounts = options[i].value.n; + } else if (!strcmp(desc->name, "lazy_refcounts")) { + lazy_refcounts = qemu_opt_get_bool(opts, "lazy_refcounts", + lazy_refcounts); } else { /* if this assertion fails, this probably means a new option was * added without having it covered here */ assert(false); } + + desc++; } if (new_version != old_version) { @@ -2324,49 +2335,55 @@ static int qcow2_amend_options(BlockDriverState *bs, return 0; } -static QEMUOptionParameter qcow2_create_options[] = { - { - .name = BLOCK_OPT_SIZE, - .type = OPT_SIZE, - .help = "Virtual disk size" - }, - { - .name = BLOCK_OPT_COMPAT_LEVEL, - .type = OPT_STRING, - .help = "Compatibility level (0.10 or 1.1)" - }, - { - .name = BLOCK_OPT_BACKING_FILE, - .type = OPT_STRING, - .help = "File name of a base image" - }, - { - .name = BLOCK_OPT_BACKING_FMT, - .type = OPT_STRING, - .help = "Image format of the base image" - }, - { - .name = BLOCK_OPT_ENCRYPT, - .type = OPT_FLAG, - .help = "Encrypt the image" - }, - { - .name = BLOCK_OPT_CLUSTER_SIZE, - .type = OPT_SIZE, - .help = "qcow2 cluster size", - .value = { .n = DEFAULT_CLUSTER_SIZE }, - }, - { - .name = BLOCK_OPT_PREALLOC, - .type = OPT_STRING, - .help = "Preallocation mode (allowed values: off, metadata)" - }, - { - .name = BLOCK_OPT_LAZY_REFCOUNTS, - .type = OPT_FLAG, - .help = "Postpone refcount updates", - }, - { NULL } +static QemuOptsList qcow2_create_opts = { + .name = "qcow2-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(qcow2_create_opts.head), + .desc = { + { + .name = BLOCK_OPT_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Virtual disk size" + }, + { + .name = BLOCK_OPT_COMPAT_LEVEL, + .type = QEMU_OPT_STRING, + .help = "Compatibility level (0.10 or 1.1)" + }, + { + .name = BLOCK_OPT_BACKING_FILE, + .type = QEMU_OPT_STRING, + .help = "File name of a base image" + }, + { + .name = BLOCK_OPT_BACKING_FMT, + .type = QEMU_OPT_STRING, + .help = "Image format of the base image" + }, + { + .name = BLOCK_OPT_ENCRYPT, + .type = QEMU_OPT_BOOL, + .help = "Encrypt the image", + .def_value_str = "off" + }, + { + .name = BLOCK_OPT_CLUSTER_SIZE, + .type = QEMU_OPT_SIZE, + .help = "qcow2 cluster size", + .def_value_str = stringify(DEFAULT_CLUSTER_SIZE) + }, + { + .name = BLOCK_OPT_PREALLOC, + .type = QEMU_OPT_STRING, + .help = "Preallocation mode (allowed values: off, metadata)" + }, + { + .name = BLOCK_OPT_LAZY_REFCOUNTS, + .type = QEMU_OPT_BOOL, + .help = "Postpone refcount updates", + .def_value_str = "off" + }, + { /* end of list */ } + } }; static BlockDriver bdrv_qcow2 = { @@ -2394,8 +2411,8 @@ static BlockDriver bdrv_qcow2 = { .bdrv_snapshot_goto = qcow2_snapshot_goto, .bdrv_snapshot_delete = qcow2_snapshot_delete, .bdrv_snapshot_list = qcow2_snapshot_list, - .bdrv_snapshot_load_tmp = qcow2_snapshot_load_tmp, - .bdrv_get_info = qcow2_get_info, + .bdrv_snapshot_load_tmp = qcow2_snapshot_load_tmp, + .bdrv_get_info = qcow2_get_info, .bdrv_get_specific_info = qcow2_get_specific_info, .bdrv_save_vmstate = qcow2_save_vmstate, @@ -2406,9 +2423,9 @@ static BlockDriver bdrv_qcow2 = { .bdrv_refresh_limits = qcow2_refresh_limits, .bdrv_invalidate_cache = qcow2_invalidate_cache, - .create_options = qcow2_create_options, - .bdrv_check = qcow2_check, - .bdrv_amend_options = qcow2_amend_options, + .create_opts = &qcow2_create_opts, + .bdrv_check = qcow2_check, + .bdrv_amend_options = qcow2_amend_options, }; static void bdrv_qcow2_init(void) diff --git a/block/qed.c b/block/qed.c index 79f5bd3..092e6fb 100644 --- a/block/qed.c +++ b/block/qed.c @@ -641,55 +641,53 @@ out: return ret; } -static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options, - Error **errp) +static int bdrv_qed_create(const char *filename, QemuOpts *opts, Error **errp) { uint64_t image_size = 0; uint32_t cluster_size = QED_DEFAULT_CLUSTER_SIZE; uint32_t table_size = QED_DEFAULT_TABLE_SIZE; - const char *backing_file = NULL; - const char *backing_fmt = NULL; - - while (options && options->name) { - if (!strcmp(options->name, BLOCK_OPT_SIZE)) { - image_size = options->value.n; - } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) { - backing_file = options->value.s; - } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FMT)) { - backing_fmt = options->value.s; - } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) { - if (options->value.n) { - cluster_size = options->value.n; - } - } else if (!strcmp(options->name, BLOCK_OPT_TABLE_SIZE)) { - if (options->value.n) { - table_size = options->value.n; - } - } - options++; - } + char *backing_file = NULL; + char *backing_fmt = NULL; + int ret; + + image_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); + backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); + backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT); + cluster_size = qemu_opt_get_size_del(opts, + BLOCK_OPT_CLUSTER_SIZE, + QED_DEFAULT_CLUSTER_SIZE); + table_size = qemu_opt_get_size_del(opts, BLOCK_OPT_TABLE_SIZE, + QED_DEFAULT_TABLE_SIZE); if (!qed_is_cluster_size_valid(cluster_size)) { error_setg(errp, "QED cluster size must be within range [%u, %u] " "and power of 2", QED_MIN_CLUSTER_SIZE, QED_MAX_CLUSTER_SIZE); - return -EINVAL; + ret = -EINVAL; + goto finish; } if (!qed_is_table_size_valid(table_size)) { error_setg(errp, "QED table size must be within range [%u, %u] " "and power of 2", QED_MIN_TABLE_SIZE, QED_MAX_TABLE_SIZE); - return -EINVAL; + ret = -EINVAL; + goto finish; } if (!qed_is_image_size_valid(image_size, cluster_size, table_size)) { error_setg(errp, "QED image size must be a non-zero multiple of " "cluster size and less than %" PRIu64 " bytes", qed_max_image_size(cluster_size, table_size)); - return -EINVAL; + ret = -EINVAL; + goto finish; } - return qed_create(filename, cluster_size, image_size, table_size, - backing_file, backing_fmt, errp); + ret = qed_create(filename, cluster_size, image_size, table_size, + backing_file, backing_fmt, errp); + +finish: + g_free(backing_file); + g_free(backing_fmt); + return ret; } typedef struct { @@ -1616,36 +1614,44 @@ static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result, return qed_check(s, result, !!fix); } -static QEMUOptionParameter qed_create_options[] = { - { - .name = BLOCK_OPT_SIZE, - .type = OPT_SIZE, - .help = "Virtual disk size (in bytes)" - }, { - .name = BLOCK_OPT_BACKING_FILE, - .type = OPT_STRING, - .help = "File name of a base image" - }, { - .name = BLOCK_OPT_BACKING_FMT, - .type = OPT_STRING, - .help = "Image format of the base image" - }, { - .name = BLOCK_OPT_CLUSTER_SIZE, - .type = OPT_SIZE, - .help = "Cluster size (in bytes)", - .value = { .n = QED_DEFAULT_CLUSTER_SIZE }, - }, { - .name = BLOCK_OPT_TABLE_SIZE, - .type = OPT_SIZE, - .help = "L1/L2 table size (in clusters)" - }, - { /* end of list */ } +static QemuOptsList qed_create_opts = { + .name = "qed-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(qed_create_opts.head), + .desc = { + { + .name = BLOCK_OPT_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Virtual disk size" + }, + { + .name = BLOCK_OPT_BACKING_FILE, + .type = QEMU_OPT_STRING, + .help = "File name of a base image" + }, + { + .name = BLOCK_OPT_BACKING_FMT, + .type = QEMU_OPT_STRING, + .help = "Image format of the base image" + }, + { + .name = BLOCK_OPT_CLUSTER_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Cluster size (in bytes)", + .def_value_str = stringify(QED_DEFAULT_CLUSTER_SIZE) + }, + { + .name = BLOCK_OPT_TABLE_SIZE, + .type = QEMU_OPT_SIZE, + .help = "L1/L2 table size (in clusters)" + }, + { /* end of list */ } + } }; static BlockDriver bdrv_qed = { .format_name = "qed", .instance_size = sizeof(BDRVQEDState), - .create_options = qed_create_options, + .create_opts = &qed_create_opts, .bdrv_probe = bdrv_qed_probe, .bdrv_rebind = bdrv_qed_rebind, diff --git a/block/qed.h b/block/qed.h index 5d65bea..b024751 100644 --- a/block/qed.h +++ b/block/qed.h @@ -43,7 +43,7 @@ * * All fields are little-endian on disk. */ - +#define QED_DEFAULT_CLUSTER_SIZE 65536 enum { QED_MAGIC = 'Q' | 'E' << 8 | 'D' << 16 | '\0' << 24, @@ -69,7 +69,6 @@ enum { */ QED_MIN_CLUSTER_SIZE = 4 * 1024, /* in bytes */ QED_MAX_CLUSTER_SIZE = 64 * 1024 * 1024, - QED_DEFAULT_CLUSTER_SIZE = 64 * 1024, /* Allocated clusters are tracked using a 2-level pagetable. Table size is * a multiple of clusters so large maximum image sizes can be supported diff --git a/block/raw-posix.c b/block/raw-posix.c index c2b30be..dacf4fb 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -1273,8 +1273,7 @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs) return (int64_t)st.st_blocks * 512; } -static int raw_create(const char *filename, QEMUOptionParameter *options, - Error **errp) +static int raw_create(const char *filename, QemuOpts *opts, Error **errp) { int fd; int result = 0; @@ -1283,12 +1282,8 @@ static int raw_create(const char *filename, QEMUOptionParameter *options, strstart(filename, "file:", &filename); /* Read out options */ - while (options && options->name) { - if (!strcmp(options->name, BLOCK_OPT_SIZE)) { - total_size = options->value.n / BDRV_SECTOR_SIZE; - } - options++; - } + total_size = + qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE; fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); @@ -1473,13 +1468,17 @@ static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) return 0; } -static QEMUOptionParameter raw_create_options[] = { - { - .name = BLOCK_OPT_SIZE, - .type = OPT_SIZE, - .help = "Virtual disk size" - }, - { NULL } +static QemuOptsList raw_create_opts = { + .name = "raw-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(raw_create_opts.head), + .desc = { + { + .name = BLOCK_OPT_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Virtual disk size" + }, + { /* end of list */ } + } }; static BlockDriver bdrv_file = { @@ -1514,7 +1513,7 @@ static BlockDriver bdrv_file = { .bdrv_detach_aio_context = raw_detach_aio_context, .bdrv_attach_aio_context = raw_attach_aio_context, - .create_options = raw_create_options, + .create_opts = &raw_create_opts, }; /***********************************************/ @@ -1835,7 +1834,7 @@ static coroutine_fn int hdev_co_write_zeroes(BlockDriverState *bs, return -ENOTSUP; } -static int hdev_create(const char *filename, QEMUOptionParameter *options, +static int hdev_create(const char *filename, QemuOpts *opts, Error **errp) { int fd; @@ -1856,12 +1855,8 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options, (void)has_prefix; /* Read out options */ - while (options && options->name) { - if (!strcmp(options->name, "size")) { - total_size = options->value.n / BDRV_SECTOR_SIZE; - } - options++; - } + total_size = + qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE; fd = qemu_open(filename, O_WRONLY | O_BINARY); if (fd < 0) { @@ -1898,8 +1893,8 @@ static BlockDriver bdrv_host_device = { .bdrv_reopen_prepare = raw_reopen_prepare, .bdrv_reopen_commit = raw_reopen_commit, .bdrv_reopen_abort = raw_reopen_abort, - .bdrv_create = hdev_create, - .create_options = raw_create_options, + .bdrv_create = hdev_create, + .create_opts = &raw_create_opts, .bdrv_co_write_zeroes = hdev_co_write_zeroes, .bdrv_aio_readv = raw_aio_readv, @@ -2045,8 +2040,8 @@ static BlockDriver bdrv_host_floppy = { .bdrv_reopen_prepare = raw_reopen_prepare, .bdrv_reopen_commit = raw_reopen_commit, .bdrv_reopen_abort = raw_reopen_abort, - .bdrv_create = hdev_create, - .create_options = raw_create_options, + .bdrv_create = hdev_create, + .create_opts = &raw_create_opts, .bdrv_aio_readv = raw_aio_readv, .bdrv_aio_writev = raw_aio_writev, @@ -2173,8 +2168,8 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_reopen_prepare = raw_reopen_prepare, .bdrv_reopen_commit = raw_reopen_commit, .bdrv_reopen_abort = raw_reopen_abort, - .bdrv_create = hdev_create, - .create_options = raw_create_options, + .bdrv_create = hdev_create, + .create_opts = &raw_create_opts, .bdrv_aio_readv = raw_aio_readv, .bdrv_aio_writev = raw_aio_writev, @@ -2308,7 +2303,7 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_reopen_commit = raw_reopen_commit, .bdrv_reopen_abort = raw_reopen_abort, .bdrv_create = hdev_create, - .create_options = raw_create_options, + .create_opts = &raw_create_opts, .bdrv_aio_readv = raw_aio_readv, .bdrv_aio_writev = raw_aio_writev, diff --git a/block/raw-win32.c b/block/raw-win32.c index 324e818..902eab6 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -503,8 +503,7 @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs) return st.st_size; } -static int raw_create(const char *filename, QEMUOptionParameter *options, - Error **errp) +static int raw_create(const char *filename, QemuOpts *opts, Error **errp) { int fd; int64_t total_size = 0; @@ -512,12 +511,8 @@ static int raw_create(const char *filename, QEMUOptionParameter *options, strstart(filename, "file:", &filename); /* Read out options */ - while (options && options->name) { - if (!strcmp(options->name, BLOCK_OPT_SIZE)) { - total_size = options->value.n / 512; - } - options++; - } + total_size = + qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / 512; fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); @@ -531,13 +526,18 @@ static int raw_create(const char *filename, QEMUOptionParameter *options, return 0; } -static QEMUOptionParameter raw_create_options[] = { - { - .name = BLOCK_OPT_SIZE, - .type = OPT_SIZE, - .help = "Virtual disk size" - }, - { NULL } + +static QemuOptsList raw_create_opts = { + .name = "raw-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(raw_create_opts.head), + .desc = { + { + .name = BLOCK_OPT_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Virtual disk size" + }, + { /* end of list */ } + } }; static BlockDriver bdrv_file = { @@ -546,9 +546,9 @@ static BlockDriver bdrv_file = { .instance_size = sizeof(BDRVRawState), .bdrv_needs_filename = true, .bdrv_parse_filename = raw_parse_filename, - .bdrv_file_open = raw_open, - .bdrv_close = raw_close, - .bdrv_create = raw_create, + .bdrv_file_open = raw_open, + .bdrv_close = raw_close, + .bdrv_create = raw_create, .bdrv_has_zero_init = bdrv_has_zero_init_1, .bdrv_aio_readv = raw_aio_readv, @@ -560,7 +560,7 @@ static BlockDriver bdrv_file = { .bdrv_get_allocated_file_size = raw_get_allocated_file_size, - .create_options = raw_create_options, + .create_opts = &raw_create_opts, }; /***********************************************/ diff --git a/block/raw_bsd.c b/block/raw_bsd.c index 01ea692..492f58d 100644 --- a/block/raw_bsd.c +++ b/block/raw_bsd.c @@ -29,13 +29,17 @@ #include "block/block_int.h" #include "qemu/option.h" -static QEMUOptionParameter raw_create_options[] = { - { - .name = BLOCK_OPT_SIZE, - .type = OPT_SIZE, - .help = "Virtual disk size" - }, - { 0 } +static QemuOptsList raw_create_opts = { + .name = "raw-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(raw_create_opts.head), + .desc = { + { + .name = BLOCK_OPT_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Virtual disk size" + }, + { /* end of list */ } + } }; static int raw_reopen_prepare(BDRVReopenState *reopen_state, @@ -139,13 +143,12 @@ static int raw_has_zero_init(BlockDriverState *bs) return bdrv_has_zero_init(bs->file); } -static int raw_create(const char *filename, QEMUOptionParameter *options, - Error **errp) +static int raw_create(const char *filename, QemuOpts *opts, Error **errp) { Error *local_err = NULL; int ret; - ret = bdrv_create_file(filename, options, &local_err); + ret = bdrv_create_file(filename, opts, &local_err); if (local_err) { error_propagate(errp, local_err); } @@ -194,7 +197,7 @@ static BlockDriver bdrv_raw = { .bdrv_lock_medium = &raw_lock_medium, .bdrv_ioctl = &raw_ioctl, .bdrv_aio_ioctl = &raw_aio_ioctl, - .create_options = &raw_create_options[0], + .create_opts = &raw_create_opts, .bdrv_has_zero_init = &raw_has_zero_init }; diff --git a/block/rbd.c b/block/rbd.c index 93639f7..2b797d3 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -289,8 +289,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf, Error **errp) return ret; } -static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options, - Error **errp) +static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp) { Error *local_err = NULL; int64_t bytes = 0; @@ -315,24 +314,18 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options, } /* Read out options */ - while (options && options->name) { - if (!strcmp(options->name, BLOCK_OPT_SIZE)) { - bytes = options->value.n; - } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) { - if (options->value.n) { - objsize = options->value.n; - if ((objsize - 1) & objsize) { /* not a power of 2? */ - error_setg(errp, "obj size needs to be power of 2"); - return -EINVAL; - } - if (objsize < 4096) { - error_setg(errp, "obj size too small"); - return -EINVAL; - } - obj_order = ffs(objsize) - 1; - } + bytes = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); + objsize = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, 0); + if (objsize) { + if ((objsize - 1) & objsize) { /* not a power of 2? */ + error_setg(errp, "obj size needs to be power of 2"); + return -EINVAL; + } + if (objsize < 4096) { + error_setg(errp, "obj size too small"); + return -EINVAL; } - options++; + obj_order = ffs(objsize) - 1; } clientname = qemu_rbd_parse_clientname(conf, clientname_buf); @@ -911,18 +904,22 @@ static BlockDriverAIOCB* qemu_rbd_aio_discard(BlockDriverState *bs, } #endif -static QEMUOptionParameter qemu_rbd_create_options[] = { - { - .name = BLOCK_OPT_SIZE, - .type = OPT_SIZE, - .help = "Virtual disk size" - }, - { - .name = BLOCK_OPT_CLUSTER_SIZE, - .type = OPT_SIZE, - .help = "RBD object size" - }, - {NULL} +static QemuOptsList qemu_rbd_create_opts = { + .name = "rbd-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(qemu_rbd_create_opts.head), + .desc = { + { + .name = BLOCK_OPT_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Virtual disk size" + }, + { + .name = BLOCK_OPT_CLUSTER_SIZE, + .type = QEMU_OPT_SIZE, + .help = "RBD object size" + }, + { /* end of list */ } + } }; static BlockDriver bdrv_rbd = { @@ -934,7 +931,7 @@ static BlockDriver bdrv_rbd = { .bdrv_create = qemu_rbd_create, .bdrv_has_zero_init = bdrv_has_zero_init_1, .bdrv_get_info = qemu_rbd_getinfo, - .create_options = qemu_rbd_create_options, + .create_opts = &qemu_rbd_create_opts, .bdrv_getlength = qemu_rbd_getlength, .bdrv_truncate = qemu_rbd_truncate, .protocol_name = "rbd", diff --git a/block/sheepdog.c b/block/sheepdog.c index 1fa1939..2dcc595 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -1670,12 +1670,13 @@ static int parse_redundancy(BDRVSheepdogState *s, const char *opt) return 0; } -static int sd_create(const char *filename, QEMUOptionParameter *options, +static int sd_create(const char *filename, QemuOpts *opts, Error **errp) { int ret = 0; uint32_t vid = 0; char *backing_file = NULL; + char *buf = NULL; BDRVSheepdogState *s; char tag[SD_MAX_VDI_TAG_LEN]; uint32_t snapid; @@ -1694,33 +1695,27 @@ static int sd_create(const char *filename, QEMUOptionParameter *options, goto out; } - while (options && options->name) { - if (!strcmp(options->name, BLOCK_OPT_SIZE)) { - s->inode.vdi_size = options->value.n; - } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) { - backing_file = options->value.s; - } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) { - if (!options->value.s || !strcmp(options->value.s, "off")) { - prealloc = false; - } else if (!strcmp(options->value.s, "full")) { - prealloc = true; - } else { - error_setg(errp, "Invalid preallocation mode: '%s'", - options->value.s); - ret = -EINVAL; - goto out; - } - } else if (!strcmp(options->name, BLOCK_OPT_REDUNDANCY)) { - if (options->value.s) { - ret = parse_redundancy(s, options->value.s); - if (ret < 0) { - error_setg(errp, "Invalid redundancy mode: '%s'", - options->value.s); - goto out; - } - } + s->inode.vdi_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); + backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); + buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); + if (!buf || !strcmp(buf, "off")) { + prealloc = false; + } else if (!strcmp(buf, "full")) { + prealloc = true; + } else { + error_setg(errp, "Invalid preallocation mode: '%s'", buf); + ret = -EINVAL; + goto out; + } + + g_free(buf); + buf = qemu_opt_get_del(opts, BLOCK_OPT_REDUNDANCY); + if (buf) { + ret = parse_redundancy(s, buf); + if (ret < 0) { + error_setg(errp, "Invalid redundancy mode: '%s'", buf); + goto out; } - options++; } if (s->inode.vdi_size > SD_MAX_VDI_SIZE) { @@ -1770,6 +1765,8 @@ static int sd_create(const char *filename, QEMUOptionParameter *options, ret = sd_prealloc(filename, errp); } out: + g_free(backing_file); + g_free(buf); g_free(s); return ret; } @@ -2571,28 +2568,32 @@ static int64_t sd_get_allocated_file_size(BlockDriverState *bs) return size; } -static QEMUOptionParameter sd_create_options[] = { - { - .name = BLOCK_OPT_SIZE, - .type = OPT_SIZE, - .help = "Virtual disk size" - }, - { - .name = BLOCK_OPT_BACKING_FILE, - .type = OPT_STRING, - .help = "File name of a base image" - }, - { - .name = BLOCK_OPT_PREALLOC, - .type = OPT_STRING, - .help = "Preallocation mode (allowed values: off, full)" - }, - { - .name = BLOCK_OPT_REDUNDANCY, - .type = OPT_STRING, - .help = "Redundancy of the image" - }, - { NULL } +static QemuOptsList sd_create_opts = { + .name = "sheepdog-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(sd_create_opts.head), + .desc = { + { + .name = BLOCK_OPT_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Virtual disk size" + }, + { + .name = BLOCK_OPT_BACKING_FILE, + .type = QEMU_OPT_STRING, + .help = "File name of a base image" + }, + { + .name = BLOCK_OPT_PREALLOC, + .type = QEMU_OPT_STRING, + .help = "Preallocation mode (allowed values: off, full)" + }, + { + .name = BLOCK_OPT_REDUNDANCY, + .type = QEMU_OPT_STRING, + .help = "Redundancy of the image" + }, + { /* end of list */ } + } }; static BlockDriver bdrv_sheepdog = { @@ -2625,7 +2626,7 @@ static BlockDriver bdrv_sheepdog = { .bdrv_detach_aio_context = sd_detach_aio_context, .bdrv_attach_aio_context = sd_attach_aio_context, - .create_options = sd_create_options, + .create_opts = &sd_create_opts, }; static BlockDriver bdrv_sheepdog_tcp = { @@ -2658,7 +2659,7 @@ static BlockDriver bdrv_sheepdog_tcp = { .bdrv_detach_aio_context = sd_detach_aio_context, .bdrv_attach_aio_context = sd_attach_aio_context, - .create_options = sd_create_options, + .create_opts = &sd_create_opts, }; static BlockDriver bdrv_sheepdog_unix = { @@ -2691,7 +2692,7 @@ static BlockDriver bdrv_sheepdog_unix = { .bdrv_detach_aio_context = sd_detach_aio_context, .bdrv_attach_aio_context = sd_attach_aio_context, - .create_options = sd_create_options, + .create_opts = &sd_create_opts, }; static void bdrv_sheepdog_init(void) diff --git a/block/ssh.c b/block/ssh.c index 9779eac..cd2fd75 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -675,17 +675,20 @@ static int ssh_file_open(BlockDriverState *bs, QDict *options, int bdrv_flags, return ret; } -static QEMUOptionParameter ssh_create_options[] = { - { - .name = BLOCK_OPT_SIZE, - .type = OPT_SIZE, - .help = "Virtual disk size" - }, - { NULL } +static QemuOptsList ssh_create_opts = { + .name = "ssh-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(ssh_create_opts.head), + .desc = { + { + .name = BLOCK_OPT_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Virtual disk size" + }, + { /* end of list */ } + } }; -static int ssh_create(const char *filename, QEMUOptionParameter *options, - Error **errp) +static int ssh_create(const char *filename, QemuOpts *opts, Error **errp) { int r, ret; int64_t total_size = 0; @@ -697,12 +700,7 @@ static int ssh_create(const char *filename, QEMUOptionParameter *options, ssh_state_init(&s); /* Get desired file size. */ - while (options && options->name) { - if (!strcmp(options->name, BLOCK_OPT_SIZE)) { - total_size = options->value.n; - } - options++; - } + total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); DPRINTF("total_size=%" PRIi64, total_size); uri_options = qdict_new(); @@ -1084,7 +1082,7 @@ static BlockDriver bdrv_ssh = { .bdrv_co_writev = ssh_co_writev, .bdrv_getlength = ssh_getlength, .bdrv_co_flush_to_disk = ssh_co_flush, - .create_options = ssh_create_options, + .create_opts = &ssh_create_opts, }; static void bdrv_ssh_init(void) diff --git a/block/vdi.c b/block/vdi.c index 1b2be1a..01fe22e 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -672,8 +672,7 @@ static int vdi_co_write(BlockDriverState *bs, return ret; } -static int vdi_create(const char *filename, QEMUOptionParameter *options, - Error **errp) +static int vdi_create(const char *filename, QemuOpts *opts, Error **errp) { int fd; int result = 0; @@ -688,25 +687,18 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options, logout("\n"); /* Read out options. */ - while (options && options->name) { - if (!strcmp(options->name, BLOCK_OPT_SIZE)) { - bytes = options->value.n; + bytes = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); #if defined(CONFIG_VDI_BLOCK_SIZE) - } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) { - if (options->value.n) { - /* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */ - block_size = options->value.n; - } + /* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */ + block_size = qemu_opt_get_size_del(opts, + BLOCK_OPT_CLUSTER_SIZE, + DEFAULT_CLUSTER_SIZE); #endif #if defined(CONFIG_VDI_STATIC_IMAGE) - } else if (!strcmp(options->name, BLOCK_OPT_STATIC)) { - if (options->value.n) { - image_type = VDI_TYPE_STATIC; - } -#endif - } - options++; + if (qemu_opt_get_bool_del(opts, BLOCK_OPT_STATIC, false)) { + image_type = VDI_TYPE_STATIC; } +#endif if (bytes > VDI_DISK_SIZE_MAX) { result = -ENOTSUP; @@ -801,29 +793,34 @@ static void vdi_close(BlockDriverState *bs) error_free(s->migration_blocker); } -static QEMUOptionParameter vdi_create_options[] = { - { - .name = BLOCK_OPT_SIZE, - .type = OPT_SIZE, - .help = "Virtual disk size" - }, +static QemuOptsList vdi_create_opts = { + .name = "vdi-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(vdi_create_opts.head), + .desc = { + { + .name = BLOCK_OPT_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Virtual disk size" + }, #if defined(CONFIG_VDI_BLOCK_SIZE) - { - .name = BLOCK_OPT_CLUSTER_SIZE, - .type = OPT_SIZE, - .help = "VDI cluster (block) size", - .value = { .n = DEFAULT_CLUSTER_SIZE }, - }, + { + .name = BLOCK_OPT_CLUSTER_SIZE, + .type = QEMU_OPT_SIZE, + .help = "VDI cluster (block) size", + .def_value_str = stringify(DEFAULT_CLUSTER_SIZE) + }, #endif #if defined(CONFIG_VDI_STATIC_IMAGE) - { - .name = BLOCK_OPT_STATIC, - .type = OPT_FLAG, - .help = "VDI static (pre-allocated) image" - }, + { + .name = BLOCK_OPT_STATIC, + .type = QEMU_OPT_BOOL, + .help = "VDI static (pre-allocated) image", + .def_value_str = "off" + }, #endif - /* TODO: An additional option to set UUID values might be useful. */ - { NULL } + /* TODO: An additional option to set UUID values might be useful. */ + { /* end of list */ } + } }; static BlockDriver bdrv_vdi = { @@ -845,7 +842,7 @@ static BlockDriver bdrv_vdi = { .bdrv_get_info = vdi_get_info, - .create_options = vdi_create_options, + .create_opts = &vdi_create_opts, .bdrv_check = vdi_check, }; diff --git a/block/vhdx.c b/block/vhdx.c index 353c74d..fedcf9f 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1723,8 +1723,7 @@ exit: * .---- ~ ----------- ~ ------------ ~ ---------------- ~ -----------. * 1MB */ -static int vhdx_create(const char *filename, QEMUOptionParameter *options, - Error **errp) +static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp) { int ret = 0; uint64_t image_size = (uint64_t) 2 * GiB; @@ -1737,24 +1736,15 @@ static int vhdx_create(const char *filename, QEMUOptionParameter *options, gunichar2 *creator = NULL; glong creator_items; BlockDriverState *bs; - const char *type = NULL; + char *type = NULL; VHDXImageType image_type; Error *local_err = NULL; - while (options && options->name) { - if (!strcmp(options->name, BLOCK_OPT_SIZE)) { - image_size = options->value.n; - } else if (!strcmp(options->name, VHDX_BLOCK_OPT_LOG_SIZE)) { - log_size = options->value.n; - } else if (!strcmp(options->name, VHDX_BLOCK_OPT_BLOCK_SIZE)) { - block_size = options->value.n; - } else if (!strcmp(options->name, BLOCK_OPT_SUBFMT)) { - type = options->value.s; - } else if (!strcmp(options->name, VHDX_BLOCK_OPT_ZERO)) { - use_zero_blocks = options->value.n != 0; - } - options++; - } + image_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); + log_size = qemu_opt_get_size_del(opts, VHDX_BLOCK_OPT_LOG_SIZE, 0); + block_size = qemu_opt_get_size_del(opts, VHDX_BLOCK_OPT_BLOCK_SIZE, 0); + type = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT); + use_zero_blocks = qemu_opt_get_bool_del(opts, VHDX_BLOCK_OPT_ZERO, false); if (image_size > VHDX_MAX_IMAGE_SIZE) { error_setg_errno(errp, EINVAL, "Image size too large; max of 64TB"); @@ -1763,7 +1753,7 @@ static int vhdx_create(const char *filename, QEMUOptionParameter *options, } if (type == NULL) { - type = "dynamic"; + type = g_strdup("dynamic"); } if (!strcmp(type, "dynamic")) { @@ -1803,7 +1793,7 @@ static int vhdx_create(const char *filename, QEMUOptionParameter *options, block_size = block_size > VHDX_BLOCK_SIZE_MAX ? VHDX_BLOCK_SIZE_MAX : block_size; - ret = bdrv_create_file(filename, options, &local_err); + ret = bdrv_create_file(filename, opts, &local_err); if (ret < 0) { error_propagate(errp, local_err); goto exit; @@ -1863,6 +1853,7 @@ static int vhdx_create(const char *filename, QEMUOptionParameter *options, delete_and_exit: bdrv_unref(bs); exit: + g_free(type); g_free(creator); return ret; } @@ -1885,37 +1876,41 @@ static int vhdx_check(BlockDriverState *bs, BdrvCheckResult *result, return 0; } -static QEMUOptionParameter vhdx_create_options[] = { - { - .name = BLOCK_OPT_SIZE, - .type = OPT_SIZE, - .help = "Virtual disk size; max of 64TB." - }, - { - .name = VHDX_BLOCK_OPT_LOG_SIZE, - .type = OPT_SIZE, - .value.n = 1 * MiB, - .help = "Log size; min 1MB." - }, - { - .name = VHDX_BLOCK_OPT_BLOCK_SIZE, - .type = OPT_SIZE, - .value.n = 0, - .help = "Block Size; min 1MB, max 256MB. " \ - "0 means auto-calculate based on image size." - }, - { - .name = BLOCK_OPT_SUBFMT, - .type = OPT_STRING, - .help = "VHDX format type, can be either 'dynamic' or 'fixed'. "\ - "Default is 'dynamic'." - }, - { - .name = VHDX_BLOCK_OPT_ZERO, - .type = OPT_FLAG, - .help = "Force use of payload blocks of type 'ZERO'. Non-standard." - }, - { NULL } +static QemuOptsList vhdx_create_opts = { + .name = "vhdx-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(vhdx_create_opts.head), + .desc = { + { + .name = BLOCK_OPT_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Virtual disk size; max of 64TB." + }, + { + .name = VHDX_BLOCK_OPT_LOG_SIZE, + .type = QEMU_OPT_SIZE, + .def_value_str = stringify(DEFAULT_LOG_SIZE), + .help = "Log size; min 1MB." + }, + { + .name = VHDX_BLOCK_OPT_BLOCK_SIZE, + .type = QEMU_OPT_SIZE, + .def_value_str = stringify(0), + .help = "Block Size; min 1MB, max 256MB. " \ + "0 means auto-calculate based on image size." + }, + { + .name = BLOCK_OPT_SUBFMT, + .type = QEMU_OPT_STRING, + .help = "VHDX format type, can be either 'dynamic' or 'fixed'. "\ + "Default is 'dynamic'." + }, + { + .name = VHDX_BLOCK_OPT_ZERO, + .type = QEMU_OPT_BOOL, + .help = "Force use of payload blocks of type 'ZERO'. Non-standard." + }, + { NULL } + } }; static BlockDriver bdrv_vhdx = { @@ -1931,7 +1926,7 @@ static BlockDriver bdrv_vhdx = { .bdrv_get_info = vhdx_get_info, .bdrv_check = vhdx_check, - .create_options = vhdx_create_options, + .create_opts = &vhdx_create_opts, }; static void bdrv_vhdx_init(void) diff --git a/block/vhdx.h b/block/vhdx.h index 8103d4c..5370010 100644 --- a/block/vhdx.h +++ b/block/vhdx.h @@ -23,6 +23,7 @@ #define GiB (MiB * 1024) #define TiB ((uint64_t) GiB * 1024) +#define DEFAULT_LOG_SIZE 1048576 /* 1MiB */ /* Structures and fields present in the VHDX file */ /* The header section has the following blocks, diff --git a/block/vmdk.c b/block/vmdk.c index b8a4762..83dd6fe 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1695,17 +1695,16 @@ static int filename_decompose(const char *filename, char *path, char *prefix, return VMDK_OK; } -static int vmdk_create(const char *filename, QEMUOptionParameter *options, - Error **errp) +static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp) { int idx = 0; BlockDriverState *new_bs = NULL; Error *local_err = NULL; char *desc = NULL; int64_t total_size = 0, filesize; - const char *adapter_type = NULL; - const char *backing_file = NULL; - const char *fmt = NULL; + char *adapter_type = NULL; + char *backing_file = NULL; + char *fmt = NULL; int flags = 0; int ret = 0; bool flat, split, compress; @@ -1745,24 +1744,19 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, goto exit; } /* Read out options */ - while (options && options->name) { - if (!strcmp(options->name, BLOCK_OPT_SIZE)) { - total_size = options->value.n; - } else if (!strcmp(options->name, BLOCK_OPT_ADAPTER_TYPE)) { - adapter_type = options->value.s; - } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) { - backing_file = options->value.s; - } else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) { - flags |= options->value.n ? BLOCK_FLAG_COMPAT6 : 0; - } else if (!strcmp(options->name, BLOCK_OPT_SUBFMT)) { - fmt = options->value.s; - } else if (!strcmp(options->name, BLOCK_OPT_ZEROED_GRAIN)) { - zeroed_grain |= options->value.n; - } - options++; + total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); + adapter_type = qemu_opt_get_del(opts, BLOCK_OPT_ADAPTER_TYPE); + backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); + if (qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false)) { + flags |= BLOCK_FLAG_COMPAT6; + } + fmt = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT); + if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ZEROED_GRAIN, false)) { + zeroed_grain = true; } + if (!adapter_type) { - adapter_type = "ide"; + adapter_type = g_strdup("ide"); } else if (strcmp(adapter_type, "ide") && strcmp(adapter_type, "buslogic") && strcmp(adapter_type, "lsilogic") && @@ -1778,7 +1772,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, } if (!fmt) { /* Default format to monolithicSparse */ - fmt = "monolithicSparse"; + fmt = g_strdup("monolithicSparse"); } else if (strcmp(fmt, "monolithicFlat") && strcmp(fmt, "monolithicSparse") && strcmp(fmt, "twoGbMaxExtentSparse") && @@ -1879,7 +1873,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options, if (!split && !flat) { desc_offset = 0x200; } else { - ret = bdrv_create_file(filename, options, &local_err); + ret = bdrv_create_file(filename, opts, &local_err); if (ret < 0) { error_propagate(errp, local_err); goto exit; @@ -1909,6 +1903,9 @@ exit: if (new_bs) { bdrv_unref(new_bs); } + g_free(adapter_type); + g_free(backing_file); + g_free(fmt); g_free(desc); g_string_free(ext_desc_lines, true); return ret; @@ -2117,41 +2114,47 @@ static void vmdk_attach_aio_context(BlockDriverState *bs, } } -static QEMUOptionParameter vmdk_create_options[] = { - { - .name = BLOCK_OPT_SIZE, - .type = OPT_SIZE, - .help = "Virtual disk size" - }, - { - .name = BLOCK_OPT_ADAPTER_TYPE, - .type = OPT_STRING, - .help = "Virtual adapter type, can be one of " - "ide (default), lsilogic, buslogic or legacyESX" - }, - { - .name = BLOCK_OPT_BACKING_FILE, - .type = OPT_STRING, - .help = "File name of a base image" - }, - { - .name = BLOCK_OPT_COMPAT6, - .type = OPT_FLAG, - .help = "VMDK version 6 image" - }, - { - .name = BLOCK_OPT_SUBFMT, - .type = OPT_STRING, - .help = - "VMDK flat extent format, can be one of " - "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat | streamOptimized} " - }, - { - .name = BLOCK_OPT_ZEROED_GRAIN, - .type = OPT_FLAG, - .help = "Enable efficient zero writes using the zeroed-grain GTE feature" - }, - { NULL } +static QemuOptsList vmdk_create_opts = { + .name = "vmdk-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(vmdk_create_opts.head), + .desc = { + { + .name = BLOCK_OPT_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Virtual disk size" + }, + { + .name = BLOCK_OPT_ADAPTER_TYPE, + .type = QEMU_OPT_STRING, + .help = "Virtual adapter type, can be one of " + "ide (default), lsilogic, buslogic or legacyESX" + }, + { + .name = BLOCK_OPT_BACKING_FILE, + .type = QEMU_OPT_STRING, + .help = "File name of a base image" + }, + { + .name = BLOCK_OPT_COMPAT6, + .type = QEMU_OPT_BOOL, + .help = "VMDK version 6 image", + .def_value_str = "off" + }, + { + .name = BLOCK_OPT_SUBFMT, + .type = QEMU_OPT_STRING, + .help = + "VMDK flat extent format, can be one of " + "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat | streamOptimized} " + }, + { + .name = BLOCK_OPT_ZEROED_GRAIN, + .type = QEMU_OPT_BOOL, + .help = "Enable efficient zero writes " + "using the zeroed-grain GTE feature" + }, + { /* end of list */ } + } }; static BlockDriver bdrv_vmdk = { @@ -2177,7 +2180,7 @@ static BlockDriver bdrv_vmdk = { .bdrv_detach_aio_context = vmdk_detach_aio_context, .bdrv_attach_aio_context = vmdk_attach_aio_context, - .create_options = vmdk_create_options, + .create_opts = &vmdk_create_opts, }; static void bdrv_vmdk_init(void) diff --git a/block/vpc.c b/block/vpc.c index 2e25f57..798d854 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -738,12 +738,11 @@ static int create_fixed_disk(int fd, uint8_t *buf, int64_t total_size) return ret; } -static int vpc_create(const char *filename, QEMUOptionParameter *options, - Error **errp) +static int vpc_create(const char *filename, QemuOpts *opts, Error **errp) { uint8_t buf[1024]; VHDFooter *footer = (VHDFooter *) buf; - QEMUOptionParameter *disk_type_param; + char *disk_type_param; int fd, i; uint16_t cyls = 0; uint8_t heads = 0; @@ -754,16 +753,16 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options, int ret = -EIO; /* Read out options */ - total_size = get_option_parameter(options, BLOCK_OPT_SIZE)->value.n; - - disk_type_param = get_option_parameter(options, BLOCK_OPT_SUBFMT); - if (disk_type_param && disk_type_param->value.s) { - if (!strcmp(disk_type_param->value.s, "dynamic")) { + total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); + disk_type_param = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT); + if (disk_type_param) { + if (!strcmp(disk_type_param, "dynamic")) { disk_type = VHD_DYNAMIC; - } else if (!strcmp(disk_type_param->value.s, "fixed")) { + } else if (!strcmp(disk_type_param, "fixed")) { disk_type = VHD_FIXED; } else { - return -EINVAL; + ret = -EINVAL; + goto out; } } else { disk_type = VHD_DYNAMIC; @@ -772,7 +771,8 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options, /* Create the file */ fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); if (fd < 0) { - return -EIO; + ret = -EIO; + goto out; } /* @@ -837,8 +837,10 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options, ret = create_fixed_disk(fd, buf, total_size); } - fail: +fail: qemu_close(fd); +out: + g_free(disk_type_param); return ret; } @@ -866,20 +868,24 @@ static void vpc_close(BlockDriverState *bs) error_free(s->migration_blocker); } -static QEMUOptionParameter vpc_create_options[] = { - { - .name = BLOCK_OPT_SIZE, - .type = OPT_SIZE, - .help = "Virtual disk size" - }, - { - .name = BLOCK_OPT_SUBFMT, - .type = OPT_STRING, - .help = - "Type of virtual hard disk format. Supported formats are " - "{dynamic (default) | fixed} " - }, - { NULL } +static QemuOptsList vpc_create_opts = { + .name = "vpc-create-opts", + .head = QTAILQ_HEAD_INITIALIZER(vpc_create_opts.head), + .desc = { + { + .name = BLOCK_OPT_SIZE, + .type = QEMU_OPT_SIZE, + .help = "Virtual disk size" + }, + { + .name = BLOCK_OPT_SUBFMT, + .type = QEMU_OPT_STRING, + .help = + "Type of virtual hard disk format. Supported formats are " + "{dynamic (default) | fixed} " + }, + { /* end of list */ } + } }; static BlockDriver bdrv_vpc = { @@ -897,7 +903,7 @@ static BlockDriver bdrv_vpc = { .bdrv_get_info = vpc_get_info, - .create_options = vpc_create_options, + .create_opts = &vpc_create_opts, .bdrv_has_zero_init = vpc_has_zero_init, }; diff --git a/block/vvfat.c b/block/vvfat.c index 3cda19f..70176b1 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -2910,8 +2910,8 @@ static BlockDriver vvfat_write_target = { static int enable_write_target(BDRVVVFATState *s, Error **errp) { - BlockDriver *bdrv_qcow; - QEMUOptionParameter *options; + BlockDriver *bdrv_qcow = NULL; + QemuOpts *opts = NULL; int ret; int size = sector2cluster(s, s->sector_count); s->used_clusters = calloc(size, 1); @@ -2926,12 +2926,12 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp) } bdrv_qcow = bdrv_find_format("qcow"); - options = parse_option_parameters("", bdrv_qcow->create_options, NULL); - set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512); - set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:"); + opts = qemu_opts_create(bdrv_qcow->create_opts, NULL, 0, &error_abort); + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512); + qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:"); - ret = bdrv_create(bdrv_qcow, s->qcow_filename, options, errp); - free_option_parameters(options); + ret = bdrv_create(bdrv_qcow, s->qcow_filename, opts, errp); + qemu_opts_del(opts); if (ret < 0) { goto err; } @@ -106,7 +106,7 @@ void blockdev_auto_del(BlockDriverState *bs) DriveInfo *dinfo = drive_get_by_blockdev(bs); if (dinfo && dinfo->auto_del) { - drive_put_ref(dinfo); + drive_del(dinfo); } } @@ -213,7 +213,7 @@ static void bdrv_format_print(void *opaque, const char *name) error_printf(" %s", name); } -static void drive_uninit(DriveInfo *dinfo) +void drive_del(DriveInfo *dinfo) { if (dinfo->opts) { qemu_opts_del(dinfo->opts); @@ -226,19 +226,6 @@ static void drive_uninit(DriveInfo *dinfo) g_free(dinfo); } -void drive_put_ref(DriveInfo *dinfo) -{ - assert(dinfo->refcount); - if (--dinfo->refcount == 0) { - drive_uninit(dinfo); - } -} - -void drive_get_ref(DriveInfo *dinfo) -{ - dinfo->refcount++; -} - typedef struct { QEMUBH *bh; BlockDriverState *bs; @@ -329,7 +316,6 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts, Error **errp) { const char *buf; - const char *serial; int ro = 0; int bdrv_flags = 0; int on_read_error, on_write_error; @@ -371,8 +357,6 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts, ro = qemu_opt_get_bool(opts, "read-only", 0); copy_on_read = qemu_opt_get_bool(opts, "copy-on-read", false); - serial = qemu_opt_get(opts, "serial"); - if ((buf = qemu_opt_get(opts, "discard")) != NULL) { if (bdrv_parse_discard_flags(buf, &bdrv_flags) != 0) { error_setg(errp, "invalid discard option"); @@ -500,10 +484,6 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts, dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0; dinfo->bdrv->read_only = ro; dinfo->bdrv->detect_zeroes = detect_zeroes; - dinfo->refcount = 1; - if (serial != NULL) { - dinfo->serial = g_strdup(serial); - } QTAILQ_INSERT_TAIL(&drives, dinfo, next); bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error); @@ -630,6 +610,10 @@ QemuOptsList qemu_legacy_drive_opts = { .type = QEMU_OPT_STRING, .help = "pci address (virtio only)", },{ + .name = "serial", + .type = QEMU_OPT_STRING, + .help = "disk serial number", + },{ .name = "file", .type = QEMU_OPT_STRING, .help = "file name", @@ -658,7 +642,7 @@ QemuOptsList qemu_legacy_drive_opts = { }, }; -DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) +DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) { const char *value; DriveInfo *dinfo = NULL; @@ -672,6 +656,7 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) const char *werror, *rerror; bool read_only = false; bool copy_on_read; + const char *serial; const char *filename; Error *local_err = NULL; @@ -875,6 +860,9 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) goto fail; } + /* Serial number */ + serial = qemu_opt_get(legacy_opts, "serial"); + /* no id supplied -> create one */ if (qemu_opts_id(all_opts) == NULL) { char *new_id; @@ -965,6 +953,8 @@ DriveInfo *drive_init(QemuOpts *all_opts, BlockInterfaceType block_default_type) dinfo->unit = unit_id; dinfo->devaddr = devaddr; + dinfo->serial = g_strdup(serial); + switch(type) { case IF_IDE: case IF_SCSI: @@ -1797,7 +1787,7 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data) bdrv_set_on_error(bs, BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT); } else { - drive_uninit(drive_get_by_blockdev(bs)); + drive_del(drive_get_by_blockdev(bs)); } return 0; @@ -2340,9 +2330,9 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp) goto fail; } - /* TODO Sort it out in raw-posix and drive_init: Reject aio=native with + /* TODO Sort it out in raw-posix and drive_new(): Reject aio=native with * cache.direct=false instead of silently switching to aio=threads, except - * if called from drive_init. + * when called from drive_new(). * * For now, simply forbidding the combination for all drivers will do. */ if (options->has_aio && options->aio == BLOCKDEV_AIO_OPTIONS_NATIVE) { @@ -2374,7 +2364,7 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp) } if (bdrv_key_required(dinfo->bdrv)) { - drive_uninit(dinfo); + drive_del(dinfo); error_setg(errp, "blockdev-add doesn't support encrypted devices"); goto fail; } @@ -2438,10 +2428,6 @@ QemuOptsList qemu_common_drive_opts = { .type = QEMU_OPT_STRING, .help = "disk format (raw, qcow2, ...)", },{ - .name = "serial", - .type = QEMU_OPT_STRING, - .help = "disk serial number", - },{ .name = "rerror", .type = QEMU_OPT_STRING, .help = "read error action", @@ -311,8 +311,8 @@ libusb="" usb_redir="" glx="" zlib="yes" -lzo="no" -snappy="no" +lzo="" +snappy="" guest_agent="" guest_agent_with_vss="no" vss_win32_sdk="" @@ -333,7 +333,7 @@ vte="" tpm="no" libssh2="" vhdx="" -quorum="no" +quorum="" # parse CC options first for opt do @@ -1050,8 +1050,12 @@ for opt do ;; --disable-zlib-test) zlib="no" ;; + --disable-lzo) lzo="no" + ;; --enable-lzo) lzo="yes" ;; + --disable-snappy) snappy="no" + ;; --enable-snappy) snappy="yes" ;; --enable-guest-agent) guest_agent="yes" @@ -1749,13 +1753,14 @@ if test "$lzo" != "no" ; then int main(void) { lzo_version(); return 0; } EOF if compile_prog "" "-llzo2" ; then - : + libs_softmmu="$libs_softmmu -llzo2" + lzo="yes" else - error_exit "lzo check failed" \ - "Make sure to have the lzo libs and headers installed." + if test "$lzo" = "yes"; then + feature_not_found "liblzo2" "Install liblzo2 devel" + fi + lzo="no" fi - - libs_softmmu="$libs_softmmu -llzo2" fi ########################################## @@ -1767,13 +1772,14 @@ if test "$snappy" != "no" ; then int main(void) { snappy_max_compressed_length(4096); return 0; } EOF if compile_prog "" "-lsnappy" ; then - : + libs_softmmu="$libs_softmmu -lsnappy" + snappy="yes" else - error_exit "snappy check failed" \ - "Make sure to have the snappy libs and headers installed." + if test "$snappy" = "yes"; then + feature_not_found "libsnappy" "Install libsnappy devel" + fi + snappy="no" fi - - libs_softmmu="$libs_softmmu -lsnappy" fi ########################################## @@ -2219,9 +2225,12 @@ if compile_prog "$quorum_tls_cflags" "$quorum_tls_libs" ; then libs_softmmu="$quorum_tls_libs $libs_softmmu" libs_tools="$quorum_tls_libs $libs_softmmu" QEMU_CFLAGS="$QEMU_CFLAGS $quorum_tls_cflags" + quorum="yes" else - echo "gnutls > 2.10.0 required to compile Quorum" - exit 1 + if test "$quorum" = "yes"; then + feature_not_found "gnutls" "gnutls > 2.10.0 required to compile Quorum" + fi + quorum="no" fi fi diff --git a/device-hotplug.c b/device-hotplug.c index eecb08e..e6a1ffb 100644 --- a/device-hotplug.c +++ b/device-hotplug.c @@ -40,7 +40,7 @@ DriveInfo *add_init_drive(const char *optstr) return NULL; mc = MACHINE_GET_CLASS(current_machine); - dinfo = drive_init(opts, mc->block_default_type); + dinfo = drive_new(opts, mc->block_default_type); if (!dinfo) { qemu_opts_del(opts); return NULL; @@ -76,6 +76,6 @@ void drive_hot_add(Monitor *mon, const QDict *qdict) err: if (dinfo) { - drive_put_ref(dinfo); + drive_del(dinfo); } } diff --git a/hw/block/onenand.c b/hw/block/onenand.c index 60d5311..5388122 100644 --- a/hw/block/onenand.c +++ b/hw/block/onenand.c @@ -335,9 +335,7 @@ static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn, dp, 1) < 0; } } - if (dp) { - g_free(dp); - } + g_free(dp); } return result; } diff --git a/hw/ide/piix.c b/hw/ide/piix.c index 40757eb..8651726 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -184,7 +184,7 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev) } bdrv_close(di->bdrv); pci_ide->bus[di->bus].ifs[di->unit].bs = NULL; - drive_put_ref(di); + drive_del(di); } } qdev_reset_all(DEVICE(dev)); diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index e919100..ae4efcb 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -691,7 +691,7 @@ static USBDevice *usb_msd_init(USBBus *bus, const char *filename) qemu_opt_set(opts, "if", "none"); /* create host drive */ - dinfo = drive_init(opts, 0); + dinfo = drive_new(opts, 0); if (!dinfo) { qemu_opts_del(opts); return NULL; diff --git a/include/block/block.h b/include/block/block.h index 7d86e29..f15b99b 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -204,9 +204,8 @@ BlockDriver *bdrv_find_format(const char *format_name); BlockDriver *bdrv_find_whitelisted_format(const char *format_name, bool readonly); int bdrv_create(BlockDriver *drv, const char* filename, - QEMUOptionParameter *options, Error **errp); -int bdrv_create_file(const char* filename, QEMUOptionParameter *options, - Error **errp); + QemuOpts *opts, Error **errp); +int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp); BlockDriverState *bdrv_new(const char *device_name, Error **errp); void bdrv_make_anon(BlockDriverState *bs); void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old); @@ -312,7 +311,7 @@ typedef enum { int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix); -int bdrv_amend_options(BlockDriverState *bs_new, QEMUOptionParameter *options); +int bdrv_amend_options(BlockDriverState *bs_new, QemuOpts *opts); /* external snapshots */ bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs, diff --git a/include/block/block_int.h b/include/block/block_int.h index 8d58334..7aa2213 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -116,8 +116,7 @@ struct BlockDriver { const uint8_t *buf, int nb_sectors); void (*bdrv_close)(BlockDriverState *bs); void (*bdrv_rebind)(BlockDriverState *bs); - int (*bdrv_create)(const char *filename, QEMUOptionParameter *options, - Error **errp); + int (*bdrv_create)(const char *filename, QemuOpts *opts, Error **errp); int (*bdrv_set_key)(BlockDriverState *bs, const char *key); int (*bdrv_make_empty)(BlockDriverState *bs); /* aio */ @@ -216,8 +215,7 @@ struct BlockDriver { BlockDriverCompletionFunc *cb, void *opaque); /* List of options for creating images, terminated by name == NULL */ - QEMUOptionParameter *create_options; - + QemuOptsList *create_opts; /* * Returns 0 for completed check, -errno for internal errors. @@ -226,8 +224,7 @@ struct BlockDriver { int (*bdrv_check)(BlockDriverState* bs, BdrvCheckResult *result, BdrvCheckMode fix); - int (*bdrv_amend_options)(BlockDriverState *bs, - QEMUOptionParameter *options); + int (*bdrv_amend_options)(BlockDriverState *bs, QemuOpts *opts); void (*bdrv_debug_event)(BlockDriverState *bs, BlkDebugEvent event); diff --git a/include/qemu/option.h b/include/qemu/option.h index 8c0ac34..59bea75 100644 --- a/include/qemu/option.h +++ b/include/qemu/option.h @@ -31,25 +31,6 @@ #include "qapi/error.h" #include "qapi/qmp/qdict.h" -enum QEMUOptionParType { - OPT_FLAG, - OPT_NUMBER, - OPT_SIZE, - OPT_STRING, -}; - -typedef struct QEMUOptionParameter { - const char *name; - enum QEMUOptionParType type; - union { - uint64_t n; - char* s; - } value; - const char *help; - bool assigned; -} QEMUOptionParameter; - - const char *get_opt_name(char *buf, int buf_size, const char *p, char delim); const char *get_opt_value(char *buf, int buf_size, const char *p); int get_next_param_value(char *buf, int buf_size, @@ -58,32 +39,11 @@ int get_param_value(char *buf, int buf_size, const char *tag, const char *str); -/* - * The following functions take a parameter list as input. This is a pointer to - * the first element of a QEMUOptionParameter array which is terminated by an - * entry with entry->name == NULL. - */ - -QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list, - const char *name); -int set_option_parameter(QEMUOptionParameter *list, const char *name, - const char *value); -int set_option_parameter_int(QEMUOptionParameter *list, const char *name, - uint64_t value); -QEMUOptionParameter *append_option_parameters(QEMUOptionParameter *dest, - QEMUOptionParameter *list); -QEMUOptionParameter *parse_option_parameters(const char *param, - QEMUOptionParameter *list, QEMUOptionParameter *dest); void parse_option_size(const char *name, const char *value, uint64_t *ret, Error **errp); -void free_option_parameters(QEMUOptionParameter *list); -void print_option_parameters(QEMUOptionParameter *list); -void print_option_help(QEMUOptionParameter *list); bool has_help_option(const char *param); bool is_valid_option_list(const char *param); -/* ------------------------------------------------------------------ */ - typedef struct QemuOpt QemuOpt; typedef struct QemuOpts QemuOpts; typedef struct QemuOptsList QemuOptsList; @@ -99,6 +59,7 @@ typedef struct QemuOptDesc { const char *name; enum QemuOptType type; const char *help; + const char *def_value_str; } QemuOptDesc; struct QemuOptsList { @@ -110,6 +71,7 @@ struct QemuOptsList { }; const char *qemu_opt_get(QemuOpts *opts, const char *name); +char *qemu_opt_get_del(QemuOpts *opts, const char *name); /** * qemu_opt_has_help_opt: * @opts: options to search for a help request @@ -122,9 +84,15 @@ const char *qemu_opt_get(QemuOpts *opts, const char *name); * Returns: true if @opts includes 'help' or equivalent. */ bool qemu_opt_has_help_opt(QemuOpts *opts); +QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name); bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval); uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval); uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval); +bool qemu_opt_get_bool_del(QemuOpts *opts, const char *name, bool defval); +uint64_t qemu_opt_get_number_del(QemuOpts *opts, const char *name, + uint64_t defval); +uint64_t qemu_opt_get_size_del(QemuOpts *opts, const char *name, + uint64_t defval); int qemu_opt_unset(QemuOpts *opts, const char *name); int qemu_opt_set(QemuOpts *opts, const char *name, const char *value); void qemu_opt_set_err(QemuOpts *opts, const char *name, const char *value, @@ -156,8 +124,11 @@ QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict); void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp); typedef int (*qemu_opts_loopfunc)(QemuOpts *opts, void *opaque); -int qemu_opts_print(QemuOpts *opts, void *dummy); +void qemu_opts_print(QemuOpts *opts); int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void *opaque, int abort_on_failure); +void qemu_opts_print_help(QemuOptsList *list); +void qemu_opts_free(QemuOptsList *list); +QemuOptsList *qemu_opts_append(QemuOptsList *dst, QemuOptsList *list); #endif diff --git a/include/qemu/option_int.h b/include/qemu/option_int.h index 8212fa4..6432c1a 100644 --- a/include/qemu/option_int.h +++ b/include/qemu/option_int.h @@ -30,8 +30,8 @@ #include "qemu/error-report.h" struct QemuOpt { - const char *name; - const char *str; + char *name; + char *str; const QemuOptDesc *desc; union { diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h index 134712b..23a5d10 100644 --- a/include/sysemu/blockdev.h +++ b/include/sysemu/blockdev.h @@ -37,27 +37,25 @@ struct DriveInfo { int bus; int unit; int auto_del; /* see blockdev_mark_auto_del() */ - bool enable_auto_del; /* Only for legacy drive_init() */ + bool enable_auto_del; /* Only for legacy drive_new() */ int media_cd; int cyls, heads, secs, trans; QemuOpts *opts; char *serial; QTAILQ_ENTRY(DriveInfo) next; - int refcount; }; DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit); DriveInfo *drive_get_by_index(BlockInterfaceType type, int index); int drive_get_max_bus(BlockInterfaceType type); DriveInfo *drive_get_next(BlockInterfaceType type); -void drive_get_ref(DriveInfo *dinfo); -void drive_put_ref(DriveInfo *dinfo); DriveInfo *drive_get_by_blockdev(BlockDriverState *bs); QemuOpts *drive_def(const char *optstr); QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file, const char *optstr); -DriveInfo *drive_init(QemuOpts *arg, BlockInterfaceType block_default_type); +DriveInfo *drive_new(QemuOpts *arg, BlockInterfaceType block_default_type); +void drive_del(DriveInfo *dinfo); /* device-hotplug */ diff --git a/qapi-schema.json b/qapi-schema.json index 14b498b..dc2abe4 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2855,12 +2855,15 @@ # # @help: #optional human readable text string, not suitable for parsing. # +# @default: #optional default value string (since 2.1) +# # Since 1.5 ## { 'type': 'CommandLineParameterInfo', 'data': { 'name': 'str', 'type': 'CommandLineParameterType', - '*help': 'str' } } + '*help': 'str', + '*default': 'str' } } ## # @CommandLineOptionInfo: diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c index 16382e7..f2ad6d7 100644 --- a/qapi/opts-visitor.c +++ b/qapi/opts-visitor.c @@ -143,8 +143,8 @@ opts_start_struct(Visitor *v, void **obj, const char *kind, if (ov->opts_root->id != NULL) { ov->fake_id_opt = g_malloc0(sizeof *ov->fake_id_opt); - ov->fake_id_opt->name = "id"; - ov->fake_id_opt->str = ov->opts_root->id; + ov->fake_id_opt->name = g_strdup("id"); + ov->fake_id_opt->str = g_strdup(ov->opts_root->id); opts_visitor_insert(ov->unprocessed_opts, ov->fake_id_opt); } } @@ -177,7 +177,11 @@ opts_end_struct(Visitor *v, Error **errp) } g_hash_table_destroy(ov->unprocessed_opts); ov->unprocessed_opts = NULL; - g_free(ov->fake_id_opt); + if (ov->fake_id_opt) { + g_free(ov->fake_id_opt->name); + g_free(ov->fake_id_opt->str); + g_free(ov->fake_id_opt); + } ov->fake_id_opt = NULL; } @@ -271,7 +271,7 @@ static int read_password(char *buf, int buf_size) static int print_block_option_help(const char *filename, const char *fmt) { BlockDriver *drv, *proto_drv; - QEMUOptionParameter *create_options = NULL; + QemuOptsList *create_opts = NULL; /* Find driver and parse its options */ drv = bdrv_find_format(fmt); @@ -280,22 +280,19 @@ static int print_block_option_help(const char *filename, const char *fmt) return 1; } - create_options = append_option_parameters(create_options, - drv->create_options); - + create_opts = qemu_opts_append(create_opts, drv->create_opts); if (filename) { proto_drv = bdrv_find_protocol(filename, true); if (!proto_drv) { error_report("Unknown protocol '%s'", filename); - free_option_parameters(create_options); + qemu_opts_free(create_opts); return 1; } - create_options = append_option_parameters(create_options, - proto_drv->create_options); + create_opts = qemu_opts_append(create_opts, proto_drv->create_opts); } - print_option_help(create_options); - free_option_parameters(create_options); + qemu_opts_print_help(create_opts); + qemu_opts_free(create_opts); return 0; } @@ -349,19 +346,19 @@ fail: return NULL; } -static int add_old_style_options(const char *fmt, QEMUOptionParameter *list, +static int add_old_style_options(const char *fmt, QemuOpts *opts, const char *base_filename, const char *base_fmt) { if (base_filename) { - if (set_option_parameter(list, BLOCK_OPT_BACKING_FILE, base_filename)) { + if (qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename)) { error_report("Backing file not supported for file format '%s'", fmt); return -1; } } if (base_fmt) { - if (set_option_parameter(list, BLOCK_OPT_BACKING_FMT, base_fmt)) { + if (qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt)) { error_report("Backing file format not supported for file " "format '%s'", fmt); return -1; @@ -1191,8 +1188,9 @@ static int img_convert(int argc, char **argv) size_t bufsectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE; const uint8_t *buf1; BlockDriverInfo bdi; - QEMUOptionParameter *param = NULL, *create_options = NULL; - QEMUOptionParameter *out_baseimg_param; + QemuOpts *opts = NULL; + QemuOptsList *create_opts = NULL; + const char *out_baseimg_param; char *options = NULL; const char *snapshot_name = NULL; int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */ @@ -1381,40 +1379,34 @@ static int img_convert(int argc, char **argv) goto out; } - create_options = append_option_parameters(create_options, - drv->create_options); - create_options = append_option_parameters(create_options, - proto_drv->create_options); + create_opts = qemu_opts_append(create_opts, drv->create_opts); + create_opts = qemu_opts_append(create_opts, proto_drv->create_opts); - if (options) { - param = parse_option_parameters(options, create_options, param); - if (param == NULL) { - error_report("Invalid options for file format '%s'.", out_fmt); - ret = -1; - goto out; - } - } else { - param = parse_option_parameters("", create_options, param); + opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); + if (options && qemu_opts_do_parse(opts, options, NULL)) { + error_report("Invalid options for file format '%s'", out_fmt); + ret = -1; + goto out; } - set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512); - ret = add_old_style_options(out_fmt, param, out_baseimg, NULL); + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_sectors * 512); + ret = add_old_style_options(out_fmt, opts, out_baseimg, NULL); if (ret < 0) { goto out; } /* Get backing file name if -o backing_file was used */ - out_baseimg_param = get_option_parameter(param, BLOCK_OPT_BACKING_FILE); + out_baseimg_param = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE); if (out_baseimg_param) { - out_baseimg = out_baseimg_param->value.s; + out_baseimg = out_baseimg_param; } /* Check if compression is supported */ if (compress) { - QEMUOptionParameter *encryption = - get_option_parameter(param, BLOCK_OPT_ENCRYPT); - QEMUOptionParameter *preallocation = - get_option_parameter(param, BLOCK_OPT_PREALLOC); + bool encryption = + qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, false); + const char *preallocation = + qemu_opt_get(opts, BLOCK_OPT_PREALLOC); if (!drv->bdrv_write_compressed) { error_report("Compression not supported for this file format"); @@ -1422,15 +1414,15 @@ static int img_convert(int argc, char **argv) goto out; } - if (encryption && encryption->value.n) { + if (encryption) { error_report("Compression and encryption not supported at " "the same time"); ret = -1; goto out; } - if (preallocation && preallocation->value.s - && strcmp(preallocation->value.s, "off")) + if (preallocation + && strcmp(preallocation, "off")) { error_report("Compression and preallocation not supported at " "the same time"); @@ -1441,7 +1433,7 @@ static int img_convert(int argc, char **argv) if (!skip_create) { /* Create the new image */ - ret = bdrv_create(drv, out_filename, param, &local_err); + ret = bdrv_create(drv, out_filename, opts, &local_err); if (ret < 0) { error_report("%s: error while converting %s: %s", out_filename, out_fmt, error_get_pretty(local_err)); @@ -1706,8 +1698,8 @@ out: qemu_progress_print(100, 0); } qemu_progress_end(); - free_option_parameters(create_options); - free_option_parameters(param); + qemu_opts_del(opts); + qemu_opts_free(create_opts); qemu_vfree(buf); if (sn_opts) { qemu_opts_del(sn_opts); @@ -2698,7 +2690,8 @@ static int img_amend(int argc, char **argv) { int c, ret = 0; char *options = NULL; - QEMUOptionParameter *create_options = NULL, *options_param = NULL; + QemuOptsList *create_opts = NULL; + QemuOpts *opts = NULL; const char *fmt = NULL, *filename; bool quiet = false; BlockDriverState *bs = NULL; @@ -2769,17 +2762,15 @@ static int img_amend(int argc, char **argv) goto out; } - create_options = append_option_parameters(create_options, - bs->drv->create_options); - options_param = parse_option_parameters(options, create_options, - options_param); - if (options_param == NULL) { + create_opts = qemu_opts_append(create_opts, bs->drv->create_opts); + opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); + if (options && qemu_opts_do_parse(opts, options, NULL)) { error_report("Invalid options for file format '%s'", fmt); ret = -1; goto out; } - ret = bdrv_amend_options(bs, options_param); + ret = bdrv_amend_options(bs, opts); if (ret < 0) { error_report("Error while amending options: %s", strerror(-ret)); goto out; @@ -2789,8 +2780,8 @@ out: if (bs) { bdrv_unref(bs); } - free_option_parameters(create_options); - free_option_parameters(options_param); + qemu_opts_del(opts); + qemu_opts_free(create_opts); g_free(options); if (ret) { diff --git a/qmp-commands.hx b/qmp-commands.hx index d8aa4ed..d6bb0f4 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2898,6 +2898,8 @@ Each array entry contains the following: or 'size') - "help": human readable description of the parameter (json-string, optional) + - "default": default value string for the parameter + (json-string, optional) Example: diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out index ceb2328..71ca44d 100644 --- a/tests/qemu-iotests/049.out +++ b/tests/qemu-iotests/049.out @@ -120,7 +120,7 @@ qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes. qemu-img create -f qcow2 -o size=foobar TEST_DIR/t.qcow2 qemu-img: Parameter 'size' expects a size -qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2'. +qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2' == Check correct interpretation of suffixes for cluster size == diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out index 4027e00..e372470 100644 --- a/tests/qemu-iotests/061.out +++ b/tests/qemu-iotests/061.out @@ -281,7 +281,7 @@ Lazy refcounts only supported with compatibility level 1.1 and above (use compat qemu-img: Error while amending options: Invalid argument Unknown compatibility level 0.42. qemu-img: Error while amending options: Invalid argument -Unknown option 'foo' +qemu-img: Invalid parameter 'foo' qemu-img: Invalid options for file format 'qcow2' Changing the cluster size is not supported. qemu-img: Error while amending options: Operation not supported diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out index 84aeb0c..2241cec 100644 --- a/tests/qemu-iotests/081.out +++ b/tests/qemu-iotests/081.out @@ -45,5 +45,5 @@ wrote 10485760/10485760 bytes at offset 0 10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == checking that quorum is broken == -qemu-io: can't open device (null): Could not read image for determining its format: Input/output error +qemu-io: can't open: Could not read image for determining its format: Input/output error *** done diff --git a/util/qemu-config.c b/util/qemu-config.c index f4e4f38..ba375c0 100644 --- a/util/qemu-config.c +++ b/util/qemu-config.c @@ -82,6 +82,10 @@ static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc) info->has_help = true; info->help = g_strdup(desc[i].help); } + if (desc[i].def_value_str) { + info->has_q_default = true; + info->q_default = g_strdup(desc[i].def_value_str); + } entry = g_malloc0(sizeof(*entry)); entry->value = info; diff --git a/util/qemu-option.c b/util/qemu-option.c index 324e4c5..836055a 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -123,22 +123,6 @@ int get_param_value(char *buf, int buf_size, return get_next_param_value(buf, buf_size, tag, &str); } -/* - * Searches an option list for an option with the given name - */ -QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list, - const char *name) -{ - while (list && list->name) { - if (!strcmp(list->name, name)) { - return list; - } - list++; - } - - return NULL; -} - static void parse_option_bool(const char *name, const char *value, bool *ret, Error **errp) { @@ -173,6 +157,20 @@ static void parse_option_number(const char *name, const char *value, } } +static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc, + const char *name) +{ + int i; + + for (i = 0; desc[i].name != NULL; i++) { + if (strcmp(desc[i].name, name) == 0) { + return &desc[i]; + } + } + + return NULL; +} + void parse_option_size(const char *name, const char *value, uint64_t *ret, Error **errp) { @@ -212,244 +210,6 @@ void parse_option_size(const char *name, const char *value, } } -/* - * Sets the value of a parameter in a given option list. The parsing of the - * value depends on the type of option: - * - * OPT_FLAG (uses value.n): - * If no value is given, the flag is set to 1. - * Otherwise the value must be "on" (set to 1) or "off" (set to 0) - * - * OPT_STRING (uses value.s): - * value is strdup()ed and assigned as option value - * - * OPT_SIZE (uses value.n): - * The value is converted to an integer. Suffixes for kilobytes etc. are - * allowed (powers of 1024). - * - * Returns 0 on succes, -1 in error cases - */ -int set_option_parameter(QEMUOptionParameter *list, const char *name, - const char *value) -{ - bool flag; - Error *local_err = NULL; - - // Find a matching parameter - list = get_option_parameter(list, name); - if (list == NULL) { - fprintf(stderr, "Unknown option '%s'\n", name); - return -1; - } - - // Process parameter - switch (list->type) { - case OPT_FLAG: - parse_option_bool(name, value, &flag, &local_err); - if (!local_err) { - list->value.n = flag; - } - break; - - case OPT_STRING: - if (value != NULL) { - list->value.s = g_strdup(value); - } else { - fprintf(stderr, "Option '%s' needs a parameter\n", name); - return -1; - } - break; - - case OPT_SIZE: - parse_option_size(name, value, &list->value.n, &local_err); - break; - - default: - fprintf(stderr, "Bug: Option '%s' has an unknown type\n", name); - return -1; - } - - if (local_err) { - qerror_report_err(local_err); - error_free(local_err); - return -1; - } - - list->assigned = true; - - return 0; -} - -/* - * Sets the given parameter to an integer instead of a string. - * This function cannot be used to set string options. - * - * Returns 0 on success, -1 in error cases - */ -int set_option_parameter_int(QEMUOptionParameter *list, const char *name, - uint64_t value) -{ - // Find a matching parameter - list = get_option_parameter(list, name); - if (list == NULL) { - fprintf(stderr, "Unknown option '%s'\n", name); - return -1; - } - - // Process parameter - switch (list->type) { - case OPT_FLAG: - case OPT_NUMBER: - case OPT_SIZE: - list->value.n = value; - break; - - default: - return -1; - } - - list->assigned = true; - - return 0; -} - -/* - * Frees a option list. If it contains strings, the strings are freed as well. - */ -void free_option_parameters(QEMUOptionParameter *list) -{ - QEMUOptionParameter *cur = list; - - while (cur && cur->name) { - if (cur->type == OPT_STRING) { - g_free(cur->value.s); - } - cur++; - } - - g_free(list); -} - -/* - * Count valid options in list - */ -static size_t count_option_parameters(QEMUOptionParameter *list) -{ - size_t num_options = 0; - - while (list && list->name) { - num_options++; - list++; - } - - return num_options; -} - -/* - * Append an option list (list) to an option list (dest). - * - * If dest is NULL, a new copy of list is created. - * - * Returns a pointer to the first element of dest (or the newly allocated copy) - */ -QEMUOptionParameter *append_option_parameters(QEMUOptionParameter *dest, - QEMUOptionParameter *list) -{ - size_t num_options, num_dest_options; - - num_options = count_option_parameters(dest); - num_dest_options = num_options; - - num_options += count_option_parameters(list); - - dest = g_realloc(dest, (num_options + 1) * sizeof(QEMUOptionParameter)); - dest[num_dest_options].name = NULL; - - while (list && list->name) { - if (get_option_parameter(dest, list->name) == NULL) { - dest[num_dest_options++] = *list; - dest[num_dest_options].name = NULL; - } - list++; - } - - return dest; -} - -/* - * Parses a parameter string (param) into an option list (dest). - * - * list is the template option list. If dest is NULL, a new copy of list is - * created. If list is NULL, this function fails. - * - * A parameter string consists of one or more parameters, separated by commas. - * Each parameter consists of its name and possibly of a value. In the latter - * case, the value is delimited by an = character. To specify a value which - * contains commas, double each comma so it won't be recognized as the end of - * the parameter. - * - * For more details of the parsing see above. - * - * Returns a pointer to the first element of dest (or the newly allocated copy) - * or NULL in error cases - */ -QEMUOptionParameter *parse_option_parameters(const char *param, - QEMUOptionParameter *list, QEMUOptionParameter *dest) -{ - QEMUOptionParameter *allocated = NULL; - char name[256]; - char value[256]; - char *param_delim, *value_delim; - char next_delim; - int i; - - if (list == NULL) { - return NULL; - } - - if (dest == NULL) { - dest = allocated = append_option_parameters(NULL, list); - } - - for (i = 0; dest[i].name; i++) { - dest[i].assigned = false; - } - - while (*param) { - - // Find parameter name and value in the string - param_delim = strchr(param, ','); - value_delim = strchr(param, '='); - - if (value_delim && (value_delim < param_delim || !param_delim)) { - next_delim = '='; - } else { - next_delim = ','; - value_delim = NULL; - } - - param = get_opt_name(name, sizeof(name), param, next_delim); - if (value_delim) { - param = get_opt_value(value, sizeof(value), param + 1); - } - if (*param != '\0') { - param++; - } - - // Set the parameter - if (set_option_parameter(dest, name, value_delim ? value : NULL)) { - goto fail; - } - } - - return dest; - -fail: - // Only free the list if it was newly allocated - free_option_parameters(allocated); - return NULL; -} - bool has_help_option(const char *param) { size_t buflen = strlen(param) + 1; @@ -499,49 +259,22 @@ out: return result; } -/* - * Prints all options of a list that have a value to stdout - */ -void print_option_parameters(QEMUOptionParameter *list) +void qemu_opts_print_help(QemuOptsList *list) { - while (list && list->name) { - switch (list->type) { - case OPT_STRING: - if (list->value.s != NULL) { - printf("%s='%s' ", list->name, list->value.s); - } - break; - case OPT_FLAG: - printf("%s=%s ", list->name, list->value.n ? "on" : "off"); - break; - case OPT_SIZE: - case OPT_NUMBER: - printf("%s=%" PRId64 " ", list->name, list->value.n); - break; - default: - printf("%s=(unknown type) ", list->name); - break; - } - list++; - } -} + QemuOptDesc *desc; -/* - * Prints an overview of all available options - */ -void print_option_help(QEMUOptionParameter *list) -{ + assert(list); + desc = list->desc; printf("Supported options:\n"); - while (list && list->name) { - printf("%-16s %s\n", list->name, - list->help ? list->help : "No description available"); - list++; + while (desc && desc->name) { + printf("%-16s %s\n", desc->name, + desc->help ? desc->help : "No description available"); + desc++; } } - /* ------------------------------------------------------------------ */ -static QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name) +QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name) { QemuOpt *opt; @@ -553,12 +286,69 @@ static QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name) return NULL; } +static void qemu_opt_del(QemuOpt *opt) +{ + QTAILQ_REMOVE(&opt->opts->head, opt, next); + g_free(opt->name); + g_free(opt->str); + g_free(opt); +} + +/* qemu_opt_set allows many settings for the same option. + * This function deletes all settings for an option. + */ +static void qemu_opt_del_all(QemuOpts *opts, const char *name) +{ + QemuOpt *opt, *next_opt; + + QTAILQ_FOREACH_SAFE(opt, &opts->head, next, next_opt) { + if (!strcmp(opt->name, name)) { + qemu_opt_del(opt); + } + } +} + const char *qemu_opt_get(QemuOpts *opts, const char *name) { QemuOpt *opt = qemu_opt_find(opts, name); + + if (!opt) { + const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name); + if (desc && desc->def_value_str) { + return desc->def_value_str; + } + } return opt ? opt->str : NULL; } +/* Get a known option (or its default) and remove it from the list + * all in one action. Return a malloced string of the option value. + * Result must be freed by caller with g_free(). + */ +char *qemu_opt_get_del(QemuOpts *opts, const char *name) +{ + QemuOpt *opt; + const QemuOptDesc *desc; + char *str = NULL; + + if (opts == NULL) { + return NULL; + } + + opt = qemu_opt_find(opts, name); + if (!opt) { + desc = find_desc_by_name(opts->list->desc, name); + if (desc && desc->def_value_str) { + str = g_strdup(desc->def_value_str); + } + return str; + } + str = opt->str; + opt->str = NULL; + qemu_opt_del_all(opts, name); + return str; +} + bool qemu_opt_has_help_opt(QemuOpts *opts) { QemuOpt *opt; @@ -571,34 +361,99 @@ bool qemu_opt_has_help_opt(QemuOpts *opts) return false; } -bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval) +static bool qemu_opt_get_bool_helper(QemuOpts *opts, const char *name, + bool defval, bool del) { QemuOpt *opt = qemu_opt_find(opts, name); + bool ret = defval; - if (opt == NULL) - return defval; + if (opt == NULL) { + const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name); + if (desc && desc->def_value_str) { + parse_option_bool(name, desc->def_value_str, &ret, &error_abort); + } + return ret; + } assert(opt->desc && opt->desc->type == QEMU_OPT_BOOL); - return opt->value.boolean; + ret = opt->value.boolean; + if (del) { + qemu_opt_del_all(opts, name); + } + return ret; } -uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval) +bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval) +{ + return qemu_opt_get_bool_helper(opts, name, defval, false); +} + +bool qemu_opt_get_bool_del(QemuOpts *opts, const char *name, bool defval) +{ + return qemu_opt_get_bool_helper(opts, name, defval, true); +} + +static uint64_t qemu_opt_get_number_helper(QemuOpts *opts, const char *name, + uint64_t defval, bool del) { QemuOpt *opt = qemu_opt_find(opts, name); + uint64_t ret = defval; - if (opt == NULL) - return defval; + if (opt == NULL) { + const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name); + if (desc && desc->def_value_str) { + parse_option_number(name, desc->def_value_str, &ret, &error_abort); + } + return ret; + } assert(opt->desc && opt->desc->type == QEMU_OPT_NUMBER); - return opt->value.uint; + ret = opt->value.uint; + if (del) { + qemu_opt_del_all(opts, name); + } + return ret; } -uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval) +uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval) +{ + return qemu_opt_get_number_helper(opts, name, defval, false); +} + +uint64_t qemu_opt_get_number_del(QemuOpts *opts, const char *name, + uint64_t defval) +{ + return qemu_opt_get_number_helper(opts, name, defval, true); +} + +static uint64_t qemu_opt_get_size_helper(QemuOpts *opts, const char *name, + uint64_t defval, bool del) { QemuOpt *opt = qemu_opt_find(opts, name); + uint64_t ret = defval; - if (opt == NULL) - return defval; + if (opt == NULL) { + const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name); + if (desc && desc->def_value_str) { + parse_option_size(name, desc->def_value_str, &ret, &error_abort); + } + return ret; + } assert(opt->desc && opt->desc->type == QEMU_OPT_SIZE); - return opt->value.uint; + ret = opt->value.uint; + if (del) { + qemu_opt_del_all(opts, name); + } + return ret; +} + +uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval) +{ + return qemu_opt_get_size_helper(opts, name, defval, false); +} + +uint64_t qemu_opt_get_size_del(QemuOpts *opts, const char *name, + uint64_t defval) +{ + return qemu_opt_get_size_helper(opts, name, defval, true); } static void qemu_opt_parse(QemuOpt *opt, Error **errp) @@ -624,33 +479,11 @@ static void qemu_opt_parse(QemuOpt *opt, Error **errp) } } -static void qemu_opt_del(QemuOpt *opt) -{ - QTAILQ_REMOVE(&opt->opts->head, opt, next); - g_free((/* !const */ char*)opt->name); - g_free((/* !const */ char*)opt->str); - g_free(opt); -} - static bool opts_accepts_any(const QemuOpts *opts) { return opts->list->desc[0].name == NULL; } -static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc, - const char *name) -{ - int i; - - for (i = 0; desc[i].name != NULL; i++) { - if (strcmp(desc[i].name, name) == 0) { - return &desc[i]; - } - } - - return NULL; -} - int qemu_opt_unset(QemuOpts *opts, const char *name) { QemuOpt *opt = qemu_opt_find(opts, name); @@ -884,6 +717,10 @@ void qemu_opts_del(QemuOpts *opts) { QemuOpt *opt; + if (opts == NULL) { + return; + } + for (;;) { opt = QTAILQ_FIRST(&opts->head); if (opt == NULL) @@ -895,17 +732,34 @@ void qemu_opts_del(QemuOpts *opts) g_free(opts); } -int qemu_opts_print(QemuOpts *opts, void *dummy) +void qemu_opts_print(QemuOpts *opts) { QemuOpt *opt; + QemuOptDesc *desc = opts->list->desc; - fprintf(stderr, "%s: %s:", opts->list->name, - opts->id ? opts->id : "<noid>"); - QTAILQ_FOREACH(opt, &opts->head, next) { - fprintf(stderr, " %s=\"%s\"", opt->name, opt->str); + if (desc[0].name == NULL) { + QTAILQ_FOREACH(opt, &opts->head, next) { + printf("%s=\"%s\" ", opt->name, opt->str); + } + return; + } + for (; desc && desc->name; desc++) { + const char *value; + QemuOpt *opt = qemu_opt_find(opts, desc->name); + + value = opt ? opt->str : desc->def_value_str; + if (!value) { + continue; + } + if (desc->type == QEMU_OPT_STRING) { + printf("%s='%s' ", desc->name, value); + } else if ((desc->type == QEMU_OPT_SIZE || + desc->type == QEMU_OPT_NUMBER) && opt) { + printf("%s=%" PRId64 " ", desc->name, opt->value.uint); + } else { + printf("%s=%s ", desc->name, value); + } } - fprintf(stderr, "\n"); - return 0; } static int opts_do_parse(QemuOpts *opts, const char *params, @@ -1202,3 +1056,77 @@ int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void *opaque, loc_pop(&loc); return rc; } + +static size_t count_opts_list(QemuOptsList *list) +{ + QemuOptDesc *desc = NULL; + size_t num_opts = 0; + + if (!list) { + return 0; + } + + desc = list->desc; + while (desc && desc->name) { + num_opts++; + desc++; + } + + return num_opts; +} + +void qemu_opts_free(QemuOptsList *list) +{ + g_free(list); +} + +/* Realloc dst option list and append options from an option list (list) + * to it. dst could be NULL or a malloced list. + * The lifetime of dst must be shorter than the input list because the + * QemuOptDesc->name, ->help, and ->def_value_str strings are shared. + */ +QemuOptsList *qemu_opts_append(QemuOptsList *dst, + QemuOptsList *list) +{ + size_t num_opts, num_dst_opts; + QemuOptDesc *desc; + bool need_init = false; + + if (!list) { + return dst; + } + + /* If dst is NULL, after realloc, some area of dst should be initialized + * before adding options to it. + */ + if (!dst) { + need_init = true; + } + + num_opts = count_opts_list(dst); + num_dst_opts = num_opts; + num_opts += count_opts_list(list); + dst = g_realloc(dst, sizeof(QemuOptsList) + + (num_opts + 1) * sizeof(QemuOptDesc)); + if (need_init) { + dst->name = NULL; + dst->implied_opt_name = NULL; + QTAILQ_INIT(&dst->head); + dst->merge_lists = false; + } + dst->desc[num_dst_opts].name = NULL; + + /* append list->desc to dst->desc */ + if (list) { + desc = list->desc; + while (desc && desc->name) { + if (find_desc_by_name(dst->desc, desc->name) == NULL) { + dst->desc[num_dst_opts++] = *desc; + dst->desc[num_dst_opts].name = NULL; + } + desc++; + } + } + + return dst; +} @@ -1074,7 +1074,7 @@ static int drive_init_func(QemuOpts *opts, void *opaque) { BlockInterfaceType *block_default_type = opaque; - return drive_init(opts, *block_default_type) == NULL; + return drive_new(opts, *block_default_type) == NULL; } static int drive_enable_snapshot(QemuOpts *opts, void *opaque) @@ -1098,7 +1098,7 @@ static void default_drive(int enable, int snapshot, BlockInterfaceType type, if (snapshot) { drive_enable_snapshot(opts, NULL); } - if (!drive_init(opts, type)) { + if (!drive_new(opts, type)) { exit(1); } } |