From nobody Mon Feb 9 07:55:46 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 1490691622880596.2596999082755; Tue, 28 Mar 2017 02:00:22 -0700 (PDT) Received: from localhost ([::1]:51699 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1csmzF-0003XJ-NK for importer@patchew.org; Tue, 28 Mar 2017 05:00:21 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39948) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1csmvM-0000F5-HH for qemu-devel@nongnu.org; Tue, 28 Mar 2017 04:56:21 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1csmvL-0008QO-6T for qemu-devel@nongnu.org; Tue, 28 Mar 2017 04:56:20 -0400 Received: from mx1.redhat.com ([209.132.183.28]:46266) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1csmvF-0008It-Ee; Tue, 28 Mar 2017 04:56:13 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 5E7DCC065107; Tue, 28 Mar 2017 08:56:12 +0000 (UTC) Received: from blackfin.pond.sub.org (ovpn-116-26.ams2.redhat.com [10.36.116.26]) by smtp.corp.redhat.com (Postfix) with ESMTPS id EFE0C17D53; Tue, 28 Mar 2017 08:56:11 +0000 (UTC) Received: by blackfin.pond.sub.org (Postfix, from userid 1000) id 49F41113860E; Tue, 28 Mar 2017 10:56:08 +0200 (CEST) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 5E7DCC065107 Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=armbru@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 5E7DCC065107 From: Markus Armbruster To: qemu-devel@nongnu.org Date: Tue, 28 Mar 2017 10:56:08 +0200 Message-Id: <1490691368-32099-11-git-send-email-armbru@redhat.com> In-Reply-To: <1490691368-32099-1-git-send-email-armbru@redhat.com> References: <1490691368-32099-1-git-send-email-armbru@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Tue, 28 Mar 2017 08:56:12 +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] [PATCH v4 for-2.9 10/10] rbd: Fix bugs around -drive parameter "server" 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, jdurgin@redhat.com, qemu-block@nongnu.org, jcody@redhat.com, mreitz@redhat.com 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" qemu_rbd_open() takes option parameters as a flattened QDict, with keys of the form server.%d.host, server.%d.port, where %d counts up from zero. qemu_rbd_array_opts() extracts these values as follows. First, it calls qdict_array_entries() to find the list's length. For each list element, it formats the list's key prefix (e.g. "server.0."), then creates a new QDict holding the options with that key prefix, then converts that to a QemuOpts, so it can finally get the member values from there. If there's one surefire way to make code using QDict more awkward, it's creating more of them and mixing in QemuOpts for good measure. The extraction of keys starting with server.%d into another QDict makes us ignore parameters like server.0.neither-host-nor-port silently. The conversion to QemuOpts abuses runtime_opts, as described a few commits ago. Rewrite to simply get the values straight from the options QDict. Fixes -drive not to crash when server.*.* are present, but server.*.host is absent. Fixes -drive to reject invalid server.*.*. Permits cleaning up runtime_opts. Do that, and fix -drive to reject bogus parameters host and port instead of silently ignoring them. Signed-off-by: Markus Armbruster Reviewed-by: Eric Blake --- block/rbd.c | 127 +++++++++++++++-----------------------------------------= ---- 1 file changed, 32 insertions(+), 95 deletions(-) diff --git a/block/rbd.c b/block/rbd.c index 485cef4..498322b 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -13,6 +13,7 @@ =20 #include "qemu/osdep.h" =20 +#include #include "qapi/error.h" #include "qemu/error-report.h" #include "block/block_int.h" @@ -20,8 +21,6 @@ #include "qemu/cutils.h" #include "qapi/qmp/qstring.h" =20 -#include - /* * When specifying the image filename use: * @@ -320,7 +319,7 @@ static QemuOptsList runtime_opts =3D { .help =3D "Rados id name", }, /* - * server.* extracted manually, see qemu_rbd_array_opts() + * server.* extracted manually, see qemu_rbd_mon_host() */ { .name =3D "password-secret", @@ -340,21 +339,6 @@ static QemuOptsList runtime_opts =3D { .type =3D QEMU_OPT_STRING, .help =3D "Legacy rados key/value option parameters", }, - - /* - * The remainder aren't option keys, but option sub-sub-keys, - * so that qemu_rbd_array_opts() can abuse runtime_opts for - * its own purposes - * TODO clean this up - */ - { - .name =3D "host", - .type =3D QEMU_OPT_STRING, - }, - { - .name =3D "port", - .type =3D QEMU_OPT_STRING, - }, { /* end of list */ } }, }; @@ -505,89 +489,43 @@ static void qemu_rbd_complete_aio(RADOSCB *rcb) qemu_aio_unref(acb); } =20 -#define RBD_MON_HOST 0 - -static char *qemu_rbd_array_opts(QDict *options, const char *prefix, int t= ype, - Error **errp) +static char *qemu_rbd_mon_host(QDict *options, Error **errp) { - int num_entries; - QemuOpts *opts =3D NULL; - QDict *sub_options; - const char *host; - const char *port; - char *str; - char *rados_str =3D NULL; - Error *local_err =3D NULL; + const char **vals =3D g_new(const char *, qdict_size(options) + 1); + char keybuf[32]; + const char *host, *port; + char *rados_str; int i; =20 - assert(type =3D=3D RBD_MON_HOST); - - num_entries =3D qdict_array_entries(options, prefix); - - if (num_entries < 0) { - error_setg(errp, "Parse error on RBD QDict array"); - return NULL; - } - - for (i =3D 0; i < num_entries; i++) { - char *strbuf =3D NULL; - const char *value; - char *rados_str_tmp; - - str =3D g_strdup_printf("%s%d.", prefix, i); - qdict_extract_subqdict(options, &sub_options, str); - g_free(str); - - opts =3D qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, sub_options, &local_err); - QDECREF(sub_options); - if (local_err) { - error_propagate(errp, local_err); - g_free(rados_str); + for (i =3D 0;; i++) { + sprintf(keybuf, "server.%d.host", i); + host =3D qdict_get_try_str(options, keybuf); + qdict_del(options, keybuf); + sprintf(keybuf, "server.%d.port", i); + port =3D qdict_get_try_str(options, keybuf); + qdict_del(options, keybuf); + if (!host && !port) { + break; + } + if (!host) { + error_setg(errp, "Parameter server.%d.host is missing", i); rados_str =3D NULL; - goto exit; + goto out; } =20 - if (type =3D=3D RBD_MON_HOST) { - host =3D qemu_opt_get(opts, "host"); - port =3D qemu_opt_get(opts, "port"); - - value =3D host; - if (port) { - /* check for ipv6 */ - if (strchr(host, ':')) { - strbuf =3D g_strdup_printf("[%s]:%s", host, port); - } else { - strbuf =3D g_strdup_printf("%s:%s", host, port); - } - value =3D strbuf; - } else if (strchr(host, ':')) { - strbuf =3D g_strdup_printf("[%s]", host); - value =3D strbuf; - } + if (strchr(host, ':')) { + vals[i] =3D port ? g_strdup_printf("[%s]:%s", host, port) + : g_strdup_printf("[%s]", host); } else { - abort(); + vals[i] =3D port ? g_strdup_printf("%s:%s", host, port) + : g_strdup(host); } - - /* each iteration in the for loop will build upon the string, and = if - * rados_str is NULL then it is our first pass */ - if (rados_str) { - /* separate options with ';', as that is what rados_conf_set() - * requires */ - rados_str_tmp =3D rados_str; - rados_str =3D g_strdup_printf("%s;%s", rados_str_tmp, value); - g_free(rados_str_tmp); - } else { - rados_str =3D g_strdup(value); - } - - g_free(strbuf); - qemu_opts_del(opts); - opts =3D NULL; } + vals[i] =3D NULL; =20 -exit: - qemu_opts_del(opts); + rados_str =3D i ? g_strjoinv(";", (char **)vals) : NULL; +out: + g_strfreev((char **)vals); return rados_str; } =20 @@ -606,12 +544,11 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict = *options, int flags, qemu_opts_absorb_qdict(opts, options, &local_err); if (local_err) { error_propagate(errp, local_err); - qemu_opts_del(opts); - return -EINVAL; + r =3D -EINVAL; + goto failed_opts; } =20 - mon_host =3D qemu_rbd_array_opts(options, "server.", - RBD_MON_HOST, &local_err); + mon_host =3D qemu_rbd_mon_host(options, &local_err); if (local_err) { error_propagate(errp, local_err); r =3D -EINVAL; --=20 2.7.4