modules: load modules from versioned /var/run dir

On upgrades the old .so files usually are replaced. But on the other
hand since a qemu process represents a guest instance it is usually kept
around.

That makes late addition of dynamic features e.g. 'hot-attach of a ceph
disk' fail by trying to load a new version of e.f. block-rbd.so into an
old still running qemu binary.

This adds a fallback to also load modules from a versioned directory in the
temporary /var/run path. That way qemu is providing a way for packaging
to store modules of an upgraded qemu package as needed until the next reboot.

An example how that can then be used in packaging can be seen in:
https://git.launchpad.net/~paelzer/ubuntu/+source/qemu/log/?h=bug-1847361-miss-old-so-on-upgrade-UBUNTU

Fixes: 1847361
Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Message-Id: <20200310145806.18335-2-christian.ehrhardt@canonical.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Christian Ehrhardt 2020-03-10 15:58:06 +01:00 committed by Paolo Bonzini
parent 5b42bc5ce9
commit bd83c861c0
2 changed files with 29 additions and 0 deletions

View file

@ -19,6 +19,9 @@
#endif
#include "qemu/queue.h"
#include "qemu/module.h"
#ifdef CONFIG_MODULE_UPGRADES
#include "qemu-version.h"
#endif
typedef struct ModuleEntry
{
@ -170,6 +173,9 @@ bool module_load_one(const char *prefix, const char *lib_name)
#ifdef CONFIG_MODULES
char *fname = NULL;
char *exec_dir;
#ifdef CONFIG_MODULE_UPGRADES
char *version_dir;
#endif
const char *search_dir;
char *dirs[4];
char *module_name;
@ -201,6 +207,14 @@ bool module_load_one(const char *prefix, const char *lib_name)
dirs[n_dirs++] = g_strdup_printf("%s", CONFIG_QEMU_MODDIR);
dirs[n_dirs++] = g_strdup_printf("%s/..", exec_dir ? : "");
dirs[n_dirs++] = g_strdup_printf("%s", exec_dir ? : "");
#ifdef CONFIG_MODULE_UPGRADES
version_dir = g_strcanon(g_strdup(QEMU_PKGVERSION),
G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "+-.~",
'_');
dirs[n_dirs++] = g_strdup_printf("/var/run/qemu/%s", version_dir);
#endif
assert(n_dirs <= ARRAY_SIZE(dirs));
g_free(exec_dir);