From patchwork Tue Apr 12 13:41:13 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Richard W.M. Jones" X-Patchwork-Id: 8810641 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 3F3169F54F for ; Tue, 12 Apr 2016 13:42:06 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 1B7F620357 for ; Tue, 12 Apr 2016 13:42:01 +0000 (UTC) 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.kernel.org (Postfix) with ESMTPS id E16F420270 for ; Tue, 12 Apr 2016 13:41:59 +0000 (UTC) Received: from localhost ([::1]:49815 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1apyZr-00019e-AL for patchwork-qemu-devel@patchwork.kernel.org; Tue, 12 Apr 2016 09:41:59 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:48848) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1apyZX-0000o8-Ed for qemu-devel@nongnu.org; Tue, 12 Apr 2016 09:41:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1apyZS-0001BY-Ll for qemu-devel@nongnu.org; Tue, 12 Apr 2016 09:41:39 -0400 Received: from mx1.redhat.com ([209.132.183.28]:40568) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1apyZK-00018m-8Y; Tue, 12 Apr 2016 09:41:26 -0400 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) (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 DAC4C3D7; Tue, 12 Apr 2016 13:41:25 +0000 (UTC) Received: from moo.home.annexia.org (ovpn-204-22.brq.redhat.com [10.40.204.22]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u3CDfLs8012021; Tue, 12 Apr 2016 09:41:24 -0400 From: "Richard W.M. Jones" To: kwolf@redhat.com Date: Tue, 12 Apr 2016 14:41:13 +0100 Message-Id: <1460468474-29812-2-git-send-email-rjones@redhat.com> In-Reply-To: <1460468474-29812-1-git-send-email-rjones@redhat.com> References: <1460468474-29812-1-git-send-email-rjones@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 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 v2 REPOST 1/2] 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: famz@redhat.com, qemu-devel@nongnu.org, qemu-block@nongnu.org, den-lists@parallels.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Marc MarĂ­ 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Ă­ --- block.c | 70 +++++++++++++++++++++++++++++++++++ configure | 2 +- include/qemu/module.h | 3 ++ include/qemu/module_block.h | 90 +++++++++++++++++++++++++++++++++++++++++++++ util/module.c | 38 ++++++------------- 5 files changed, 175 insertions(+), 28 deletions(-) create mode 100644 include/qemu/module_block.h diff --git a/block.c b/block.c index d4939b4..ccd9e57 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" @@ -252,11 +253,30 @@ 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; } @@ -457,8 +477,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); @@ -480,6 +507,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 */ @@ -506,6 +534,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)) { @@ -513,6 +542,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; } @@ -535,8 +581,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); @@ -2794,6 +2847,7 @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name), BlockDriver *drv; int count = 0; int i; + size_t n; const char **formats = NULL; QLIST_FOREACH(drv, &bdrv_drivers, list) { @@ -2811,6 +2865,22 @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name), } } + for (n = 0; n < ARRAY_SIZE(block_driver_modules); ++n) { + if (block_driver_modules[n].format_name) { + bool found = false; + int i = count; + while (formats && i && !found) { + found = !strcmp(formats[--i], + block_driver_modules[n].format_name); + } + + if (!found) { + formats = g_renew(const char *, formats, count + 1); + formats[count++] = block_driver_modules[n].format_name; + } + } + } + qsort(formats, count, sizeof(formats[0]), qsort_strcmp); for (i = 0; i < count; i++) { diff --git a/configure b/configure index 5db29f0..725d576 100755 --- a/configure +++ b/configure @@ -5261,7 +5261,7 @@ if test "$bzip2" = "yes" ; then fi if test "$libiscsi" = "yes" ; then - echo "CONFIG_LIBISCSI=m" >> $config_host_mak + echo "CONFIG_LIBISCSI=y" >> $config_host_mak echo "LIBISCSI_CFLAGS=$libiscsi_cflags" >> $config_host_mak echo "LIBISCSI_LIBS=$libiscsi_libs" >> $config_host_mak fi 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/include/qemu/module_block.h b/include/qemu/module_block.h new file mode 100644 index 0000000..d725db8 --- /dev/null +++ b/include/qemu/module_block.h @@ -0,0 +1,90 @@ +/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ +/* + * QEMU Block Module Infrastructure + * + * Copyright Red Hat, Inc. 2015 + * + * Authors: + * Marc Mari + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_MODULE_BLOCK_H +#define QEMU_MODULE_BLOCK_H + +#include "qemu-common.h" + +static const struct { + const char *format_name; + const char *protocol_name; + const char *library_name; + bool has_probe; + bool has_probe_device; +} block_driver_modules[] = { + { + .library_name = "curl", + .format_name = "http", + .protocol_name = "http", + }, + { + .library_name = "curl", + .format_name = "https", + .protocol_name = "https", + }, + { + .library_name = "curl", + .format_name = "ftp", + .protocol_name = "ftp", + }, + { + .library_name = "curl", + .format_name = "ftps", + .protocol_name = "ftps", + }, + { + .library_name = "curl", + .format_name = "tftp", + .protocol_name = "tftp", + }, + { + .library_name = "rbd", + .format_name = "rbd", + .protocol_name = "rbd", + }, + { + .library_name = "gluster", + .format_name = "gluster", + .protocol_name = "gluster", + }, + { + .library_name = "gluster", + .format_name = "gluster", + .protocol_name = "gluster+tcp", + }, + { + .library_name = "gluster", + .format_name = "gluster", + .protocol_name = "gluster+unix", + }, + { + .library_name = "gluster", + .format_name = "gluster", + .protocol_name = "gluster+rdma", + }, + { + .library_name = "ssh", + .format_name = "ssh", + .protocol_name = "ssh", + }, + { + .library_name = "dmg", + .format_name = "dmg", + .has_probe = true, + }, +}; + +#endif + diff --git a/util/module.c b/util/module.c index ce058ae..8ff1340 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) { @@ -149,6 +146,7 @@ static int module_load_file(const char *fname) ret = -EINVAL; } else { QTAILQ_FOREACH(e, &dso_init_list, node) { + e->init(); register_module_init(e->init, e->type); } ret = 0; @@ -163,14 +161,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 +175,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 +183,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; } }