From patchwork Wed Jun 15 18:40:55 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: clord@redhat.com X-Patchwork-Id: 9179167 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 6B81A604DB for ; Wed, 15 Jun 2016 18:49:55 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 580EF20223 for ; Wed, 15 Jun 2016 18:49:55 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4B4A627DF9; Wed, 15 Jun 2016 18:49:55 +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.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI 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 83B6120223 for ; Wed, 15 Jun 2016 18:49:54 +0000 (UTC) Received: from localhost ([::1]:44428 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bDFsv-000706-Gz for patchwork-qemu-devel@patchwork.kernel.org; Wed, 15 Jun 2016 14:49:53 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53583) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bDFpH-00049P-QU for qemu-devel@nongnu.org; Wed, 15 Jun 2016 14:46:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bDFpG-00040E-3N for qemu-devel@nongnu.org; Wed, 15 Jun 2016 14:46:07 -0400 Received: from mx1.redhat.com ([209.132.183.28]:46197) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bDFp8-0003yl-R0; Wed, 15 Jun 2016 14:45:59 -0400 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 1EA9B486B3; Wed, 15 Jun 2016 18:45:58 +0000 (UTC) Received: from dhcp-17-138.bos.redhat.com (dhcp-17-189.bos.redhat.com [10.18.17.189]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u5FIeueb005872; Wed, 15 Jun 2016 14:45:57 -0400 From: Colin Lord To: qemu-devel@nongnu.org Date: Wed, 15 Jun 2016 14:40:55 -0400 Message-Id: <1466016055-31351-3-git-send-email-clord@redhat.com> In-Reply-To: <1466016055-31351-1-git-send-email-clord@redhat.com> References: <1466016055-31351-1-git-send-email-clord@redhat.com> MIME-Version: 1.0 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.30]); Wed, 15 Jun 2016 18:45:58 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH 2/2] blockdev: Add dynamic module loading for block drivers 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, markmb@redhat.com, Colin Lord , qemu-block@nongnu.org, 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 From: Marc Mari Extend the current module interface to allow for block drivers to be loaded dynamically on request. The only block drivers that can be converted into modules are the drivers that don't perform any init operation except for registering themselves. This is why libiscsi has been disabled as a module. All the necessary module information is located in a new structure found in include/qemu/module_block.h Signed-off-by: Marc MarĂ­ Signed-off-by: Colin Lord --- Makefile | 3 -- block.c | 86 +++++++++++++++++++++++++++++++++++++++++++++------ include/qemu/module.h | 3 ++ util/module.c | 37 ++++++---------------- 4 files changed, 90 insertions(+), 39 deletions(-) diff --git a/Makefile b/Makefile index 8f8b6a2..461187c 100644 --- a/Makefile +++ b/Makefile @@ -247,9 +247,6 @@ Makefile: $(version-obj-y) $(version-lobj-y) libqemustub.a: $(stub-obj-y) libqemuutil.a: $(util-obj-y) -block-modules = $(foreach o,$(block-obj-m),"$(basename $(subst /,-,$o))",) NULL -util/module.o-cflags = -D'CONFIG_BLOCK_MODULES=$(block-modules)' - ###################################################################### qemu-img.o: qemu-img-cmds.h diff --git a/block.c b/block.c index f54bc25..7a91434 100644 --- a/block.c +++ b/block.c @@ -26,6 +26,7 @@ #include "block/block_int.h" #include "block/blockjob.h" #include "qemu/error-report.h" +#include "qemu/module_block.h" #include "qemu/module.h" #include "qapi/qmp/qerror.h" #include "qapi/qmp/qbool.h" @@ -242,11 +243,29 @@ BlockDriverState *bdrv_new(void) BlockDriver *bdrv_find_format(const char *format_name) { BlockDriver *drv1; + size_t i; + QLIST_FOREACH(drv1, &bdrv_drivers, list) { if (!strcmp(drv1->format_name, format_name)) { return drv1; } } + + for (i = 0; i < ARRAY_SIZE(block_driver_modules); ++i) { + if (!strcmp(block_driver_modules[i].format_name, format_name)) { + block_module_load_one(block_driver_modules[i].library_name); + /* Copying code is not nice, but this way the current discovery is + * not modified. Calling recursively could fail if the library + * has been deleted. + */ + QLIST_FOREACH(drv1, &bdrv_drivers, list) { + if (!strcmp(drv1->format_name, format_name)) { + return drv1; + } + } + } + } + return NULL; } @@ -447,8 +466,15 @@ int get_tmp_filename(char *filename, int size) static BlockDriver *find_hdev_driver(const char *filename) { int score_max = 0, score; + size_t i; BlockDriver *drv = NULL, *d; + for (i = 0; i < ARRAY_SIZE(block_driver_modules); ++i) { + if (block_driver_modules[i].has_probe_device) { + block_module_load_one(block_driver_modules[i].library_name); + } + } + QLIST_FOREACH(d, &bdrv_drivers, list) { if (d->bdrv_probe_device) { score = d->bdrv_probe_device(filename); @@ -470,6 +496,7 @@ BlockDriver *bdrv_find_protocol(const char *filename, char protocol[128]; int len; const char *p; + size_t i; /* TODO Drivers without bdrv_file_open must be specified explicitly */ @@ -496,6 +523,7 @@ BlockDriver *bdrv_find_protocol(const char *filename, len = sizeof(protocol) - 1; memcpy(protocol, filename, len); protocol[len] = '\0'; + QLIST_FOREACH(drv1, &bdrv_drivers, list) { if (drv1->protocol_name && !strcmp(drv1->protocol_name, protocol)) { @@ -503,6 +531,23 @@ BlockDriver *bdrv_find_protocol(const char *filename, } } + for (i = 0; i < ARRAY_SIZE(block_driver_modules); ++i) { + if (block_driver_modules[i].protocol_name && + !strcmp(block_driver_modules[i].protocol_name, protocol)) { + block_module_load_one(block_driver_modules[i].library_name); + /* Copying code is not nice, but this way the current discovery is + * not modified. Calling recursively could fail if the library + * has been deleted. + */ + QLIST_FOREACH(drv1, &bdrv_drivers, list) { + if (drv1->protocol_name && + !strcmp(drv1->protocol_name, protocol)) { + return drv1; + } + } + } + } + error_setg(errp, "Unknown protocol '%s'", protocol); return NULL; } @@ -525,8 +570,15 @@ BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size, const char *filename) { int score_max = 0, score; + size_t i; BlockDriver *drv = NULL, *d; + for (i = 0; i < ARRAY_SIZE(block_driver_modules); ++i) { + if (block_driver_modules[i].has_probe) { + block_module_load_one(block_driver_modules[i].library_name); + } + } + QLIST_FOREACH(d, &bdrv_drivers, list) { if (d->bdrv_probe) { score = d->bdrv_probe(buf, buf_size, filename); @@ -2738,26 +2790,42 @@ static int qsort_strcmp(const void *a, const void *b) return strcmp(a, b); } +static const char **add_format(const char **formats, int *count, + const char *format_name) +{ + int i; + + for (i = 0; i < *count; i++) { + if (!strcmp(formats[i], format_name)) { + return formats; + } + } + + *count += 1; + formats = g_renew(const char *, formats, *count); + formats[*count] = format_name; + return formats; +} + void bdrv_iterate_format(void (*it)(void *opaque, const char *name), void *opaque) { BlockDriver *drv; int count = 0; int i; + size_t n; const char **formats = NULL; QLIST_FOREACH(drv, &bdrv_drivers, list) { if (drv->format_name) { - bool found = false; - int i = count; - while (formats && i && !found) { - found = !strcmp(formats[--i], drv->format_name); - } + formats = add_format(formats, &count, drv->format_name); + } + } - if (!found) { - formats = g_renew(const char *, formats, count + 1); - formats[count++] = drv->format_name; - } + for (n = 0; n < ARRAY_SIZE(block_driver_modules); ++n) { + if (block_driver_modules[n].format_name) { + formats = add_format(formats, &count, + block_driver_modules[n].format_name); } } diff --git a/include/qemu/module.h b/include/qemu/module.h index 2370708..4729858 100644 --- a/include/qemu/module.h +++ b/include/qemu/module.h @@ -52,9 +52,12 @@ typedef enum { #define qapi_init(function) module_init(function, MODULE_INIT_QAPI) #define type_init(function) module_init(function, MODULE_INIT_QOM) +#define block_module_load_one(lib) module_load_one("block-", lib); + void register_module_init(void (*fn)(void), module_init_type type); void register_dso_module_init(void (*fn)(void), module_init_type type); void module_call_init(module_init_type type); +void module_load_one(const char *prefix, const char *lib_name); #endif diff --git a/util/module.c b/util/module.c index ce058ae..dbc6e52 100644 --- a/util/module.c +++ b/util/module.c @@ -91,14 +91,11 @@ void register_dso_module_init(void (*fn)(void), module_init_type type) QTAILQ_INSERT_TAIL(&dso_init_list, e, node); } -static void module_load(module_init_type type); - void module_call_init(module_init_type type) { ModuleTypeList *l; ModuleEntry *e; - module_load(type); l = find_type(type); QTAILQ_FOREACH(e, l, node) { @@ -163,14 +160,10 @@ out: } #endif -static void module_load(module_init_type type) +void module_load_one(const char *prefix, const char *lib_name) { #ifdef CONFIG_MODULES char *fname = NULL; - const char **mp; - static const char *block_modules[] = { - CONFIG_BLOCK_MODULES - }; char *exec_dir; char *dirs[3]; int i = 0; @@ -181,15 +174,6 @@ static void module_load(module_init_type type) return; } - switch (type) { - case MODULE_INIT_BLOCK: - mp = block_modules; - break; - default: - /* no other types have dynamic modules for now*/ - return; - } - exec_dir = qemu_get_exec_dir(); dirs[i++] = g_strdup_printf("%s", CONFIG_QEMU_MODDIR); dirs[i++] = g_strdup_printf("%s/..", exec_dir ? : ""); @@ -198,16 +182,15 @@ static void module_load(module_init_type type) g_free(exec_dir); exec_dir = NULL; - for ( ; *mp; mp++) { - for (i = 0; i < ARRAY_SIZE(dirs); i++) { - fname = g_strdup_printf("%s/%s%s", dirs[i], *mp, HOST_DSOSUF); - ret = module_load_file(fname); - g_free(fname); - fname = NULL; - /* Try loading until loaded a module file */ - if (!ret) { - break; - } + for (i = 0; i < ARRAY_SIZE(dirs); i++) { + fname = g_strdup_printf("%s/%s%s%s", + dirs[i], prefix, lib_name, HOST_DSOSUF); + ret = module_load_file(fname); + g_free(fname); + fname = NULL; + /* Try loading until loaded a module file */ + if (!ret) { + break; } }