From nobody Sun Feb 8 20:59:48 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1488901991255638.8074719402821; Tue, 7 Mar 2017 07:53:11 -0800 (PST) Received: from localhost ([::1]:51313 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1clHQC-0003LJ-LE for importer@patchew.org; Tue, 07 Mar 2017 10:53:08 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42852) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1clHF1-0002WG-Hv for qemu-devel@nongnu.org; Tue, 07 Mar 2017 10:41:37 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1clHEz-0002uB-GR for qemu-devel@nongnu.org; Tue, 07 Mar 2017 10:41:35 -0500 Received: from mx1.redhat.com ([209.132.183.28]:57920) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1clHEt-0002qn-Ug; Tue, 07 Mar 2017 10:41:28 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 150DAC04B92D; Tue, 7 Mar 2017 15:41:28 +0000 (UTC) Received: from noname.str.redhat.com (dhcp-192-197.str.redhat.com [10.33.192.197]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v27FeuUm032123; Tue, 7 Mar 2017 10:41:26 -0500 From: Kevin Wolf To: qemu-block@nongnu.org Date: Tue, 7 Mar 2017 16:40:43 +0100 Message-Id: <1488901251-16214-20-git-send-email-kwolf@redhat.com> In-Reply-To: <1488901251-16214-1-git-send-email-kwolf@redhat.com> References: <1488901251-16214-1-git-send-email-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Tue, 07 Mar 2017 15:41:28 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 19/27] sheepdog: Implement bdrv_parse_filename() 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: kwolf@redhat.com, qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Markus Armbruster This permits configuration with driver-specific options in addition to pseudo-filename parsed as URI. For instance, --drive driver=3Dsheepdog,host=3Dfido,vdi=3Ddolly instead of --drive driver=3Dsheepdog,file=3Dsheepdog://fido/dolly It's also a first step towards supporting blockdev-add. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/sheepdog.c | 230 +++++++++++++++++++++++++++++++++++++++++----------= ---- 1 file changed, 174 insertions(+), 56 deletions(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index 9b1e121..89e98ed 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -14,6 +14,8 @@ =20 #include "qemu/osdep.h" #include "qapi/error.h" +#include "qapi/qmp/qdict.h" +#include "qapi/qmp/qint.h" #include "qemu/uri.h" #include "qemu/error-report.h" #include "qemu/sockets.h" @@ -526,6 +528,25 @@ static void sd_aio_setup(SheepdogAIOCB *acb, BDRVSheep= dogState *s, QLIST_INSERT_HEAD(&s->inflight_aiocb_head, acb, aiocb_siblings); } =20 +static SocketAddress *sd_socket_address(const char *path, + const char *host, const char *port) +{ + SocketAddress *addr =3D g_new0(SocketAddress, 1); + + if (path) { + addr->type =3D SOCKET_ADDRESS_KIND_UNIX; + addr->u.q_unix.data =3D g_new0(UnixSocketAddress, 1); + addr->u.q_unix.data->path =3D g_strdup(path); + } else { + addr->type =3D SOCKET_ADDRESS_KIND_INET; + addr->u.inet.data =3D g_new0(InetSocketAddress, 1); + addr->u.inet.data->host =3D g_strdup(host ?: SD_DEFAULT_ADDR); + addr->u.inet.data->port =3D g_strdup(port ?: stringify(SD_DEFAULT_= PORT)); + } + + return addr; +} + /* Return -EIO in case of error, file descriptor on success */ static int connect_to_sdog(BDRVSheepdogState *s, Error **errp) { @@ -951,17 +972,37 @@ static bool sd_parse_snapid_or_tag(const char *str, return true; } =20 -static void sd_parse_uri(BDRVSheepdogState *s, const char *filename, - char *vdi, uint32_t *snapid, char *tag, +typedef struct { + const char *path; /* non-null iff transport is tcp */ + const char *host; /* valid when transport is tcp */ + int port; /* valid when transport is tcp */ + char vdi[SD_MAX_VDI_LEN]; + char tag[SD_MAX_VDI_TAG_LEN]; + uint32_t snap_id; + /* Remainder is only for sd_config_done() */ + URI *uri; + QueryParams *qp; +} SheepdogConfig; + +static void sd_config_done(SheepdogConfig *cfg) +{ + if (cfg->qp) { + query_params_free(cfg->qp); + } + uri_free(cfg->uri); +} + +static void sd_parse_uri(SheepdogConfig *cfg, const char *filename, Error **errp) { Error *err =3D NULL; QueryParams *qp =3D NULL; - SocketAddress *addr =3D NULL; bool is_unix; URI *uri; =20 - uri =3D uri_parse(filename); + memset(cfg, 0, sizeof(*cfg)); + + cfg->uri =3D uri =3D uri_parse(filename); if (!uri) { error_setg(&err, "invalid URI"); goto out; @@ -984,13 +1025,13 @@ static void sd_parse_uri(BDRVSheepdogState *s, const= char *filename, error_setg(&err, "missing file path in URI"); goto out; } - if (g_strlcpy(vdi, uri->path + 1, SD_MAX_VDI_LEN) >=3D SD_MAX_VDI_LEN)= { + if (g_strlcpy(cfg->vdi, uri->path + 1, SD_MAX_VDI_LEN) + >=3D SD_MAX_VDI_LEN) { error_setg(&err, "VDI name is too long"); goto out; } =20 - qp =3D query_params_parse(uri->query); - addr =3D g_new0(SocketAddress, 1); + cfg->qp =3D qp =3D query_params_parse(uri->query); =20 if (is_unix) { /* sheepdog+unix:///vdiname?socket=3Dpath */ @@ -1009,44 +1050,34 @@ static void sd_parse_uri(BDRVSheepdogState *s, cons= t char *filename, error_setg(&err, "unexpected query parameters"); goto out; } - addr->type =3D SOCKET_ADDRESS_KIND_UNIX; - addr->u.q_unix.data =3D g_new0(UnixSocketAddress, 1); - addr->u.q_unix.data->path =3D g_strdup(qp->p[0].value); + cfg->path =3D qp->p[0].value; } else { /* sheepdog[+tcp]://[host:port]/vdiname */ if (qp->n) { error_setg(&err, "unexpected query parameters"); goto out; } - addr->type =3D SOCKET_ADDRESS_KIND_INET; - addr->u.inet.data =3D g_new0(InetSocketAddress, 1); - addr->u.inet.data->host =3D g_strdup(uri->server ?: SD_DEFAULT_ADD= R); - addr->u.inet.data->port =3D g_strdup_printf("%d", - uri->port ?: SD_DEFAULT_PORT); + cfg->host =3D uri->server; + cfg->port =3D uri->port; } =20 /* snapshot tag */ if (uri->fragment) { - if (!sd_parse_snapid_or_tag(uri->fragment, snapid, tag)) { + if (!sd_parse_snapid_or_tag(uri->fragment, + &cfg->snap_id, cfg->tag)) { error_setg(&err, "'%s' is not a valid snapshot ID", uri->fragment); goto out; } } else { - *snapid =3D CURRENT_VDI_ID; /* search current vdi */ + cfg->snap_id =3D CURRENT_VDI_ID; /* search current vdi */ } =20 out: if (err) { error_propagate(errp, err); - qapi_free_SocketAddress(addr); - } else { - s->addr =3D addr; - } - if (qp) { - query_params_free(qp); + sd_config_done(cfg); } - uri_free(uri); } =20 /* @@ -1066,8 +1097,7 @@ out: * You can run VMs outside the Sheepdog cluster by specifying * `hostname' and `port' (experimental). */ -static void parse_vdiname(BDRVSheepdogState *s, const char *filename, - char *vdi, uint32_t *snapid, char *tag, +static void parse_vdiname(SheepdogConfig *cfg, const char *filename, Error **errp) { Error *err =3D NULL; @@ -1112,7 +1142,7 @@ static void parse_vdiname(BDRVSheepdogState *s, const= char *filename, * FIXME We to escape URI meta-characters, e.g. "x?y=3Dz" * produces "sheepdog://x?y=3Dz". Because of that ... */ - sd_parse_uri(s, uri, vdi, snapid, tag, &err); + sd_parse_uri(cfg, uri, &err); if (err) { /* * ... this can fail, but the error message is misleading. @@ -1127,6 +1157,43 @@ static void parse_vdiname(BDRVSheepdogState *s, cons= t char *filename, g_free(uri); } =20 +static void sd_parse_filename(const char *filename, QDict *options, + Error **errp) +{ + Error *err =3D NULL; + SheepdogConfig cfg; + char buf[32]; + + if (strstr(filename, "://")) { + sd_parse_uri(&cfg, filename, &err); + } else { + parse_vdiname(&cfg, filename, &err); + } + if (err) { + error_propagate(errp, err); + return; + } + + if (cfg.host) { + qdict_set_default_str(options, "host", cfg.host); + } + if (cfg.port) { + snprintf(buf, sizeof(buf), "%d", cfg.port); + qdict_set_default_str(options, "port", buf); + } + if (cfg.path) { + qdict_set_default_str(options, "path", cfg.path); + } + qdict_set_default_str(options, "vdi", cfg.vdi); + qdict_set_default_str(options, "tag", cfg.tag); + if (cfg.snap_id) { + snprintf(buf, sizeof(buf), "%d", cfg.snap_id); + qdict_set_default_str(options, "snap-id", buf); + } + + sd_config_done(&cfg); +} + static int find_vdi_name(BDRVSheepdogState *s, const char *filename, uint32_t snapid, const char *tag, uint32_t *vid, bool lock, Error **errp) @@ -1438,15 +1505,33 @@ static void sd_attach_aio_context(BlockDriverState = *bs, co_read_response, NULL, NULL, s); } =20 -/* TODO Convert to fine grained options */ static QemuOptsList runtime_opts =3D { .name =3D "sheepdog", .head =3D QTAILQ_HEAD_INITIALIZER(runtime_opts.head), .desc =3D { { - .name =3D "filename", + .name =3D "host", + .type =3D QEMU_OPT_STRING, + }, + { + .name =3D "port", + .type =3D QEMU_OPT_STRING, + }, + { + .name =3D "path", + .type =3D QEMU_OPT_STRING, + }, + { + .name =3D "vdi", + .type =3D QEMU_OPT_STRING, + }, + { + .name =3D "snap-id", + .type =3D QEMU_OPT_NUMBER, + }, + { + .name =3D "tag", .type =3D QEMU_OPT_STRING, - .help =3D "URL to the sheepdog image", }, { /* end of list */ } }, @@ -1458,12 +1543,11 @@ static int sd_open(BlockDriverState *bs, QDict *opt= ions, int flags, int ret, fd; uint32_t vid =3D 0; BDRVSheepdogState *s =3D bs->opaque; - char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN]; - uint32_t snapid; + const char *host, *port, *path, *vdi, *snap_id_str, *tag; + uint64_t snap_id; char *buf =3D NULL; QemuOpts *opts; Error *local_err =3D NULL; - const char *filename; =20 s->bs =3D bs; s->aio_context =3D bdrv_get_aio_context(bs); @@ -1476,33 +1560,63 @@ static int sd_open(BlockDriverState *bs, QDict *opt= ions, int flags, goto err_no_fd; } =20 - filename =3D qemu_opt_get(opts, "filename"); + host =3D qemu_opt_get(opts, "host"); + port =3D qemu_opt_get(opts, "port"); + path =3D qemu_opt_get(opts, "path"); + vdi =3D qemu_opt_get(opts, "vdi"); + snap_id_str =3D qemu_opt_get(opts, "snap-id"); + snap_id =3D qemu_opt_get_number(opts, "snap-id", CURRENT_VDI_ID); + tag =3D qemu_opt_get(opts, "tag"); =20 - QLIST_INIT(&s->inflight_aio_head); - QLIST_INIT(&s->failed_aio_head); - QLIST_INIT(&s->inflight_aiocb_head); - s->fd =3D -1; + if ((host || port) && path) { + error_setg(errp, "can't use 'path' together with 'host' or 'port'"= ); + ret =3D -EINVAL; + goto err_no_fd; + } + + if (!vdi) { + error_setg(errp, "parameter 'vdi' is missing"); + ret =3D -EINVAL; + goto err_no_fd; + } + if (strlen(vdi) >=3D SD_MAX_VDI_LEN) { + error_setg(errp, "value of parameter 'vdi' is too long"); + ret =3D -EINVAL; + goto err_no_fd; + } =20 - memset(vdi, 0, sizeof(vdi)); - memset(tag, 0, sizeof(tag)); + if (snap_id > UINT32_MAX) { + snap_id =3D 0; + } + if (snap_id_str && !snap_id) { + error_setg(errp, "'snap-id=3D%s' is not a valid snapshot ID", + snap_id_str); + ret =3D -EINVAL; + goto err_no_fd; + } =20 - if (strstr(filename, "://")) { - sd_parse_uri(s, filename, vdi, &snapid, tag, &local_err); - } else { - parse_vdiname(s, filename, vdi, &snapid, tag, &local_err); + if (!tag) { + tag =3D ""; } - if (local_err) { - error_propagate(errp, local_err); + if (tag && strlen(tag) >=3D SD_MAX_VDI_TAG_LEN) { + error_setg(errp, "value of parameter 'tag' is too long"); ret =3D -EINVAL; goto err_no_fd; } + + s->addr =3D sd_socket_address(path, host, port); + + QLIST_INIT(&s->inflight_aio_head); + QLIST_INIT(&s->failed_aio_head); + QLIST_INIT(&s->inflight_aiocb_head); + s->fd =3D get_sheep_fd(s, errp); if (s->fd < 0) { ret =3D s->fd; goto err_no_fd; } =20 - ret =3D find_vdi_name(s, vdi, snapid, tag, &vid, true, errp); + ret =3D find_vdi_name(s, vdi, (uint32_t)snap_id, tag, &vid, true, errp= ); if (ret) { goto err; } @@ -1517,7 +1631,7 @@ static int sd_open(BlockDriverState *bs, QDict *optio= ns, int flags, } s->discard_supported =3D true; =20 - if (snapid || tag[0] !=3D '\0') { + if (snap_id || tag[0]) { DPRINTF("%" PRIx32 " snapshot inode was open.\n", vid); s->is_snapshot =3D true; } @@ -1827,24 +1941,28 @@ static int sd_create(const char *filename, QemuOpts= *opts, char *backing_file =3D NULL; char *buf =3D NULL; BDRVSheepdogState *s; - char tag[SD_MAX_VDI_TAG_LEN]; - uint32_t snapid; + SheepdogConfig cfg; uint64_t max_vdi_size; bool prealloc =3D false; =20 s =3D g_new0(BDRVSheepdogState, 1); =20 - memset(tag, 0, sizeof(tag)); if (strstr(filename, "://")) { - sd_parse_uri(s, filename, s->name, &snapid, tag, &err); + sd_parse_uri(&cfg, filename, &err); } else { - parse_vdiname(s, filename, s->name, &snapid, tag, &err); + parse_vdiname(&cfg, filename, &err); } if (err) { error_propagate(errp, err); goto out; } =20 + buf =3D cfg.port ? g_strdup_printf("%d", cfg.port) : NULL; + s->addr =3D sd_socket_address(cfg.path, cfg.host, buf); + g_free(buf); + strcpy(s->name, cfg.vdi); + sd_config_done(&cfg); + s->inode.vdi_size =3D ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_S= IZE, 0), BDRV_SECTOR_SIZE); backing_file =3D qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); @@ -2921,7 +3039,7 @@ static BlockDriver bdrv_sheepdog =3D { .format_name =3D "sheepdog", .protocol_name =3D "sheepdog", .instance_size =3D sizeof(BDRVSheepdogState), - .bdrv_needs_filename =3D true, + .bdrv_parse_filename =3D sd_parse_filename, .bdrv_file_open =3D sd_open, .bdrv_reopen_prepare =3D sd_reopen_prepare, .bdrv_reopen_commit =3D sd_reopen_commit, @@ -2957,7 +3075,7 @@ static BlockDriver bdrv_sheepdog_tcp =3D { .format_name =3D "sheepdog", .protocol_name =3D "sheepdog+tcp", .instance_size =3D sizeof(BDRVSheepdogState), - .bdrv_needs_filename =3D true, + .bdrv_parse_filename =3D sd_parse_filename, .bdrv_file_open =3D sd_open, .bdrv_reopen_prepare =3D sd_reopen_prepare, .bdrv_reopen_commit =3D sd_reopen_commit, @@ -2993,7 +3111,7 @@ static BlockDriver bdrv_sheepdog_unix =3D { .format_name =3D "sheepdog", .protocol_name =3D "sheepdog+unix", .instance_size =3D sizeof(BDRVSheepdogState), - .bdrv_needs_filename =3D true, + .bdrv_parse_filename =3D sd_parse_filename, .bdrv_file_open =3D sd_open, .bdrv_reopen_prepare =3D sd_reopen_prepare, .bdrv_reopen_commit =3D sd_reopen_commit, --=20 1.8.3.1