nfs: Use QAPI options in nfs_client_open()

Using the QAPI visitor to turn all options into QAPI BlockdevOptionsNfs
simplifies the code a lot. It will also be useful for implementing the
QAPI based .bdrv_co_create callback.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
stable-2.12
Kevin Wolf 2018-01-31 19:47:48 +01:00
parent aa045c2d37
commit c22a034545
1 changed files with 53 additions and 123 deletions

View File

@ -367,49 +367,6 @@ static int coroutine_fn nfs_co_flush(BlockDriverState *bs)
return task.ret;
}
static QemuOptsList runtime_opts = {
.name = "nfs",
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
.desc = {
{
.name = "path",
.type = QEMU_OPT_STRING,
.help = "Path of the image on the host",
},
{
.name = "user",
.type = QEMU_OPT_NUMBER,
.help = "UID value to use when talking to the server",
},
{
.name = "group",
.type = QEMU_OPT_NUMBER,
.help = "GID value to use when talking to the server",
},
{
.name = "tcp-syn-count",
.type = QEMU_OPT_NUMBER,
.help = "Number of SYNs to send during the session establish",
},
{
.name = "readahead-size",
.type = QEMU_OPT_NUMBER,
.help = "Set the readahead size in bytes",
},
{
.name = "page-cache-size",
.type = QEMU_OPT_NUMBER,
.help = "Set the pagecache size in bytes",
},
{
.name = "debug",
.type = QEMU_OPT_NUMBER,
.help = "Set the NFS debug level (max 2)",
},
{ /* end of list */ }
},
};
static void nfs_detach_aio_context(BlockDriverState *bs)
{
NFSClient *client = bs->opaque;
@ -452,71 +409,16 @@ static void nfs_file_close(BlockDriverState *bs)
nfs_client_close(client);
}
static NFSServer *nfs_config(QDict *options, Error **errp)
{
NFSServer *server = NULL;
QDict *addr = NULL;
QObject *crumpled_addr = NULL;
Visitor *iv = NULL;
Error *local_error = NULL;
qdict_extract_subqdict(options, &addr, "server.");
if (!qdict_size(addr)) {
error_setg(errp, "NFS server address missing");
goto out;
}
crumpled_addr = qdict_crumple(addr, errp);
if (!crumpled_addr) {
goto out;
}
/*
* Caution: this works only because all scalar members of
* NFSServer are QString in @crumpled_addr. The visitor expects
* @crumpled_addr to be typed according to the QAPI schema. It
* is when @options come from -blockdev or blockdev_add. But when
* they come from -drive, they're all QString.
*/
iv = qobject_input_visitor_new(crumpled_addr);
visit_type_NFSServer(iv, NULL, &server, &local_error);
if (local_error) {
error_propagate(errp, local_error);
goto out;
}
out:
QDECREF(addr);
qobject_decref(crumpled_addr);
visit_free(iv);
return server;
}
static int64_t nfs_client_open(NFSClient *client, QDict *options,
static int64_t nfs_client_open(NFSClient *client, BlockdevOptionsNfs *opts,
int flags, int open_flags, Error **errp)
{
int64_t ret = -EINVAL;
QemuOpts *opts = NULL;
Error *local_err = NULL;
struct stat st;
char *file = NULL, *strp = NULL;
qemu_mutex_init(&client->mutex);
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
if (local_err) {
error_propagate(errp, local_err);
ret = -EINVAL;
goto fail;
}
client->path = g_strdup(qemu_opt_get(opts, "path"));
if (!client->path) {
ret = -EINVAL;
error_setg(errp, "No path was specified");
goto fail;
}
client->path = g_strdup(opts->path);
strp = strrchr(client->path, '/');
if (strp == NULL) {
@ -526,12 +428,10 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
file = g_strdup(strp);
*strp = 0;
/* Pop the config into our state object, Exit if invalid */
client->server = nfs_config(options, errp);
if (!client->server) {
ret = -EINVAL;
goto fail;
}
/* Steal the NFSServer object from opts; set the original pointer to NULL
* to avoid use after free and double free. */
client->server = opts->server;
opts->server = NULL;
client->context = nfs_init_context();
if (client->context == NULL) {
@ -539,29 +439,29 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
goto fail;
}
if (qemu_opt_get(opts, "user")) {
client->uid = qemu_opt_get_number(opts, "user", 0);
if (opts->has_user) {
client->uid = opts->user;
nfs_set_uid(client->context, client->uid);
}
if (qemu_opt_get(opts, "group")) {
client->gid = qemu_opt_get_number(opts, "group", 0);
if (opts->has_group) {
client->gid = opts->group;
nfs_set_gid(client->context, client->gid);
}
if (qemu_opt_get(opts, "tcp-syn-count")) {
client->tcp_syncnt = qemu_opt_get_number(opts, "tcp-syn-count", 0);
if (opts->has_tcp_syn_count) {
client->tcp_syncnt = opts->tcp_syn_count;
nfs_set_tcp_syncnt(client->context, client->tcp_syncnt);
}
#ifdef LIBNFS_FEATURE_READAHEAD
if (qemu_opt_get(opts, "readahead-size")) {
if (opts->has_readahead_size) {
if (open_flags & BDRV_O_NOCACHE) {
error_setg(errp, "Cannot enable NFS readahead "
"if cache.direct = on");
goto fail;
}
client->readahead = qemu_opt_get_number(opts, "readahead-size", 0);
client->readahead = opts->readahead_size;
if (client->readahead > QEMU_NFS_MAX_READAHEAD_SIZE) {
warn_report("Truncating NFS readahead size to %d",
QEMU_NFS_MAX_READAHEAD_SIZE);
@ -576,13 +476,13 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
#endif
#ifdef LIBNFS_FEATURE_PAGECACHE
if (qemu_opt_get(opts, "page-cache-size")) {
if (opts->has_page_cache_size) {
if (open_flags & BDRV_O_NOCACHE) {
error_setg(errp, "Cannot enable NFS pagecache "
"if cache.direct = on");
goto fail;
}
client->pagecache = qemu_opt_get_number(opts, "page-cache-size", 0);
client->pagecache = opts->page_cache_size;
if (client->pagecache > QEMU_NFS_MAX_PAGECACHE_SIZE) {
warn_report("Truncating NFS pagecache size to %d pages",
QEMU_NFS_MAX_PAGECACHE_SIZE);
@ -595,8 +495,8 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
#endif
#ifdef LIBNFS_FEATURE_DEBUG
if (qemu_opt_get(opts, "debug")) {
client->debug = qemu_opt_get_number(opts, "debug", 0);
if (opts->has_debug) {
client->debug = opts->debug;
/* limit the maximum debug level to avoid potential flooding
* of our log files. */
if (client->debug > QEMU_NFS_MAX_DEBUG_LEVEL) {
@ -647,11 +547,41 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
fail:
nfs_client_close(client);
out:
qemu_opts_del(opts);
g_free(file);
return ret;
}
static int64_t nfs_client_open_qdict(NFSClient *client, QDict *options,
int flags, int open_flags, Error **errp)
{
BlockdevOptionsNfs *opts = NULL;
QObject *crumpled = NULL;
Visitor *v;
Error *local_err = NULL;
int ret;
crumpled = qdict_crumple(options, errp);
if (crumpled == NULL) {
return -EINVAL;
}
v = qobject_input_visitor_new_keyval(crumpled);
visit_type_BlockdevOptionsNfs(v, NULL, &opts, &local_err);
visit_free(v);
if (local_err) {
error_propagate(errp, local_err);
ret = -EINVAL;
goto fail;
}
ret = nfs_client_open(client, opts, flags, open_flags, errp);
fail:
qobject_decref(crumpled);
qapi_free_BlockdevOptionsNfs(opts);
return ret;
}
static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp) {
NFSClient *client = bs->opaque;
@ -659,9 +589,9 @@ static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
client->aio_context = bdrv_get_aio_context(bs);
ret = nfs_client_open(client, options,
(flags & BDRV_O_RDWR) ? O_RDWR : O_RDONLY,
bs->open_flags, errp);
ret = nfs_client_open_qdict(client, options,
(flags & BDRV_O_RDWR) ? O_RDWR : O_RDONLY,
bs->open_flags, errp);
if (ret < 0) {
return ret;
}
@ -703,7 +633,7 @@ static int coroutine_fn nfs_file_co_create_opts(const char *url, QemuOpts *opts,
goto out;
}
ret = nfs_client_open(client, options, O_CREAT, 0, errp);
ret = nfs_client_open_qdict(client, options, O_CREAT, 0, errp);
if (ret < 0) {
goto out;
}