From patchwork Thu Oct 27 10:43:41 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ashijeet Acharya X-Patchwork-Id: 9399161 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 484D4600BA for ; Thu, 27 Oct 2016 10:47:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3F8AD2A041 for ; Thu, 27 Oct 2016 10:47:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 343162A0BC; Thu, 27 Oct 2016 10:47:23 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 457AD2A041 for ; Thu, 27 Oct 2016 10:47:21 +0000 (UTC) Received: from localhost ([::1]:40183 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bziDR-0001mG-5b for patchwork-qemu-devel@patchwork.kernel.org; Thu, 27 Oct 2016 06:47:21 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:46051) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bziCw-0001kQ-ML for qemu-devel@nongnu.org; Thu, 27 Oct 2016 06:46:52 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bziCt-0003LO-Hv for qemu-devel@nongnu.org; Thu, 27 Oct 2016 06:46:50 -0400 Received: from mail-pf0-x242.google.com ([2607:f8b0:400e:c00::242]:34749) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1bziCt-0003L5-7r; Thu, 27 Oct 2016 06:46:47 -0400 Received: by mail-pf0-x242.google.com with SMTP id u84so2342073pfj.1; Thu, 27 Oct 2016 03:46:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=JUOPfZAlih/YuW+A/8owzAvSwrnOJ+DOJZhSO3fMwIQ=; b=nrKG4SNi3URBRMz0WoZKjhU3S5jPXKKWUopFhlRN8dr44zJypcELPrOXPI0xxZlDEi ko9DpQpPue4aPFRh/b7YVW9vsof6nHwbgr9ASbrfnEy5isWmjZrl//qtrjNg5cR7ndzU GjAFISoMA6DAkIHzVoe4Ke67yK3JYDPadGyO4K+1I2nv1oFH9Le0yzFu6UNaLKRKmuK+ +2nrQUu7z4OkPmW4sNOJ/tGTwgHW0KDgLfi4BtNpjQi9+jhOjYM3fjhIbREq8zgcn+ck 1embd8lvVTScWmqYgEEvxrsVgwgAIQjeev978lgcw5pV6aM8m9rSJsRMMsFUkLDGGFZW uAQw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=JUOPfZAlih/YuW+A/8owzAvSwrnOJ+DOJZhSO3fMwIQ=; b=bL26X+ldD+9YtjodtYktiWtlhSS+3OPk4Uzdf7742+5m8ARaDehdbe8rLwaYwJoGGL Y9OpfGDFrKfTH/eTk4STrMPZbCFSTEFKPUOWz9bPlyvYxI9zgI7vsfuDZj2BXkc8C8gh v3MZj43RtTvqiRMg1sg1IpoHYZd0pDb0PPnNjqVGgPN+gx7oUL/3HGnSGWz5Fu3CGXkI RaUPQJbP66hEn/2Cbxz0+6N17vgRJCcOIqtXu0kNuplkQtn2JroglYplOBJiiJzoQeBJ ORtPxP4qmLDHpALIWpSgE402+qorLbaqz37wqMCJx14Qqcy/9p7aeJDi76tHQ4tHptsa jtig== X-Gm-Message-State: ABUngvfgpuKl8aWrvIRuUZfQsdXa2BbNJhCif67e4W6Z+iYkRtYPZ8/nmoBTvXLwmfr3Ag== X-Received: by 10.98.138.79 with SMTP id y76mr13445720pfd.158.1477565206081; Thu, 27 Oct 2016 03:46:46 -0700 (PDT) Received: from linux.local ([47.247.49.45]) by smtp.gmail.com with ESMTPSA id h8sm10808715pab.9.2016.10.27.03.46.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 27 Oct 2016 03:46:45 -0700 (PDT) From: Ashijeet Acharya To: kwolf@redhat.com Date: Thu, 27 Oct 2016 16:13:41 +0530 Message-Id: <1477565022-11377-2-git-send-email-ashijeetacharya@gmail.com> X-Mailer: git-send-email 2.6.2 In-Reply-To: <1477565022-11377-1-git-send-email-ashijeetacharya@gmail.com> References: <1477565022-11377-1-git-send-email-ashijeetacharya@gmail.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2607:f8b0:400e:c00::242 Subject: [Qemu-devel] [PATCH v3 1/2] block/nfs: Introduce runtime_opts in NFS X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: qemu-block@nongnu.org, jcody@redhat.com, pl@kamp.de, qemu-devel@nongnu.org, armbru@redhat.com, Ashijeet Acharya , mreitz@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Make NFS block driver use various fine grained runtime_opts. Set .bdrv_parse_filename() to nfs_parse_filename() and introduce two new functions nfs_parse_filename() and nfs_parse_uri() to help parsing the URI. Signed-off-by: Ashijeet Acharya --- block/nfs.c | 331 +++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 238 insertions(+), 93 deletions(-) diff --git a/block/nfs.c b/block/nfs.c index 8602a44..739ae8a 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -35,8 +35,12 @@ #include "qemu/uri.h" #include "qemu/cutils.h" #include "sysemu/sysemu.h" +#include "qapi/qmp/qdict.h" +#include "qapi/qmp/qint.h" +#include "qapi/qmp/qstring.h" #include + #define QEMU_NFS_MAX_READAHEAD_SIZE 1048576 #define QEMU_NFS_MAX_PAGECACHE_SIZE (8388608 / NFS_BLKSIZE) #define QEMU_NFS_MAX_DEBUG_LEVEL 2 @@ -61,6 +65,107 @@ typedef struct NFSRPC { NFSClient *client; } NFSRPC; +static int nfs_parse_uri(const char *filename, QDict *options, Error **errp) +{ + URI *uri = NULL; + QueryParams *qp = NULL; + int ret = -EINVAL, i; + + uri = uri_parse(filename); + if (!uri) { + error_setg(errp, "Invalid URI specified"); + goto out; + } + if (strcmp(uri->scheme, "nfs") != 0) { + error_setg(errp, "URI scheme must be 'nfs'"); + goto out; + } + + if (!uri->server) { + error_setg(errp, "missing hostname in URI"); + goto out; + } + + if (!uri->path) { + error_setg(errp, "missing file path in URI"); + goto out; + } + + qp = query_params_parse(uri->query); + if (!qp) { + error_setg(errp, "could not parse query parameters"); + goto out; + } + + qdict_put(options, "host", qstring_from_str(uri->server)); + qdict_put(options, "path", qstring_from_str(uri->path)); + + for (i = 0; i < qp->n; i++) { + if (!qp->p[i].value) { + error_setg(errp, "Value for NFS parameter expected: %s", + qp->p[i].name); + goto out; + } + if (parse_uint_full(qp->p[i].value, NULL, 0)) { + error_setg(errp, "Illegal value for NFS parameter: %s", + qp->p[i].name); + goto out; + } + if (!strcmp(qp->p[i].name, "uid")) { + qdict_put(options, "user", + qstring_from_str(qp->p[i].value)); + } else if (!strcmp(qp->p[i].name, "gid")) { + qdict_put(options, "group", + qstring_from_str(qp->p[i].value)); + } else if (!strcmp(qp->p[i].name, "tcp-syncnt")) { + qdict_put(options, "tcp-syn-count", + qstring_from_str(qp->p[i].value)); + } else if (!strcmp(qp->p[i].name, "readahead")) { + qdict_put(options, "readahead-size", + qstring_from_str(qp->p[i].value)); + } else if (!strcmp(qp->p[i].name, "pagecache")) { + qdict_put(options, "page-cache-size", + qstring_from_str(qp->p[i].value)); + } else if (!strcmp(qp->p[i].name, "debug")) { + qdict_put(options, "debug-level", + qstring_from_str(qp->p[i].value)); + } else { + error_setg(errp, "Unknown NFS parameter name: %s", + qp->p[i].name); + goto out; + } + } + ret = 0; +out: + if (qp) { + query_params_free(qp); + } + if (uri) { + uri_free(uri); + } + return ret; +} + +static void nfs_parse_filename(const char *filename, QDict *options, + Error **errp) +{ + if (qdict_haskey(options, "host") || + qdict_haskey(options, "path") || + qdict_haskey(options, "user") || + qdict_haskey(options, "group") || + qdict_haskey(options, "tcp-syn-count") || + qdict_haskey(options, "readahead-size") || + qdict_haskey(options, "page-cache-size") || + qdict_haskey(options, "debug-level")) { + error_setg(errp, "host/path/uid/gid/tcp-syncnt/readahead/pagecache" + "/debug and a filename may not be used at the same" + " time"); + return; + } + + nfs_parse_uri(filename, options, errp); +} + static void nfs_process_read(void *arg); static void nfs_process_write(void *arg); @@ -228,15 +333,49 @@ static int coroutine_fn nfs_co_flush(BlockDriverState *bs) return task.ret; } -/* TODO Convert to fine grained options */ static QemuOptsList runtime_opts = { .name = "nfs", .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), .desc = { { - .name = "filename", + .name = "host", .type = QEMU_OPT_STRING, - .help = "URL to the NFS file", + .help = "Host to connect to", + }, + { + .name = "path", + .type = QEMU_OPT_STRING, + .help = "Path of the image on the host", + }, + { + .name = "uid", + .type = QEMU_OPT_NUMBER, + .help = "UID value to use when talking to the server", + }, + { + .name = "gid", + .type = QEMU_OPT_NUMBER, + .help = "GID value to use when talking to the server", + }, + { + .name = "tcp-syncnt", + .type = QEMU_OPT_NUMBER, + .help = "Number of SYNs to send during the session establish", + }, + { + .name = "readahead", + .type = QEMU_OPT_NUMBER, + .help = "Set the readahead size in bytes", + }, + { + .name = "pagecache", + .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 */ } }, @@ -279,25 +418,40 @@ static void nfs_file_close(BlockDriverState *bs) nfs_client_close(client); } -static int64_t nfs_client_open(NFSClient *client, const char *filename, +static int64_t nfs_client_open(NFSClient *client, QDict *options, int flags, Error **errp, int open_flags) { - int ret = -EINVAL, i; + int ret = -EINVAL; + QemuOpts *opts = NULL; + Error *local_err = NULL; struct stat st; - URI *uri; - QueryParams *qp = NULL; char *file = NULL, *strp = NULL; + const char *host, *path; + unsigned long long val; - uri = uri_parse(filename); - if (!uri) { - error_setg(errp, "Invalid URL specified"); + 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; } - if (!uri->server) { - error_setg(errp, "Invalid URL specified"); + + host = qemu_opt_get(opts, "host"); + if (!host) { + ret = -EINVAL; + error_setg(errp, "No hostname was specified"); goto fail; } - strp = strrchr(uri->path, '/'); + + path = qemu_opt_get(opts, "path"); + if (!path) { + ret = -EINVAL; + error_setg(errp, "No path was specified"); + goto fail; + } + + strp = strrchr(path, '/'); if (strp == NULL) { error_setg(errp, "Invalid URL specified"); goto fail; @@ -311,79 +465,76 @@ static int64_t nfs_client_open(NFSClient *client, const char *filename, goto fail; } - qp = query_params_parse(uri->query); - for (i = 0; i < qp->n; i++) { - unsigned long long val; - if (!qp->p[i].value) { - error_setg(errp, "Value for NFS parameter expected: %s", - qp->p[i].name); + if (qemu_opt_get(opts, "uid")) { + nfs_set_uid(client->context, + qemu_opt_get_number(opts, "uid", 0)); + } + + if (qemu_opt_get(opts, "gid")) { + nfs_set_gid(client->context, + qemu_opt_get_number(opts, "gid", 0)); + } + + if (qemu_opt_get(opts, "tcp-syncnt")) { + nfs_set_tcp_syncnt(client->context, + qemu_opt_get_number(opts, "tcp-syncnt", 0)); + } + +#ifdef LIBNFS_FEATURE_READAHEAD + if (qemu_opt_get(opts, "readahead")) { + if (open_flags & BDRV_O_NOCACHE) { + error_setg(errp, "Cannot enable NFS readahead " + "if cache.direct = on"); goto fail; } - if (parse_uint_full(qp->p[i].value, &val, 0)) { - error_setg(errp, "Illegal value for NFS parameter: %s", - qp->p[i].name); - goto fail; + val = qemu_opt_get_number(opts, "readahead", 0); + if (val > QEMU_NFS_MAX_READAHEAD_SIZE) { + error_report("NFS Warning: Truncating NFS readahead " + "size to %d", QEMU_NFS_MAX_READAHEAD_SIZE); + val = QEMU_NFS_MAX_READAHEAD_SIZE; } - if (!strcmp(qp->p[i].name, "uid")) { - nfs_set_uid(client->context, val); - } else if (!strcmp(qp->p[i].name, "gid")) { - nfs_set_gid(client->context, val); - } else if (!strcmp(qp->p[i].name, "tcp-syncnt")) { - nfs_set_tcp_syncnt(client->context, val); -#ifdef LIBNFS_FEATURE_READAHEAD - } else if (!strcmp(qp->p[i].name, "readahead")) { - if (open_flags & BDRV_O_NOCACHE) { - error_setg(errp, "Cannot enable NFS readahead " - "if cache.direct = on"); - goto fail; - } - if (val > QEMU_NFS_MAX_READAHEAD_SIZE) { - error_report("NFS Warning: Truncating NFS readahead" - " size to %d", QEMU_NFS_MAX_READAHEAD_SIZE); - val = QEMU_NFS_MAX_READAHEAD_SIZE; - } - nfs_set_readahead(client->context, val); + nfs_set_readahead(client->context, val); #ifdef LIBNFS_FEATURE_PAGECACHE - nfs_set_pagecache_ttl(client->context, 0); + nfs_set_pagecache_ttl(client->context, 0); #endif - client->cache_used = true; + client->cache_used = true; + } #endif + #ifdef LIBNFS_FEATURE_PAGECACHE - nfs_set_pagecache_ttl(client->context, 0); - } else if (!strcmp(qp->p[i].name, "pagecache")) { - if (open_flags & BDRV_O_NOCACHE) { - error_setg(errp, "Cannot enable NFS pagecache " - "if cache.direct = on"); - goto fail; - } - if (val > QEMU_NFS_MAX_PAGECACHE_SIZE) { - error_report("NFS Warning: Truncating NFS pagecache" - " size to %d pages", QEMU_NFS_MAX_PAGECACHE_SIZE); - val = QEMU_NFS_MAX_PAGECACHE_SIZE; - } - nfs_set_pagecache(client->context, val); - nfs_set_pagecache_ttl(client->context, 0); - client->cache_used = true; + if (qemu_opt_get(opts, "pagecache")) { + if (open_flags & BDRV_O_NOCACHE) { + error_setg(errp, "Cannot enable NFS pagecache " + "if cache.direct = on"); + goto fail; + } + val = qemu_opt_get_number(opts, "pagecache", 0); + if (val > QEMU_NFS_MAX_PAGECACHE_SIZE) { + error_report("NFS Warning: Truncating NFS pagecache " + "size to %d pages", QEMU_NFS_MAX_PAGECACHE_SIZE); + val = QEMU_NFS_MAX_PAGECACHE_SIZE; + } + nfs_set_pagecache(client->context, val); + nfs_set_pagecache_ttl(client->context, 0); + client->cache_used = true; + } #endif + #ifdef LIBNFS_FEATURE_DEBUG - } else if (!strcmp(qp->p[i].name, "debug")) { - /* limit the maximum debug level to avoid potential flooding - * of our log files. */ - if (val > QEMU_NFS_MAX_DEBUG_LEVEL) { - error_report("NFS Warning: Limiting NFS debug level" - " to %d", QEMU_NFS_MAX_DEBUG_LEVEL); - val = QEMU_NFS_MAX_DEBUG_LEVEL; - } - nfs_set_debug(client->context, val); -#endif - } else { - error_setg(errp, "Unknown NFS parameter name: %s", - qp->p[i].name); - goto fail; + if (qemu_opt_get(opts, "debug")) { + val = qemu_opt_get_number(opts, "debug", 0); + /* limit the maximum debug level to avoid potential flooding + * of our log files. */ + if (val > QEMU_NFS_MAX_DEBUG_LEVEL) { + error_report("NFS Warning: Limiting NFS debug level " + "to %d", QEMU_NFS_MAX_DEBUG_LEVEL); + val = QEMU_NFS_MAX_DEBUG_LEVEL; } + nfs_set_debug(client->context, val); } +#endif - ret = nfs_mount(client->context, uri->server, uri->path); + ret = nfs_mount(client->context, host, path); if (ret < 0) { error_setg(errp, "Failed to mount nfs share: %s", nfs_get_error(client->context)); @@ -417,13 +568,11 @@ static int64_t nfs_client_open(NFSClient *client, const char *filename, client->st_blocks = st.st_blocks; client->has_zero_init = S_ISREG(st.st_mode); goto out; + fail: nfs_client_close(client); out: - if (qp) { - query_params_free(qp); - } - uri_free(uri); + qemu_opts_del(opts); g_free(file); return ret; } @@ -432,28 +581,17 @@ static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) { NFSClient *client = bs->opaque; int64_t ret; - QemuOpts *opts; - Error *local_err = NULL; client->aio_context = bdrv_get_aio_context(bs); - 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 out; - } - ret = nfs_client_open(client, qemu_opt_get(opts, "filename"), + ret = nfs_client_open(client, options, (flags & BDRV_O_RDWR) ? O_RDWR : O_RDONLY, errp, bs->open_flags); if (ret < 0) { - goto out; + return ret; } bs->total_sectors = ret; ret = 0; -out: - qemu_opts_del(opts); return ret; } @@ -475,6 +613,7 @@ static int nfs_file_create(const char *url, QemuOpts *opts, Error **errp) int ret = 0; int64_t total_size = 0; NFSClient *client = g_new0(NFSClient, 1); + QDict *options = NULL; client->aio_context = qemu_get_aio_context(); @@ -482,7 +621,13 @@ static int nfs_file_create(const char *url, QemuOpts *opts, Error **errp) total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), BDRV_SECTOR_SIZE); - ret = nfs_client_open(client, url, O_CREAT, errp, 0); + options = qdict_new(); + ret = nfs_parse_uri(url, options, errp); + if (ret < 0) { + goto out; + } + + ret = nfs_client_open(client, options, O_CREAT, errp, 0); if (ret < 0) { goto out; } @@ -578,7 +723,7 @@ static BlockDriver bdrv_nfs = { .protocol_name = "nfs", .instance_size = sizeof(NFSClient), - .bdrv_needs_filename = true, + .bdrv_parse_filename = nfs_parse_filename, .create_opts = &nfs_create_opts, .bdrv_has_zero_init = nfs_has_zero_init,