Blame packages/q/qemu/module-add-Error-arguments-to-module_loa.patch

Bernhard M. Wiedemann 399b1f
From: Claudio Fontana <cfontana@suse.de>
Bernhard M. Wiedemann 399b1f
Date: Thu, 29 Sep 2022 11:30:33 +0200
Bernhard M. Wiedemann 399b1f
Subject: module: add Error arguments to module_load and module_load_qom
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
improve error handling during module load, by changing:
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
bool module_load(const char *prefix, const char *lib_name);
Bernhard M. Wiedemann 399b1f
void module_load_qom(const char *type);
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
to:
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
int module_load(const char *prefix, const char *name, Error **errp);
Bernhard M. Wiedemann 399b1f
int module_load_qom(const char *type, Error **errp);
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
where the return value is:
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
 -1 on module load error, and errp is set with the error
Bernhard M. Wiedemann 399b1f
  0 on module or one of its dependencies are not installed
Bernhard M. Wiedemann 399b1f
  1 on module load success
Bernhard M. Wiedemann 399b1f
  2 on module load success (module already loaded or built-in)
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
module_load_qom_one has been introduced in:
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
commit 28457744c345 ("module: qom module support"), which built on top of
Bernhard M. Wiedemann 399b1f
module_load_one, but discarded the bool return value. Restore it.
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
Adapt all callers to emit errors, or ignore them, or fail hard,
Bernhard M. Wiedemann 399b1f
as appropriate in each context.
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
Replace the previous emission of errors via fprintf in _some_ error
Bernhard M. Wiedemann 399b1f
conditions with Error and error_report, so as to emit to the appropriate
Bernhard M. Wiedemann 399b1f
target.
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
A memory leak is also fixed as part of the module_load changes.
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
audio: when attempting to load an audio module, report module load errors.
Bernhard M. Wiedemann 399b1f
Note that still for some callers, a single issue may generate multiple
Bernhard M. Wiedemann 399b1f
error reports, and this could be improved further.
Bernhard M. Wiedemann 399b1f
Regarding the audio code itself, audio_add() seems to ignore errors,
Bernhard M. Wiedemann 399b1f
and this should probably be improved.
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
block: when attempting to load a block module, report module load errors.
Bernhard M. Wiedemann 399b1f
For the code paths that already use the Error API, take advantage of those
Bernhard M. Wiedemann 399b1f
to report module load errors into the Error parameter.
Bernhard M. Wiedemann 399b1f
For the other code paths, we currently emit the error, but this could be
Bernhard M. Wiedemann 399b1f
improved further by adding Error parameters to all possible code paths.
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
console: when attempting to load a display module, report module load errors.
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
qdev: when creating a new qdev Device object (DeviceState), report load errors.
Bernhard M. Wiedemann 399b1f
      If a module cannot be loaded to create that device, now abort execution
Bernhard M. Wiedemann 399b1f
      (if no CONFIG_MODULE) or exit (if CONFIG_MODULE).
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
qom/object.c: when initializing a QOM object, or looking up class_by_name,
Bernhard M. Wiedemann 399b1f
              report module load errors.
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
qtest: when processing the "module_load" qtest command, report errors
Bernhard M. Wiedemann 399b1f
       in the load of the module.
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
Signed-off-by: Claudio Fontana <cfontana@suse.de>
Bernhard M. Wiedemann 399b1f
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Bernhard M. Wiedemann 399b1f
Message-Id: <20220929093035.4231-4-cfontana@suse.de>
Bernhard M. Wiedemann 399b1f
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Bernhard M. Wiedemann 399b1f
(cherry picked from commit c551fb0b53db5d9a1f0116e8cce12f994605c9ea)
Bernhard M. Wiedemann 399b1f
Resolves: bsc#1208139
Bernhard M. Wiedemann 399b1f
Signed-off-by: Dario Faggioli <dfaggioli@suse.com>
Bernhard M. Wiedemann 399b1f
---
Bernhard M. Wiedemann 399b1f
 audio/audio.c         |  16 ++--
Bernhard M. Wiedemann 399b1f
 block.c               |  20 +++--
Bernhard M. Wiedemann 399b1f
 block/dmg.c           |  14 +++-
Bernhard M. Wiedemann 399b1f
 hw/core/qdev.c        |  17 +++-
Bernhard M. Wiedemann 399b1f
 include/qemu/module.h |  37 +++++++--
Bernhard M. Wiedemann 399b1f
 qom/object.c          |  18 +++-
Bernhard M. Wiedemann 399b1f
 softmmu/qtest.c       |   8 +-
Bernhard M. Wiedemann 399b1f
 ui/console.c          |  18 +++-
Bernhard M. Wiedemann 399b1f
 util/module.c         | 189 +++++++++++++++++++++++-------------------
Bernhard M. Wiedemann 399b1f
 9 files changed, 224 insertions(+), 113 deletions(-)
Bernhard M. Wiedemann 399b1f
Bernhard M. Wiedemann 399b1f
diff --git a/audio/audio.c b/audio/audio.c
Bernhard M. Wiedemann 399b1f
index 9e2609707d7f4adecfb6e9f45670..cdbcaa8603cc661332e4906f8a37 100644
Bernhard M. Wiedemann 399b1f
--- a/audio/audio.c
Bernhard M. Wiedemann 399b1f
+++ b/audio/audio.c
Bernhard M. Wiedemann 399b1f
@@ -72,20 +72,24 @@ void audio_driver_register(audio_driver *drv)
Bernhard M. Wiedemann 399b1f
 audio_driver *audio_driver_lookup(const char *name)
Bernhard M. Wiedemann 399b1f
 {
Bernhard M. Wiedemann 399b1f
     struct audio_driver *d;
Bernhard M. Wiedemann 399b1f
+    Error *local_err = NULL;
Bernhard M. Wiedemann 399b1f
+    int rv;
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
     QLIST_FOREACH(d, &audio_drivers, next) {
Bernhard M. Wiedemann 399b1f
         if (strcmp(name, d->name) == 0) {
Bernhard M. Wiedemann 399b1f
             return d;
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
-
Bernhard M. Wiedemann 399b1f
-    audio_module_load(name);
Bernhard M. Wiedemann 399b1f
-    QLIST_FOREACH(d, &audio_drivers, next) {
Bernhard M. Wiedemann 399b1f
-        if (strcmp(name, d->name) == 0) {
Bernhard M. Wiedemann 399b1f
-            return d;
Bernhard M. Wiedemann 399b1f
+    rv = audio_module_load(name, &local_err);
Bernhard M. Wiedemann 399b1f
+    if (rv > 0) {
Bernhard M. Wiedemann 399b1f
+        QLIST_FOREACH(d, &audio_drivers, next) {
Bernhard M. Wiedemann 399b1f
+            if (strcmp(name, d->name) == 0) {
Bernhard M. Wiedemann 399b1f
+                return d;
Bernhard M. Wiedemann 399b1f
+            }
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
+    } else if (rv < 0) {
Bernhard M. Wiedemann 399b1f
+        error_report_err(local_err);
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
-
Bernhard M. Wiedemann 399b1f
     return NULL;
Bernhard M. Wiedemann 399b1f
 }
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
diff --git a/block.c b/block.c
Bernhard M. Wiedemann 399b1f
index 72c7f6d47d590657472b036a5847..7a94739aedc5eeac349a917f9864 100644
Bernhard M. Wiedemann 399b1f
--- a/block.c
Bernhard M. Wiedemann 399b1f
+++ b/block.c
Bernhard M. Wiedemann 399b1f
@@ -464,12 +464,18 @@ BlockDriver *bdrv_find_format(const char *format_name)
Bernhard M. Wiedemann 399b1f
     /* The driver isn't registered, maybe we need to load a module */
Bernhard M. Wiedemann 399b1f
     for (i = 0; i < (int)ARRAY_SIZE(block_driver_modules); ++i) {
Bernhard M. Wiedemann 399b1f
         if (!strcmp(block_driver_modules[i].format_name, format_name)) {
Bernhard M. Wiedemann 399b1f
-            block_module_load(block_driver_modules[i].library_name);
Bernhard M. Wiedemann 399b1f
+            Error *local_err = NULL;
Bernhard M. Wiedemann 399b1f
+            int rv = block_module_load(block_driver_modules[i].library_name,
Bernhard M. Wiedemann 399b1f
+                                       &local_err);
Bernhard M. Wiedemann 399b1f
+            if (rv > 0) {
Bernhard M. Wiedemann 399b1f
+                return bdrv_do_find_format(format_name);
Bernhard M. Wiedemann 399b1f
+            } else if (rv < 0) {
Bernhard M. Wiedemann 399b1f
+                error_report_err(local_err);
Bernhard M. Wiedemann 399b1f
+            }
Bernhard M. Wiedemann 399b1f
             break;
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
-
Bernhard M. Wiedemann 399b1f
-    return bdrv_do_find_format(format_name);
Bernhard M. Wiedemann 399b1f
+    return NULL;
Bernhard M. Wiedemann 399b1f
 }
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
 static int bdrv_format_is_whitelisted(const char *format_name, bool read_only)
Bernhard M. Wiedemann 399b1f
@@ -976,12 +982,16 @@ BlockDriver *bdrv_find_protocol(const char *filename,
Bernhard M. Wiedemann 399b1f
     for (i = 0; i < (int)ARRAY_SIZE(block_driver_modules); ++i) {
Bernhard M. Wiedemann 399b1f
         if (block_driver_modules[i].protocol_name &&
Bernhard M. Wiedemann 399b1f
             !strcmp(block_driver_modules[i].protocol_name, protocol)) {
Bernhard M. Wiedemann 399b1f
-            block_module_load(block_driver_modules[i].library_name);
Bernhard M. Wiedemann 399b1f
+            int rv = block_module_load(block_driver_modules[i].library_name, errp);
Bernhard M. Wiedemann 399b1f
+            if (rv > 0) {
Bernhard M. Wiedemann 399b1f
+                drv1 = bdrv_do_find_protocol(protocol);
Bernhard M. Wiedemann 399b1f
+            } else if (rv < 0) {
Bernhard M. Wiedemann 399b1f
+                return NULL;
Bernhard M. Wiedemann 399b1f
+            }
Bernhard M. Wiedemann 399b1f
             break;
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
-    drv1 = bdrv_do_find_protocol(protocol);
Bernhard M. Wiedemann 399b1f
     if (!drv1) {
Bernhard M. Wiedemann 399b1f
         error_setg(errp, "Unknown protocol '%s'", protocol);
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
diff --git a/block/dmg.c b/block/dmg.c
Bernhard M. Wiedemann 399b1f
index 007b8d9996d61be8370699f3d81f..837f18aa20ff7ebb35f961a9626c 100644
Bernhard M. Wiedemann 399b1f
--- a/block/dmg.c
Bernhard M. Wiedemann 399b1f
+++ b/block/dmg.c
Bernhard M. Wiedemann 399b1f
@@ -445,9 +445,17 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
Bernhard M. Wiedemann 399b1f
     if (!bs->file) {
Bernhard M. Wiedemann 399b1f
         return -EINVAL;
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
-
Bernhard M. Wiedemann 399b1f
-    block_module_load("dmg-bz2");
Bernhard M. Wiedemann 399b1f
-    block_module_load("dmg-lzfse");
Bernhard M. Wiedemann 399b1f
+    /*
Bernhard M. Wiedemann 399b1f
+     * NB: if uncompress submodules are absent,
Bernhard M. Wiedemann 399b1f
+     * ie block_module_load return value == 0, the function pointers
Bernhard M. Wiedemann 399b1f
+     * dmg_uncompress_bz2 and dmg_uncompress_lzfse will be NULL.
Bernhard M. Wiedemann 399b1f
+     */
Bernhard M. Wiedemann 399b1f
+    if (block_module_load("dmg-bz2", errp) < 0) {
Bernhard M. Wiedemann 399b1f
+        return -EINVAL;
Bernhard M. Wiedemann 399b1f
+    }
Bernhard M. Wiedemann 399b1f
+    if (block_module_load("dmg-lzfse", errp) < 0) {
Bernhard M. Wiedemann 399b1f
+        return -EINVAL;
Bernhard M. Wiedemann 399b1f
+    }
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
     s->n_chunks = 0;
Bernhard M. Wiedemann 399b1f
     s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
Bernhard M. Wiedemann 399b1f
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
Bernhard M. Wiedemann 399b1f
index 25dfc08468011b2d63f032526919..0145501904473864167a11481d94 100644
Bernhard M. Wiedemann 399b1f
--- a/hw/core/qdev.c
Bernhard M. Wiedemann 399b1f
+++ b/hw/core/qdev.c
Bernhard M. Wiedemann 399b1f
@@ -147,8 +147,21 @@ bool qdev_set_parent_bus(DeviceState *dev, BusState *bus, Error **errp)
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
 DeviceState *qdev_new(const char *name)
Bernhard M. Wiedemann 399b1f
 {
Bernhard M. Wiedemann 399b1f
-    if (!object_class_by_name(name)) {
Bernhard M. Wiedemann 399b1f
-        module_load_qom(name);
Bernhard M. Wiedemann 399b1f
+    ObjectClass *oc = object_class_by_name(name);
Bernhard M. Wiedemann 399b1f
+#ifdef CONFIG_MODULES
Bernhard M. Wiedemann 399b1f
+    if (!oc) {
Bernhard M. Wiedemann 399b1f
+        int rv = module_load_qom(name, &error_fatal);
Bernhard M. Wiedemann 399b1f
+        if (rv > 0) {
Bernhard M. Wiedemann 399b1f
+            oc = object_class_by_name(name);
Bernhard M. Wiedemann 399b1f
+        } else {
Bernhard M. Wiedemann 399b1f
+            error_report("could not find a module for type '%s'", name);
Bernhard M. Wiedemann 399b1f
+            exit(1);
Bernhard M. Wiedemann 399b1f
+        }
Bernhard M. Wiedemann 399b1f
+    }
Bernhard M. Wiedemann 399b1f
+#endif
Bernhard M. Wiedemann 399b1f
+    if (!oc) {
Bernhard M. Wiedemann 399b1f
+        error_report("unknown type '%s'", name);
Bernhard M. Wiedemann 399b1f
+        abort();
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
     return DEVICE(object_new(name));
Bernhard M. Wiedemann 399b1f
 }
Bernhard M. Wiedemann 399b1f
diff --git a/include/qemu/module.h b/include/qemu/module.h
Bernhard M. Wiedemann 399b1f
index b7911ce7916148ba9c3245878350..c37ce74b16ffe57550fab68b0f2d 100644
Bernhard M. Wiedemann 399b1f
--- a/include/qemu/module.h
Bernhard M. Wiedemann 399b1f
+++ b/include/qemu/module.h
Bernhard M. Wiedemann 399b1f
@@ -61,16 +61,43 @@ typedef enum {
Bernhard M. Wiedemann 399b1f
 #define fuzz_target_init(function) module_init(function, \
Bernhard M. Wiedemann 399b1f
                                                MODULE_INIT_FUZZ_TARGET)
Bernhard M. Wiedemann 399b1f
 #define migration_init(function) module_init(function, MODULE_INIT_MIGRATION)
Bernhard M. Wiedemann 399b1f
-#define block_module_load(lib) module_load("block-", lib)
Bernhard M. Wiedemann 399b1f
-#define ui_module_load(lib) module_load("ui-", lib)
Bernhard M. Wiedemann 399b1f
-#define audio_module_load(lib) module_load("audio-", lib)
Bernhard M. Wiedemann 399b1f
+#define block_module_load(lib, errp) module_load("block-", lib, errp)
Bernhard M. Wiedemann 399b1f
+#define ui_module_load(lib, errp) module_load("ui-", lib, errp)
Bernhard M. Wiedemann 399b1f
+#define audio_module_load(lib, errp) module_load("audio-", lib, errp)
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
 void register_module_init(void (*fn)(void), module_init_type type);
Bernhard M. Wiedemann 399b1f
 void register_dso_module_init(void (*fn)(void), module_init_type type);
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
 void module_call_init(module_init_type type);
Bernhard M. Wiedemann 399b1f
-bool module_load(const char *prefix, const char *lib_name);
Bernhard M. Wiedemann 399b1f
-void module_load_qom(const char *type);
Bernhard M. Wiedemann 399b1f
+
Bernhard M. Wiedemann 399b1f
+/*
Bernhard M. Wiedemann 399b1f
+ * module_load: attempt to load a module from a set of directories
Bernhard M. Wiedemann 399b1f
+ *
Bernhard M. Wiedemann 399b1f
+ * directories searched are:
Bernhard M. Wiedemann 399b1f
+ * - getenv("QEMU_MODULE_DIR")
Bernhard M. Wiedemann 399b1f
+ * - get_relocated_path(CONFIG_QEMU_MODDIR);
Bernhard M. Wiedemann 399b1f
+ * - /var/run/qemu/${version_dir}
Bernhard M. Wiedemann 399b1f
+ *
Bernhard M. Wiedemann 399b1f
+ * prefix:         a subsystem prefix, or the empty string ("audio-", ..., "")
Bernhard M. Wiedemann 399b1f
+ * name:           name of the module
Bernhard M. Wiedemann 399b1f
+ * errp:           error to set in case the module is found, but load failed.
Bernhard M. Wiedemann 399b1f
+ *
Bernhard M. Wiedemann 399b1f
+ * Return value:   -1 on error (errp set if not NULL).
Bernhard M. Wiedemann 399b1f
+ *                 0 if module or one of its dependencies are not installed,
Bernhard M. Wiedemann 399b1f
+ *                 1 if the module is found and loaded,
Bernhard M. Wiedemann 399b1f
+ *                 2 if the module is already loaded, or module is built-in.
Bernhard M. Wiedemann 399b1f
+ */
Bernhard M. Wiedemann 399b1f
+int module_load(const char *prefix, const char *name, Error **errp);
Bernhard M. Wiedemann 399b1f
+
Bernhard M. Wiedemann 399b1f
+/*
Bernhard M. Wiedemann 399b1f
+ * module_load_qom: attempt to load a module to provide a QOM type
Bernhard M. Wiedemann 399b1f
+ *
Bernhard M. Wiedemann 399b1f
+ * type:           the type to be provided
Bernhard M. Wiedemann 399b1f
+ * errp:           error to set.
Bernhard M. Wiedemann 399b1f
+ *
Bernhard M. Wiedemann 399b1f
+ * Return value:   as per module_load.
Bernhard M. Wiedemann 399b1f
+ */
Bernhard M. Wiedemann 399b1f
+int module_load_qom(const char *type, Error **errp);
Bernhard M. Wiedemann 399b1f
 void module_load_qom_all(void);
Bernhard M. Wiedemann 399b1f
 void module_allow_arch(const char *arch);
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
diff --git a/qom/object.c b/qom/object.c
Bernhard M. Wiedemann 399b1f
index 4f834f3bf66c6672138d9bfc9e55..45da07980a19d1db754961bcc377 100644
Bernhard M. Wiedemann 399b1f
--- a/qom/object.c
Bernhard M. Wiedemann 399b1f
+++ b/qom/object.c
Bernhard M. Wiedemann 399b1f
@@ -526,8 +526,13 @@ void object_initialize(void *data, size_t size, const char *typename)
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
 #ifdef CONFIG_MODULES
Bernhard M. Wiedemann 399b1f
     if (!type) {
Bernhard M. Wiedemann 399b1f
-        module_load_qom(typename);
Bernhard M. Wiedemann 399b1f
-        type = type_get_by_name(typename);
Bernhard M. Wiedemann 399b1f
+        int rv = module_load_qom(typename, &error_fatal);
Bernhard M. Wiedemann 399b1f
+        if (rv > 0) {
Bernhard M. Wiedemann 399b1f
+            type = type_get_by_name(typename);
Bernhard M. Wiedemann 399b1f
+        } else {
Bernhard M. Wiedemann 399b1f
+            error_report("missing object type '%s'", typename);
Bernhard M. Wiedemann 399b1f
+            exit(1);
Bernhard M. Wiedemann 399b1f
+        }
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
 #endif
Bernhard M. Wiedemann 399b1f
     if (!type) {
Bernhard M. Wiedemann 399b1f
@@ -1033,8 +1038,13 @@ ObjectClass *module_object_class_by_name(const char *typename)
Bernhard M. Wiedemann 399b1f
     oc = object_class_by_name(typename);
Bernhard M. Wiedemann 399b1f
 #ifdef CONFIG_MODULES
Bernhard M. Wiedemann 399b1f
     if (!oc) {
Bernhard M. Wiedemann 399b1f
-        module_load_qom(typename);
Bernhard M. Wiedemann 399b1f
-        oc = object_class_by_name(typename);
Bernhard M. Wiedemann 399b1f
+        Error *local_err = NULL;
Bernhard M. Wiedemann 399b1f
+        int rv = module_load_qom(typename, &local_err);
Bernhard M. Wiedemann 399b1f
+        if (rv > 0) {
Bernhard M. Wiedemann 399b1f
+            oc = object_class_by_name(typename);
Bernhard M. Wiedemann 399b1f
+        } else if (rv < 0) {
Bernhard M. Wiedemann 399b1f
+            error_report_err(local_err);
Bernhard M. Wiedemann 399b1f
+        }
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
 #endif
Bernhard M. Wiedemann 399b1f
     return oc;
Bernhard M. Wiedemann 399b1f
diff --git a/softmmu/qtest.c b/softmmu/qtest.c
Bernhard M. Wiedemann 399b1f
index fc5b733c630035785732610c920c..36e28609ffa2fb977d05f115a4d8 100644
Bernhard M. Wiedemann 399b1f
--- a/softmmu/qtest.c
Bernhard M. Wiedemann 399b1f
+++ b/softmmu/qtest.c
Bernhard M. Wiedemann 399b1f
@@ -753,12 +753,18 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
Bernhard M. Wiedemann 399b1f
         qtest_sendf(chr, "OK %"PRIi64"\n",
Bernhard M. Wiedemann 399b1f
                     (int64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
Bernhard M. Wiedemann 399b1f
     } else if (strcmp(words[0], "module_load") == 0) {
Bernhard M. Wiedemann 399b1f
+        Error *local_err = NULL;
Bernhard M. Wiedemann 399b1f
+        int rv;
Bernhard M. Wiedemann 399b1f
         g_assert(words[1] && words[2]);
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
         qtest_send_prefix(chr);
Bernhard M. Wiedemann 399b1f
-        if (module_load(words[1], words[2])) {
Bernhard M. Wiedemann 399b1f
+        rv = module_load(words[1], words[2], &local_err);
Bernhard M. Wiedemann 399b1f
+        if (rv > 0) {
Bernhard M. Wiedemann 399b1f
             qtest_sendf(chr, "OK\n");
Bernhard M. Wiedemann 399b1f
         } else {
Bernhard M. Wiedemann 399b1f
+            if (rv < 0) {
Bernhard M. Wiedemann 399b1f
+                error_report_err(local_err);
Bernhard M. Wiedemann 399b1f
+            }
Bernhard M. Wiedemann 399b1f
             qtest_sendf(chr, "FAIL\n");
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
     } else if (qtest_enabled() && strcmp(words[0], "clock_set") == 0) {
Bernhard M. Wiedemann 399b1f
diff --git a/ui/console.c b/ui/console.c
Bernhard M. Wiedemann 399b1f
index 4913c55684cb9b9d8c8ab0df5b22..4e53c3c71b2f94d1e2644d5b6ed3 100644
Bernhard M. Wiedemann 399b1f
--- a/ui/console.c
Bernhard M. Wiedemann 399b1f
+++ b/ui/console.c
Bernhard M. Wiedemann 399b1f
@@ -2632,7 +2632,11 @@ bool qemu_display_find_default(DisplayOptions *opts)
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
     for (i = 0; i < (int)ARRAY_SIZE(prio); i++) {
Bernhard M. Wiedemann 399b1f
         if (dpys[prio[i]] == NULL) {
Bernhard M. Wiedemann 399b1f
-            ui_module_load(DisplayType_str(prio[i]));
Bernhard M. Wiedemann 399b1f
+            Error *local_err = NULL;
Bernhard M. Wiedemann 399b1f
+            int rv = ui_module_load(DisplayType_str(prio[i]), &local_err);
Bernhard M. Wiedemann 399b1f
+            if (rv < 0) {
Bernhard M. Wiedemann 399b1f
+                error_report_err(local_err);
Bernhard M. Wiedemann 399b1f
+            }
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
         if (dpys[prio[i]] == NULL) {
Bernhard M. Wiedemann 399b1f
             continue;
Bernhard M. Wiedemann 399b1f
@@ -2650,7 +2654,11 @@ void qemu_display_early_init(DisplayOptions *opts)
Bernhard M. Wiedemann 399b1f
         return;
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
     if (dpys[opts->type] == NULL) {
Bernhard M. Wiedemann 399b1f
-        ui_module_load(DisplayType_str(opts->type));
Bernhard M. Wiedemann 399b1f
+        Error *local_err = NULL;
Bernhard M. Wiedemann 399b1f
+        int rv = ui_module_load(DisplayType_str(opts->type), &local_err);
Bernhard M. Wiedemann 399b1f
+        if (rv < 0) {
Bernhard M. Wiedemann 399b1f
+            error_report_err(local_err);
Bernhard M. Wiedemann 399b1f
+        }
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
     if (dpys[opts->type] == NULL) {
Bernhard M. Wiedemann 399b1f
         error_report("Display '%s' is not available.",
Bernhard M. Wiedemann 399b1f
@@ -2680,7 +2688,11 @@ void qemu_display_help(void)
Bernhard M. Wiedemann 399b1f
     printf("none\n");
Bernhard M. Wiedemann 399b1f
     for (idx = DISPLAY_TYPE_NONE; idx < DISPLAY_TYPE__MAX; idx++) {
Bernhard M. Wiedemann 399b1f
         if (!dpys[idx]) {
Bernhard M. Wiedemann 399b1f
-            ui_module_load(DisplayType_str(idx));
Bernhard M. Wiedemann 399b1f
+            Error *local_err = NULL;
Bernhard M. Wiedemann 399b1f
+            int rv = ui_module_load(DisplayType_str(idx), &local_err);
Bernhard M. Wiedemann 399b1f
+            if (rv < 0) {
Bernhard M. Wiedemann 399b1f
+                error_report_err(local_err);
Bernhard M. Wiedemann 399b1f
+            }
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
         if (dpys[idx]) {
Bernhard M. Wiedemann 399b1f
             printf("%s\n",  DisplayType_str(dpys[idx]->type));
Bernhard M. Wiedemann 399b1f
diff --git a/util/module.c b/util/module.c
Bernhard M. Wiedemann 399b1f
index ad89cd50dc2a03ea6f8431849137..32e263163c75dfa8e93ca67c739d 100644
Bernhard M. Wiedemann 399b1f
--- a/util/module.c
Bernhard M. Wiedemann 399b1f
+++ b/util/module.c
Bernhard M. Wiedemann 399b1f
@@ -21,6 +21,7 @@
Bernhard M. Wiedemann 399b1f
 #include "qemu/module.h"
Bernhard M. Wiedemann 399b1f
 #include "qemu/cutils.h"
Bernhard M. Wiedemann 399b1f
 #include "qemu/config-file.h"
Bernhard M. Wiedemann 399b1f
+#include "qapi/error.h"
Bernhard M. Wiedemann 399b1f
 #ifdef CONFIG_MODULE_UPGRADES
Bernhard M. Wiedemann 399b1f
 #include "qemu-version.h"
Bernhard M. Wiedemann 399b1f
 #endif
Bernhard M. Wiedemann 399b1f
@@ -144,25 +145,22 @@ static bool module_check_arch(const QemuModinfo *modinfo)
Bernhard M. Wiedemann 399b1f
     return true;
Bernhard M. Wiedemann 399b1f
 }
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
-static int module_load_file(const char *fname, bool export_symbols)
Bernhard M. Wiedemann 399b1f
+/*
Bernhard M. Wiedemann 399b1f
+ * module_load_dso: attempt to load an existing dso file
Bernhard M. Wiedemann 399b1f
+ *
Bernhard M. Wiedemann 399b1f
+ * fname:          full pathname of the file to load
Bernhard M. Wiedemann 399b1f
+ * export_symbols: if true, add the symbols to the global name space
Bernhard M. Wiedemann 399b1f
+ * errp:           error to set.
Bernhard M. Wiedemann 399b1f
+ *
Bernhard M. Wiedemann 399b1f
+ * Return value:   true on success, false on error, and errp will be set.
Bernhard M. Wiedemann 399b1f
+ */
Bernhard M. Wiedemann 399b1f
+static bool module_load_dso(const char *fname, bool export_symbols,
Bernhard M. Wiedemann 399b1f
+                            Error **errp)
Bernhard M. Wiedemann 399b1f
 {
Bernhard M. Wiedemann 399b1f
     GModule *g_module;
Bernhard M. Wiedemann 399b1f
     void (*sym)(void);
Bernhard M. Wiedemann 399b1f
-    const char *dsosuf = CONFIG_HOST_DSOSUF;
Bernhard M. Wiedemann 399b1f
-    int len = strlen(fname);
Bernhard M. Wiedemann 399b1f
-    int suf_len = strlen(dsosuf);
Bernhard M. Wiedemann 399b1f
     ModuleEntry *e, *next;
Bernhard M. Wiedemann 399b1f
-    int ret, flags;
Bernhard M. Wiedemann 399b1f
-
Bernhard M. Wiedemann 399b1f
-    if (len <= suf_len || strcmp(&fname[len - suf_len], dsosuf)) {
Bernhard M. Wiedemann 399b1f
-        /* wrong suffix */
Bernhard M. Wiedemann 399b1f
-        ret = -EINVAL;
Bernhard M. Wiedemann 399b1f
-        goto out;
Bernhard M. Wiedemann 399b1f
-    }
Bernhard M. Wiedemann 399b1f
-    if (access(fname, F_OK)) {
Bernhard M. Wiedemann 399b1f
-        ret = -ENOENT;
Bernhard M. Wiedemann 399b1f
-        goto out;
Bernhard M. Wiedemann 399b1f
-    }
Bernhard M. Wiedemann 399b1f
+    int flags;
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
     assert(QTAILQ_EMPTY(&dso_init_list));
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
@@ -172,46 +170,38 @@ static int module_load_file(const char *fname, bool export_symbols)
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
     g_module = g_module_open(fname, flags);
Bernhard M. Wiedemann 399b1f
     if (!g_module) {
Bernhard M. Wiedemann 399b1f
-        fprintf(stderr, "Failed to open module: %s\n",
Bernhard M. Wiedemann 399b1f
-                g_module_error());
Bernhard M. Wiedemann 399b1f
-        ret = -EINVAL;
Bernhard M. Wiedemann 399b1f
-        goto out;
Bernhard M. Wiedemann 399b1f
+        error_setg(errp, "failed to open module: %s", g_module_error());
Bernhard M. Wiedemann 399b1f
+        return false;
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
     if (!g_module_symbol(g_module, DSO_STAMP_FUN_STR, (gpointer *)&sym)) {
Bernhard M. Wiedemann 399b1f
-        fprintf(stderr, "Failed to initialize module: %s\n",
Bernhard M. Wiedemann 399b1f
-                fname);
Bernhard M. Wiedemann 399b1f
-        /* Print some info if this is a QEMU module (but from different build),
Bernhard M. Wiedemann 399b1f
-         * this will make debugging user problems easier. */
Bernhard M. Wiedemann 399b1f
+        error_setg(errp, "failed to initialize module: %s", fname);
Bernhard M. Wiedemann 399b1f
+        /*
Bernhard M. Wiedemann 399b1f
+         * Print some info if this is a QEMU module (but from different build),
Bernhard M. Wiedemann 399b1f
+         * this will make debugging user problems easier.
Bernhard M. Wiedemann 399b1f
+         */
Bernhard M. Wiedemann 399b1f
         if (g_module_symbol(g_module, "qemu_module_dummy", (gpointer *)&sym)) {
Bernhard M. Wiedemann 399b1f
-            fprintf(stderr,
Bernhard M. Wiedemann 399b1f
-                    "Note: only modules from the same build can be loaded.\n");
Bernhard M. Wiedemann 399b1f
+            error_append_hint(errp,
Bernhard M. Wiedemann 399b1f
+                "Only modules from the same build can be loaded.\n");
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
         g_module_close(g_module);
Bernhard M. Wiedemann 399b1f
-        ret = -EINVAL;
Bernhard M. Wiedemann 399b1f
-    } else {
Bernhard M. Wiedemann 399b1f
-        QTAILQ_FOREACH(e, &dso_init_list, node) {
Bernhard M. Wiedemann 399b1f
-            e->init();
Bernhard M. Wiedemann 399b1f
-            register_module_init(e->init, e->type);
Bernhard M. Wiedemann 399b1f
-        }
Bernhard M. Wiedemann 399b1f
-        ret = 0;
Bernhard M. Wiedemann 399b1f
+        return false;
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
+    QTAILQ_FOREACH(e, &dso_init_list, node) {
Bernhard M. Wiedemann 399b1f
+        e->init();
Bernhard M. Wiedemann 399b1f
+        register_module_init(e->init, e->type);
Bernhard M. Wiedemann 399b1f
+    }
Bernhard M. Wiedemann 399b1f
     trace_module_load_module(fname);
Bernhard M. Wiedemann 399b1f
     QTAILQ_FOREACH_SAFE(e, &dso_init_list, node, next) {
Bernhard M. Wiedemann 399b1f
         QTAILQ_REMOVE(&dso_init_list, e, node);
Bernhard M. Wiedemann 399b1f
         g_free(e);
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
-out:
Bernhard M. Wiedemann 399b1f
-    return ret;
Bernhard M. Wiedemann 399b1f
+    return true;
Bernhard M. Wiedemann 399b1f
 }
Bernhard M. Wiedemann 399b1f
-#endif
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
-bool module_load(const char *prefix, const char *lib_name)
Bernhard M. Wiedemann 399b1f
+int module_load(const char *prefix, const char *name, Error **errp)
Bernhard M. Wiedemann 399b1f
 {
Bernhard M. Wiedemann 399b1f
-    bool success = false;
Bernhard M. Wiedemann 399b1f
-
Bernhard M. Wiedemann 399b1f
-#ifdef CONFIG_MODULES
Bernhard M. Wiedemann 399b1f
-    char *fname = NULL;
Bernhard M. Wiedemann 399b1f
+    int rv = -1;
Bernhard M. Wiedemann 399b1f
 #ifdef CONFIG_MODULE_UPGRADES
Bernhard M. Wiedemann 399b1f
     char *version_dir;
Bernhard M. Wiedemann 399b1f
 #endif
Bernhard M. Wiedemann 399b1f
@@ -219,34 +209,52 @@ bool module_load(const char *prefix, const char *lib_name)
Bernhard M. Wiedemann 399b1f
     char *dirs[5];
Bernhard M. Wiedemann 399b1f
     char *module_name;
Bernhard M. Wiedemann 399b1f
     int i = 0, n_dirs = 0;
Bernhard M. Wiedemann 399b1f
-    int ret;
Bernhard M. Wiedemann 399b1f
     bool export_symbols = false;
Bernhard M. Wiedemann 399b1f
     static GHashTable *loaded_modules;
Bernhard M. Wiedemann 399b1f
     const QemuModinfo *modinfo;
Bernhard M. Wiedemann 399b1f
     const char **sl;
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
     if (!g_module_supported()) {
Bernhard M. Wiedemann 399b1f
-        fprintf(stderr, "Module is not supported by system.\n");
Bernhard M. Wiedemann 399b1f
-        return false;
Bernhard M. Wiedemann 399b1f
+        error_setg(errp, "%s", "this platform does not support GLib modules");
Bernhard M. Wiedemann 399b1f
+        return -1;
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
     if (!loaded_modules) {
Bernhard M. Wiedemann 399b1f
         loaded_modules = g_hash_table_new(g_str_hash, g_str_equal);
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
-    module_name = g_strdup_printf("%s%s", prefix, lib_name);
Bernhard M. Wiedemann 399b1f
+    /* allocate all resources managed by the out: label here */
Bernhard M. Wiedemann 399b1f
+    module_name = g_strdup_printf("%s%s", prefix, name);
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
     if (g_hash_table_contains(loaded_modules, module_name)) {
Bernhard M. Wiedemann 399b1f
         g_free(module_name);
Bernhard M. Wiedemann 399b1f
-        return true;
Bernhard M. Wiedemann 399b1f
+        return 2; /* module already loaded */
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
     g_hash_table_add(loaded_modules, module_name);
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
+    search_dir = getenv("QEMU_MODULE_DIR");
Bernhard M. Wiedemann 399b1f
+    if (search_dir != NULL) {
Bernhard M. Wiedemann 399b1f
+        dirs[n_dirs++] = g_strdup_printf("%s", search_dir);
Bernhard M. Wiedemann 399b1f
+    }
Bernhard M. Wiedemann 399b1f
+    dirs[n_dirs++] = get_relocated_path(CONFIG_QEMU_MODDIR);
Bernhard M. Wiedemann 399b1f
+
Bernhard M. Wiedemann 399b1f
+#ifdef CONFIG_MODULE_UPGRADES
Bernhard M. Wiedemann 399b1f
+    version_dir = g_strcanon(g_strdup(QEMU_PKGVERSION),
Bernhard M. Wiedemann 399b1f
+                             G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "+-.~",
Bernhard M. Wiedemann 399b1f
+                             '_');
Bernhard M. Wiedemann 399b1f
+    dirs[n_dirs++] = g_strdup_printf("/var/run/qemu/%s", version_dir);
Bernhard M. Wiedemann 399b1f
+#endif
Bernhard M. Wiedemann 399b1f
+    assert(n_dirs <= ARRAY_SIZE(dirs));
Bernhard M. Wiedemann 399b1f
+
Bernhard M. Wiedemann 399b1f
+    /* end of resources managed by the out: label */
Bernhard M. Wiedemann 399b1f
+
Bernhard M. Wiedemann 399b1f
     for (modinfo = module_info; modinfo->name != NULL; modinfo++) {
Bernhard M. Wiedemann 399b1f
         if (modinfo->arch) {
Bernhard M. Wiedemann 399b1f
             if (strcmp(modinfo->name, module_name) == 0) {
Bernhard M. Wiedemann 399b1f
                 if (!module_check_arch(modinfo)) {
Bernhard M. Wiedemann 399b1f
-                    return false;
Bernhard M. Wiedemann 399b1f
+                    error_setg(errp, "module arch does not match: "
Bernhard M. Wiedemann 399b1f
+                        "expected '%s', got '%s'", module_arch, modinfo->arch);
Bernhard M. Wiedemann 399b1f
+                    goto out;
Bernhard M. Wiedemann 399b1f
                 }
Bernhard M. Wiedemann 399b1f
             }
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
@@ -254,7 +262,11 @@ bool module_load(const char *prefix, const char *lib_name)
Bernhard M. Wiedemann 399b1f
             if (strcmp(modinfo->name, module_name) == 0) {
Bernhard M. Wiedemann 399b1f
                 /* we depend on other module(s) */
Bernhard M. Wiedemann 399b1f
                 for (sl = modinfo->deps; *sl != NULL; sl++) {
Bernhard M. Wiedemann 399b1f
-                    module_load("", *sl);
Bernhard M. Wiedemann 399b1f
+                    int subrv = module_load("", *sl, errp);
Bernhard M. Wiedemann 399b1f
+                    if (subrv <= 0) {
Bernhard M. Wiedemann 399b1f
+                        rv = subrv;
Bernhard M. Wiedemann 399b1f
+                        goto out;
Bernhard M. Wiedemann 399b1f
+                    }
Bernhard M. Wiedemann 399b1f
                 }
Bernhard M. Wiedemann 399b1f
             } else {
Bernhard M. Wiedemann 399b1f
                 for (sl = modinfo->deps; *sl != NULL; sl++) {
Bernhard M. Wiedemann 399b1f
@@ -267,58 +279,52 @@ bool module_load(const char *prefix, const char *lib_name)
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
-    search_dir = getenv("QEMU_MODULE_DIR");
Bernhard M. Wiedemann 399b1f
-    if (search_dir != NULL) {
Bernhard M. Wiedemann 399b1f
-        dirs[n_dirs++] = g_strdup_printf("%s", search_dir);
Bernhard M. Wiedemann 399b1f
-    }
Bernhard M. Wiedemann 399b1f
-    dirs[n_dirs++] = get_relocated_path(CONFIG_QEMU_MODDIR);
Bernhard M. Wiedemann 399b1f
-
Bernhard M. Wiedemann 399b1f
-#ifdef CONFIG_MODULE_UPGRADES
Bernhard M. Wiedemann 399b1f
-    version_dir = g_strcanon(g_strdup(QEMU_PKGVERSION),
Bernhard M. Wiedemann 399b1f
-                             G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "+-.~",
Bernhard M. Wiedemann 399b1f
-                             '_');
Bernhard M. Wiedemann 399b1f
-    dirs[n_dirs++] = g_strdup_printf("/var/run/qemu/%s", version_dir);
Bernhard M. Wiedemann 399b1f
-#endif
Bernhard M. Wiedemann 399b1f
-
Bernhard M. Wiedemann 399b1f
-    assert(n_dirs <= ARRAY_SIZE(dirs));
Bernhard M. Wiedemann 399b1f
-
Bernhard M. Wiedemann 399b1f
     for (i = 0; i < n_dirs; i++) {
Bernhard M. Wiedemann 399b1f
-        fname = g_strdup_printf("%s/%s%s",
Bernhard M. Wiedemann 399b1f
-                dirs[i], module_name, CONFIG_HOST_DSOSUF);
Bernhard M. Wiedemann 399b1f
-        ret = module_load_file(fname, export_symbols);
Bernhard M. Wiedemann 399b1f
-        g_free(fname);
Bernhard M. Wiedemann 399b1f
-        fname = NULL;
Bernhard M. Wiedemann 399b1f
-        /* Try loading until loaded a module file */
Bernhard M. Wiedemann 399b1f
-        if (!ret) {
Bernhard M. Wiedemann 399b1f
-            success = true;
Bernhard M. Wiedemann 399b1f
-            break;
Bernhard M. Wiedemann 399b1f
+        char *fname = g_strdup_printf("%s/%s%s",
Bernhard M. Wiedemann 399b1f
+                                      dirs[i], module_name, CONFIG_HOST_DSOSUF);
Bernhard M. Wiedemann 399b1f
+        int ret = access(fname, F_OK);
Bernhard M. Wiedemann 399b1f
+        if (ret != 0 && (errno == ENOENT || errno == ENOTDIR)) {
Bernhard M. Wiedemann 399b1f
+            /*
Bernhard M. Wiedemann 399b1f
+             * if we don't find the module in this dir, try the next one.
Bernhard M. Wiedemann 399b1f
+             * If we don't find it in any dir, that can be fine too: user
Bernhard M. Wiedemann 399b1f
+             * did not install the module. We will return 0 in this case
Bernhard M. Wiedemann 399b1f
+             * with no error set.
Bernhard M. Wiedemann 399b1f
+             */
Bernhard M. Wiedemann 399b1f
+            g_free(fname);
Bernhard M. Wiedemann 399b1f
+            continue;
Bernhard M. Wiedemann 399b1f
+        } else if (ret != 0) {
Bernhard M. Wiedemann 399b1f
+            /* most common is EACCES here */
Bernhard M. Wiedemann 399b1f
+            error_setg_errno(errp, errno, "error trying to access %s", fname);
Bernhard M. Wiedemann 399b1f
+        } else if (module_load_dso(fname, export_symbols, errp)) {
Bernhard M. Wiedemann 399b1f
+            rv = 1; /* module successfully loaded */
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
+        g_free(fname);
Bernhard M. Wiedemann 399b1f
+        goto out;
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
+    rv = 0; /* module not found */
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
-    if (!success) {
Bernhard M. Wiedemann 399b1f
+out:
Bernhard M. Wiedemann 399b1f
+    if (rv <= 0) {
Bernhard M. Wiedemann 399b1f
         g_hash_table_remove(loaded_modules, module_name);
Bernhard M. Wiedemann 399b1f
         g_free(module_name);
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
-
Bernhard M. Wiedemann 399b1f
     for (i = 0; i < n_dirs; i++) {
Bernhard M. Wiedemann 399b1f
         g_free(dirs[i]);
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
-
Bernhard M. Wiedemann 399b1f
-#endif
Bernhard M. Wiedemann 399b1f
-    return success;
Bernhard M. Wiedemann 399b1f
+    return rv;
Bernhard M. Wiedemann 399b1f
 }
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
-#ifdef CONFIG_MODULES
Bernhard M. Wiedemann 399b1f
-
Bernhard M. Wiedemann 399b1f
 static bool module_loaded_qom_all;
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
-void module_load_qom(const char *type)
Bernhard M. Wiedemann 399b1f
+int module_load_qom(const char *type, Error **errp)
Bernhard M. Wiedemann 399b1f
 {
Bernhard M. Wiedemann 399b1f
     const QemuModinfo *modinfo;
Bernhard M. Wiedemann 399b1f
     const char **sl;
Bernhard M. Wiedemann 399b1f
+    int rv = 0;
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
     if (!type) {
Bernhard M. Wiedemann 399b1f
-        return;
Bernhard M. Wiedemann 399b1f
+        error_setg(errp, "%s", "type is NULL");
Bernhard M. Wiedemann 399b1f
+        return -1;
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
     trace_module_lookup_object_type(type);
Bernhard M. Wiedemann 399b1f
@@ -331,15 +337,24 @@ void module_load_qom(const char *type)
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
         for (sl = modinfo->objs; *sl != NULL; sl++) {
Bernhard M. Wiedemann 399b1f
             if (strcmp(type, *sl) == 0) {
Bernhard M. Wiedemann 399b1f
-                module_load("", modinfo->name);
Bernhard M. Wiedemann 399b1f
+                if (rv > 0) {
Bernhard M. Wiedemann 399b1f
+                    error_setg(errp, "multiple modules providing '%s'", type);
Bernhard M. Wiedemann 399b1f
+                    return -1;
Bernhard M. Wiedemann 399b1f
+                }
Bernhard M. Wiedemann 399b1f
+                rv = module_load("", modinfo->name, errp);
Bernhard M. Wiedemann 399b1f
+                if (rv < 0) {
Bernhard M. Wiedemann 399b1f
+                    return rv;
Bernhard M. Wiedemann 399b1f
+                }
Bernhard M. Wiedemann 399b1f
             }
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
+    return rv;
Bernhard M. Wiedemann 399b1f
 }
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
 void module_load_qom_all(void)
Bernhard M. Wiedemann 399b1f
 {
Bernhard M. Wiedemann 399b1f
     const QemuModinfo *modinfo;
Bernhard M. Wiedemann 399b1f
+    Error *local_err = NULL;
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
     if (module_loaded_qom_all) {
Bernhard M. Wiedemann 399b1f
         return;
Bernhard M. Wiedemann 399b1f
@@ -352,7 +367,9 @@ void module_load_qom_all(void)
Bernhard M. Wiedemann 399b1f
         if (!module_check_arch(modinfo)) {
Bernhard M. Wiedemann 399b1f
             continue;
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
-        module_load("", modinfo->name);
Bernhard M. Wiedemann 399b1f
+        if (module_load("", modinfo->name, &local_err) < 0) {
Bernhard M. Wiedemann 399b1f
+            error_report_err(local_err);
Bernhard M. Wiedemann 399b1f
+        }
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
     module_loaded_qom_all = true;
Bernhard M. Wiedemann 399b1f
 }
Bernhard M. Wiedemann 399b1f
@@ -368,7 +385,10 @@ void qemu_load_module_for_opts(const char *group)
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
         for (sl = modinfo->opts; *sl != NULL; sl++) {
Bernhard M. Wiedemann 399b1f
             if (strcmp(group, *sl) == 0) {
Bernhard M. Wiedemann 399b1f
-                module_load("", modinfo->name);
Bernhard M. Wiedemann 399b1f
+                Error *local_err = NULL;
Bernhard M. Wiedemann 399b1f
+                if (module_load("", modinfo->name, &local_err) < 0) {
Bernhard M. Wiedemann 399b1f
+                    error_report_err(local_err);
Bernhard M. Wiedemann 399b1f
+                }
Bernhard M. Wiedemann 399b1f
             }
Bernhard M. Wiedemann 399b1f
         }
Bernhard M. Wiedemann 399b1f
     }
Bernhard M. Wiedemann 399b1f
@@ -378,7 +398,8 @@ void qemu_load_module_for_opts(const char *group)
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
 void module_allow_arch(const char *arch) {}
Bernhard M. Wiedemann 399b1f
 void qemu_load_module_for_opts(const char *group) {}
Bernhard M. Wiedemann 399b1f
-void module_load_qom(const char *type) {}
Bernhard M. Wiedemann 399b1f
+int module_load(const char *prefix, const char *name, Error **errp) { return 2; }
Bernhard M. Wiedemann 399b1f
+int module_load_qom(const char *type, Error **errp) { return 2; }
Bernhard M. Wiedemann 399b1f
 void module_load_qom_all(void) {}
Bernhard M. Wiedemann 399b1f
 
Bernhard M. Wiedemann 399b1f
 #endif