From patchwork Thu Jul 14 19:02:59 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: 648540 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3rr4yd0rn0z9sC4 for ; Fri, 15 Jul 2016 05:10:01 +1000 (AEST) Received: from localhost ([::1]:56299 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bNm1G-0002u2-LP for incoming@patchwork.ozlabs.org; Thu, 14 Jul 2016 15:09:58 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:60225) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bNlvA-0003gE-Uk for qemu-devel@nongnu.org; Thu, 14 Jul 2016 15:03:42 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bNlv9-0002db-1w for qemu-devel@nongnu.org; Thu, 14 Jul 2016 15:03:40 -0400 Received: from mx1.redhat.com ([209.132.183.28]:53335) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bNlv3-0002aF-DZ; Thu, 14 Jul 2016 15:03:33 -0400 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (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 063C8C05AA40; Thu, 14 Jul 2016 19:03:33 +0000 (UTC) Received: from dhcp-17-138.bos.redhat.com (dhcp-17-130.bos.redhat.com [10.18.17.130]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u6EJ3T8Q000405; Thu, 14 Jul 2016 15:03:32 -0400 From: Colin Lord To: qemu-devel@nongnu.org Date: Thu, 14 Jul 2016 15:02:59 -0400 Message-Id: <1468523008-30013-4-git-send-email-clord@redhat.com> In-Reply-To: <1468523008-30013-1-git-send-email-clord@redhat.com> References: <1468523008-30013-1-git-send-email-clord@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Thu, 14 Jul 2016 19:03:33 +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 v4 03/32] 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, Marc Mari , Colin Lord , qemu-block@nongnu.org, mreitz@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" 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. All the necessary module information is located in a new structure found in module_block.h Signed-off-by: Marc MarĂ­ Signed-off-by: Colin Lord Reviewed-by: Max Reitz --- block.c | 110 ++++++++++++++++++++++++++++++++++++++++++-------- include/qemu/module.h | 3 ++ util/module.c | 38 +++++------------ 3 files changed, 108 insertions(+), 43 deletions(-) diff --git a/block.c b/block.c index 823ff1d..3a0dc19 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 "module_block.h" #include "qemu/module.h" #include "qapi/qmp/qerror.h" #include "qapi/qmp/qbool.h" @@ -239,17 +240,40 @@ BlockDriverState *bdrv_new(void) return bs; } -BlockDriver *bdrv_find_format(const char *format_name) +static BlockDriver *bdrv_do_find_format(const char *format_name) { BlockDriver *drv1; + QLIST_FOREACH(drv1, &bdrv_drivers, list) { if (!strcmp(drv1->format_name, format_name)) { return drv1; } } + return NULL; } +BlockDriver *bdrv_find_format(const char *format_name) +{ + BlockDriver *drv1; + size_t i; + + drv1 = bdrv_do_find_format(format_name); + if (drv1) { + return drv1; + } + + /* The driver isn't registered, maybe we need to load a module */ + 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); + break; + } + } + + return bdrv_do_find_format(format_name); +} + static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only) { static const char *whitelist_rw[] = { @@ -443,8 +467,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); @@ -458,6 +489,19 @@ static BlockDriver *find_hdev_driver(const char *filename) return drv; } +static BlockDriver *bdrv_do_find_protocol(const char *protocol) +{ + BlockDriver *drv1; + + QLIST_FOREACH(drv1, &bdrv_drivers, list) { + if (drv1->protocol_name && !strcmp(drv1->protocol_name, protocol)) { + return drv1; + } + } + + return NULL; +} + BlockDriver *bdrv_find_protocol(const char *filename, bool allow_protocol_prefix, Error **errp) @@ -466,6 +510,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 */ @@ -492,15 +537,25 @@ 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)) { - return drv1; + + drv1 = bdrv_do_find_protocol(protocol); + if (drv1) { + return drv1; + } + + 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); + break; } } - error_setg(errp, "Unknown protocol '%s'", protocol); - return NULL; + drv1 = bdrv_do_find_protocol(protocol); + if (!drv1) { + error_setg(errp, "Unknown protocol '%s'", protocol); + } + return drv1; } /* @@ -521,8 +576,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); @@ -2628,26 +2690,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; + } + } + + formats = g_renew(const char *, formats, *count + 1); + formats[*count] = format_name; + *count += 1; + 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..dc2c9d4 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 86e3f7a..a5f7fbd 100644 --- a/util/module.c +++ b/util/module.c @@ -87,14 +87,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) { @@ -145,6 +142,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; @@ -159,14 +157,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; @@ -177,15 +171,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 ? : ""); @@ -194,16 +179,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; } }