From: Peter Lieven <pl@kamp.de>
To: "Benoît Canet" <benoit.canet@irqsave.net>
Cc: Kevin Wolf <kwolf@redhat.com>, Fam Zheng <famz@redhat.com>,
Stefan Hajnoczi <stefanha@redhat.com>,
Jeff Cody <jcody@redhat.com>,
qemu-devel@nongnu.org, Max Reitz <mreitz@redhat.com>,
owasserm@redhat.com, Federico Simoncelli <fsimonce@redhat.com>,
ronniesahlberg@gmail.com,
Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Subject: Re: [Qemu-devel] [PATCHv7 1/5] block: add native support for NFS
Date: Fri, 31 Jan 2014 12:36:29 +0100 [thread overview]
Message-ID: <52EB8ABD.6070208@kamp.de> (raw)
In-Reply-To: <20140129161959.GG3079@irqsave.net>
On 29.01.2014 17:19, Benoît Canet wrote:
> Le Wednesday 29 Jan 2014 à 09:50:21 (+0100), Peter Lieven a écrit :
>> This patch adds native support for accessing images on NFS
>> shares without the requirement to actually mount the entire
>> NFS share on the host.
>>
>> NFS Images can simply be specified by an url of the form:
>> nfs://<host>/<export>/<filename>[?param=value[¶m2=value2[&...]]]
>>
>> For example:
>> qemu-img create -f qcow2 nfs://10.0.0.1/qemu-images/test.qcow2
>>
>> You need LibNFS from Ronnie Sahlberg available at:
>> git://github.com/sahlberg/libnfs.git
>> for this to work.
>>
>> During configure it is automatically probed for libnfs and support
>> is enabled on-the-fly. You can forbid or enforce libnfs support
>> with --disable-libnfs or --enable-libnfs respectively.
>>
>> Due to NFS restrictions you might need to execute your binaries
>> as root, allow them to open priviledged ports (<1024) or specify
>> insecure option on the NFS server.
>>
>> For additional information on ROOT vs. non-ROOT operation and URL
>> format + parameters see:
>> https://raw.github.com/sahlberg/libnfs/master/README
>>
>> Supported by qemu are the uid, gid and tcp-syncnt URL parameters.
>>
>> LibNFS currently support NFS version 3 only.
>>
>> Signed-off-by: Peter Lieven <pl@kamp.de>
>> ---
>> MAINTAINERS | 5 +
>> block/Makefile.objs | 1 +
>> block/nfs.c | 440 +++++++++++++++++++++++++++++++++++++++++++++++++++
>> configure | 26 +++
>> qapi-schema.json | 1 +
>> 5 files changed, 473 insertions(+)
>> create mode 100644 block/nfs.c
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index fb53242..f8411f9 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -936,6 +936,11 @@ M: Peter Lieven <pl@kamp.de>
>> S: Supported
>> F: block/iscsi.c
>>
>> +NFS
>> +M: Peter Lieven <pl@kamp.de>
>> +S: Maintained
>> +F: block/nfs.c
>> +
>> SSH
>> M: Richard W.M. Jones <rjones@redhat.com>
>> S: Supported
>> diff --git a/block/Makefile.objs b/block/Makefile.objs
>> index 4e8c91e..e254a21 100644
>> --- a/block/Makefile.objs
>> +++ b/block/Makefile.objs
>> @@ -12,6 +12,7 @@ block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
>> ifeq ($(CONFIG_POSIX),y)
>> block-obj-y += nbd.o nbd-client.o sheepdog.o
>> block-obj-$(CONFIG_LIBISCSI) += iscsi.o
>> +block-obj-$(CONFIG_LIBNFS) += nfs.o
>> block-obj-$(CONFIG_CURL) += curl.o
>> block-obj-$(CONFIG_RBD) += rbd.o
>> block-obj-$(CONFIG_GLUSTERFS) += gluster.o
>> diff --git a/block/nfs.c b/block/nfs.c
>> new file mode 100644
>> index 0000000..2bbf7a2
>> --- /dev/null
>> +++ b/block/nfs.c
>> @@ -0,0 +1,440 @@
>> +/*
>> + * QEMU Block driver for native access to files on NFS shares
>> + *
>> + * Copyright (c) 2014 Peter Lieven <pl@kamp.de>
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a copy
>> + * of this software and associated documentation files (the "Software"), to deal
>> + * in the Software without restriction, including without limitation the rights
>> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>> + * copies of the Software, and to permit persons to whom the Software is
>> + * furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>> + * THE SOFTWARE.
>> + */
>> +
>> +#include "config-host.h"
>> +
>> +#include <poll.h>
>> +#include "qemu-common.h"
>> +#include "qemu/config-file.h"
>> +#include "qemu/error-report.h"
>> +#include "block/block_int.h"
>> +#include "trace.h"
>> +#include "qemu/iov.h"
>> +#include "qemu/uri.h"
>> +#include "sysemu/sysemu.h"
>> +#include <nfsc/libnfs.h>
>> +
>> +typedef struct NFSClient {
>> + struct nfs_context *context;
>> + struct nfsfh *fh;
>> + int events;
>> + bool has_zero_init;
>> +} NFSClient;
>> +
>> +typedef struct NFSRPC {
>> + int status;
>> + int complete;
>> + QEMUIOVector *iov;
>> + struct stat *st;
>> + Coroutine *co;
>> + QEMUBH *bh;
>> +} NFSRPC;
>> +
>> +static void nfs_process_read(void *arg);
>> +static void nfs_process_write(void *arg);
>> +
>> +static void nfs_set_events(NFSClient *client)
>> +{
>> + int ev = nfs_which_events(client->context);
>> + if (ev != client->events) {
>> + qemu_aio_set_fd_handler(nfs_get_fd(client->context),
>> + (ev & POLLIN) ? nfs_process_read : NULL,
>> + (ev & POLLOUT) ? nfs_process_write : NULL,
>> + client);
>> +
>> + }
>> + client->events = ev;
>> +}
>> +
>> +static void nfs_process_read(void *arg)
>> +{
>> + NFSClient *client = arg;
>> + nfs_service(client->context, POLLIN);
>> + nfs_set_events(client);
>> +}
>> +
>> +static void nfs_process_write(void *arg)
>> +{
>> + NFSClient *client = arg;
>> + nfs_service(client->context, POLLOUT);
>> + nfs_set_events(client);
>> +}
>> +
>> +static void nfs_co_init_task(NFSClient *client, NFSRPC *task)
>> +{
>> + *task = (NFSRPC) {
>> + .co = qemu_coroutine_self(),
>> + };
>> +}
>> +
>> +static void nfs_co_generic_bh_cb(void *opaque)
>> +{
>> + NFSRPC *task = opaque;
>> + qemu_bh_delete(task->bh);
>> + qemu_coroutine_enter(task->co, NULL);
>> +}
>> +
>> +static void
>> +nfs_co_generic_cb(int status, struct nfs_context *nfs, void *data,
>> + void *private_data)
>> +{
>> + NFSRPC *task = private_data;
>> + task->complete = 1;
>> + task->status = status;
>> + if (task->status > 0 && task->iov) {
>> + if (task->status <= task->iov->size) {
> It feel very odd to compare something named status with something named size.
>
>> + qemu_iovec_from_buf(task->iov, 0, data, task->status);
>> + } else {
>> + task->status = -EIO;
>> + }
>> + }
>> + if (task->status == 0 && task->st) {
>> + memcpy(task->st, data, sizeof(struct stat));
>> + }
>> + if (task->co) {
>> + task->bh = qemu_bh_new(nfs_co_generic_bh_cb, task);
>> + qemu_bh_schedule(task->bh);
>> + }
>> +}
>> +
>> +static int coroutine_fn nfs_co_readv(BlockDriverState *bs,
>> + int64_t sector_num, int nb_sectors,
>> + QEMUIOVector *iov)
>> +{
>> + NFSClient *client = bs->opaque;
>> + NFSRPC task;
>> +
>> + nfs_co_init_task(client, &task);
>> + task.iov = iov;
>> +
>> + if (nfs_pread_async(client->context, client->fh,
>> + sector_num * BDRV_SECTOR_SIZE,
>> + nb_sectors * BDRV_SECTOR_SIZE,
>> + nfs_co_generic_cb, &task) != 0) {
>> + return -ENOMEM;
>> + }
>> +
>> + while (!task.complete) {
>> + nfs_set_events(client);
>> + qemu_coroutine_yield();
>> + }
>> +
>> + if (task.status < 0) {
>> + return task.status;
>> + }
>> +
>> + /* zero pad short reads */
>> + if (task.status < iov->size) {
>> + qemu_iovec_memset(iov, task.status, 0, iov->size - task.status);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int coroutine_fn nfs_co_writev(BlockDriverState *bs,
>> + int64_t sector_num, int nb_sectors,
>> + QEMUIOVector *iov)
>> +{
>> + NFSClient *client = bs->opaque;
>> + NFSRPC task;
>> + char *buf = NULL;
>> +
>> + nfs_co_init_task(client, &task);
>> +
>> + buf = g_malloc(nb_sectors * BDRV_SECTOR_SIZE);
>> + qemu_iovec_to_buf(iov, 0, buf, nb_sectors * BDRV_SECTOR_SIZE);
>> +
>> + if (nfs_pwrite_async(client->context, client->fh,
>> + sector_num * BDRV_SECTOR_SIZE,
>> + nb_sectors * BDRV_SECTOR_SIZE,
>> + buf, nfs_co_generic_cb, &task) != 0) {
>> + g_free(buf);
>> + return -ENOMEM;
>> + }
>> +
>> + while (!task.complete) {
>> + nfs_set_events(client);
>> + qemu_coroutine_yield();
>> + }
>> +
>> + g_free(buf);
>> +
>> + if (task.status != nb_sectors * BDRV_SECTOR_SIZE) {
>> + return task.status < 0 ? task.status : -EIO;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int coroutine_fn nfs_co_flush(BlockDriverState *bs)
>> +{
>> + NFSClient *client = bs->opaque;
>> + NFSRPC task;
>> +
>> + nfs_co_init_task(client, &task);
>> +
>> + if (nfs_fsync_async(client->context, client->fh, nfs_co_generic_cb,
>> + &task) != 0) {
>> + return -ENOMEM;
>> + }
>> +
>> + while (!task.complete) {
>> + nfs_set_events(client);
>> + qemu_coroutine_yield();
>> + }
>> +
>> + return task.status;
>> +}
>> +
>> +/* TODO Convert to fine grained options */
>> +static QemuOptsList runtime_opts = {
>> + .name = "nfs",
>> + .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
>> + .desc = {
>> + {
>> + .name = "filename",
>> + .type = QEMU_OPT_STRING,
>> + .help = "URL to the NFS file",
>> + },
>> + { /* end of list */ }
>> + },
>> +};
>> +
>> +static void nfs_client_close(NFSClient *client)
>> +{
>> + if (client->context) {
>> + if (client->fh) {
>> + nfs_close(client->context, client->fh);
>> + }
>> + qemu_aio_set_fd_handler(nfs_get_fd(client->context), NULL, NULL, NULL);
>> + nfs_destroy_context(client->context);
>> + }
>> + memset(client, 0, sizeof(NFSClient));
>> +}
>> +
>> +static void nfs_file_close(BlockDriverState *bs)
>> +{
>> + NFSClient *client = bs->opaque;
>> + nfs_client_close(client);
>> +}
>> +
>> +static int64_t nfs_.cilclient_open(NFSClient *client, const char *filename,
>> + int flags, Error **errp)
>> +{
>> + int ret = -EINVAL, i;
>> + struct stat st;
>> + URI *uri;
>> + QueryParams *qp = NULL;
>> + char *file = NULL, *strp = NULL;
>> +
>> + uri = uri_parse(filename);
>> + if (!uri) {
>> + error_setg(errp, "Invalid URL specified");
>> + goto fail;
> Should this be goto out since we don't have done nfs_init_context yet ?
it doesn't matter nfs_client_close can be called with client->context == NULL.
Sorry I entirely missed your other comments.
Peter
next prev parent reply other threads:[~2014-01-31 11:37 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-01-29 8:50 [Qemu-devel] [PATCHv7 0/5] block: add native support for NFS Peter Lieven
2014-01-29 8:50 ` [Qemu-devel] [PATCHv7 1/5] " Peter Lieven
2014-01-29 16:19 ` Benoît Canet
2014-01-29 16:38 ` Peter Lieven
2014-01-30 9:05 ` Stefan Hajnoczi
2014-01-30 9:12 ` Peter Lieven
2014-01-30 14:23 ` Stefan Hajnoczi
2014-01-30 21:33 ` Peter Lieven
2014-01-30 14:22 ` Stefan Hajnoczi
2014-01-30 21:35 ` Peter Lieven
2014-01-31 8:57 ` Stefan Hajnoczi
2014-01-31 9:11 ` Peter Lieven
2014-01-31 10:46 ` Stefan Hajnoczi
2014-01-31 11:16 ` Peter Lieven
2014-01-31 11:36 ` Peter Lieven [this message]
2014-01-29 8:50 ` [Qemu-devel] [PATCHv7 2/5] qemu-iotests: change _supported_proto to file for various tests Peter Lieven
2014-01-29 8:50 ` [Qemu-devel] [PATCHv7 3/5] qemu-iotests: enable support for NFS protocol Peter Lieven
2014-01-29 8:50 ` [Qemu-devel] [PATCHv7 4/5] qemu-iotests: enable test 016 and 025 to work with " Peter Lieven
2014-01-29 8:50 ` [Qemu-devel] [PATCHv7 5/5] qemu-iotests: blacklist test 020 for " Peter Lieven
2014-01-29 13:59 ` [Qemu-devel] [PATCHv7 0/5] block: add native support for NFS Stefan Hajnoczi
2014-01-29 14:13 ` Peter Lieven
2014-01-29 14:22 ` Peter Lieven
2014-01-29 14:26 ` Peter Lieven
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=52EB8ABD.6070208@kamp.de \
--to=pl@kamp.de \
--cc=benoit.canet@irqsave.net \
--cc=famz@redhat.com \
--cc=fsimonce@redhat.com \
--cc=jcody@redhat.com \
--cc=kwolf@redhat.com \
--cc=mreitz@redhat.com \
--cc=owasserm@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=ronniesahlberg@gmail.com \
--cc=stefanha@redhat.com \
--cc=xiawenc@linux.vnet.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).