qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 1/2] Add dynamic module loading for block driver


From: Daniel P. Berrange
Subject: Re: [Qemu-devel] [PATCH 1/2] Add dynamic module loading for block drivers
Date: Thu, 27 Aug 2015 10:19:35 +0100
User-agent: Mutt/1.5.23 (2014-03-12)

On Mon, Aug 17, 2015 at 10:09:34AM +0200, Marc Marí wrote:
> 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.

Seems like we would just need to split the iscsi opts registration out
into a separate file that is permanently linked.

> All the necessary module information is located in a new structure found in
> include/qemu/module_block.h
> 
> Signed-off-by: Marc Marí <address@hidden>
> ---
>  block.c                     | 73 +++++++++++++++++++++++++++++++++++--
>  configure                   |  2 +-
>  include/qemu/module.h       |  3 ++
>  include/qemu/module_block.h | 89 
> +++++++++++++++++++++++++++++++++++++++++++++
>  util/module.c               | 38 ++++++-------------
>  5 files changed, 174 insertions(+), 31 deletions(-)
>  create mode 100644 include/qemu/module_block.h
> 
> diff --git a/block.c b/block.c
> index d088ee0..f24a624 100644
> --- a/block.c
> +++ b/block.c
> @@ -27,6 +27,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/qjson.h"
> @@ -277,11 +278,30 @@ void bdrv_add_close_notifier(BlockDriverState *bs, 
> Notifier *notify)
>  BlockDriver *bdrv_find_format(const char *format_name)
>  {
>      BlockDriver *drv1;
> +    int i;

Nit-pick  'size_t' is a better type for loop iterators, especially
when combined with a sizeof() comparison. Some comment in later
functions too.

> +
>      QLIST_FOREACH(drv1, &bdrv_drivers, list) {
>          if (!strcmp(drv1->format_name, format_name)) {
>              return drv1;
>          }
>      }
> +
> +    for (i = 0; i < ARRAY_SIZE(block_driver_module); ++i) {
> +        if (!strcmp(block_driver_module[i].format_name, format_name)) {
> +            block_module_load_one(block_driver_module[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.
> +             */

Can you explaiin what you mean here about "if the library has been deleted" ?

Are you referring to possibilty of dlclose()ing the previously loaded
library, or about possibility of the module on disk having been deleted
or something else ?

> @@ -483,9 +503,15 @@ int get_tmp_filename(char *filename, int size)
>   */
>  static BlockDriver *find_hdev_driver(const char *filename)
>  {
> -    int score_max = 0, score;
> +    int score_max = 0, score, i;
>      BlockDriver *drv = NULL, *d;
>  
> +    for (i = 0; i < ARRAY_SIZE(block_driver_module); ++i) {
> +        if (block_driver_module[i].has_probe_device) {
> +            block_module_load_one(block_driver_module[i].library_name);
> +        }
> +    }

If we have multiuple disks of the same type given to QEMU, it
seems like we might end up calling block_module_load_one()
multiple times for the same module & end up loading the same
.so multiple times as a result. Should module_load() keep a
record of everything it has loaded and short-circuit itself
to a no-op, so that callers of module_load() don't have to
worry about avoiding multiple calls.

> +
>      QLIST_FOREACH(d, &bdrv_drivers, list) {
>          if (d->bdrv_probe_device) {
>              score = d->bdrv_probe_device(filename);
> @@ -507,6 +533,7 @@ BlockDriver *bdrv_find_protocol(const char *filename,
>      char protocol[128];
>      int len;
>      const char *p;
> +    int i;
>  
>      /* TODO Drivers without bdrv_file_open must be specified explicitly */
>  
> @@ -533,6 +560,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)) {
> @@ -540,6 +568,23 @@ BlockDriver *bdrv_find_protocol(const char *filename,
>          }
>      }
>  
> +    for (i = 0; i < ARRAY_SIZE(block_driver_module); ++i) {
> +        if (block_driver_module[i].protocol_name &&
> +            !strcmp(block_driver_module[i].protocol_name, protocol)) {
> +            block_module_load_one(block_driver_module[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;
>  }
> @@ -561,9 +606,15 @@ BlockDriver *bdrv_find_protocol(const char *filename,
>  BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
>                              const char *filename)
>  {
> -    int score_max = 0, score;
> +    int score_max = 0, score, i;
>      BlockDriver *drv = NULL, *d;
>  
> +    for (i = 0; i < ARRAY_SIZE(block_driver_module); ++i) {
> +        if (block_driver_module[i].has_probe) {
> +            block_module_load_one(block_driver_module[i].library_name);
> +        }
> +    }
> +
>      QLIST_FOREACH(d, &bdrv_drivers, list) {
>          if (d->bdrv_probe) {
>              score = d->bdrv_probe(buf, buf_size, filename);
> @@ -2783,7 +2834,7 @@ void bdrv_iterate_format(void (*it)(void *opaque, const 
> char *name),
>  {
>      BlockDriver *drv;
>      int count = 0;
> -    int i;
> +    int i, n;
>      const char **formats = NULL;
>  
>      QLIST_FOREACH(drv, &bdrv_drivers, list) {
> @@ -2801,6 +2852,22 @@ void bdrv_iterate_format(void (*it)(void *opaque, 
> const char *name),
>          }
>      }
>  
> +    for (n = 0; n < ARRAY_SIZE(block_driver_module); ++n) {
> +        if (block_driver_module[n].format_name) {
> +            bool found = false;
> +            int i = count;
> +            while (formats && i && !found) {
> +                found = !strcmp(formats[--i],
> +                                block_driver_module[n].format_name);
> +            }
> +
> +            if (!found) {
> +                formats = g_renew(const char *, formats, count + 1);
> +                formats[count++] = block_driver_module[n].format_name;
> +            }
> +        }
> +    }
> +
>      qsort(formats, count, sizeof(formats[0]), qsort_strcmp);
>  
>      for (i = 0; i < count; i++) {
> diff --git a/configure b/configure
> index cd219d8..9fca9ee 100755
> --- a/configure
> +++ b/configure
> @@ -4971,7 +4971,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 72d9498..0ad4bb7 100644
> --- a/include/qemu/module.h
> +++ b/include/qemu/module.h
> @@ -53,9 +53,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..f1d389c
> --- /dev/null
> +++ b/include/qemu/module_block.h
> @@ -0,0 +1,88 @@
> +/*
> + * QEMU Block Module Infrastructure
> + *
> + * Copyright Red Hat, Inc. 2015
> + *
> + * Authors:
> + *  Marc Mari       <address@hidden>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.  See
> + * the COPYING file in the top-level directory.
> + *
> + */

[snip]

> +
> +#endif
> \ No newline at end of file

Missing newline at end of file :-)

> diff --git a/util/module.c b/util/module.c
> index 4bd4a94..992d317 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) {

Isn't the entire of module_call_init() a no-op now that you removed
the module_load() call. IIUC, the find_type() method should return
an empty list at that point, so the rest of the method doesn't
nothing. IOW, I would think module_call_init() and its supporting
functions can be deleted now.

> @@ -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;
>          }
>      }
>  
> -- 
> 2.4.3
> 
> 

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|



reply via email to

[Prev in Thread] Current Thread [Next in Thread]