qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
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[&param2=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

  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).