aboutsummaryrefslogtreecommitdiff
path: root/qga
diff options
context:
space:
mode:
authorJean-Louis Dupond <jean-louis@dupond.be>2024-10-02 12:06:35 +0200
committerKonstantin Kostiuk <kkostiuk@redhat.com>2024-12-18 13:14:49 +0200
commit56ef123777b7a29f5b813696a69865d6033c3c78 (patch)
treee436aa1d7c3fcba78d5b0ba7a26a261aa444f271 /qga
parent8032c78e556cd0baec111740a6c636863f9bd7c8 (diff)
downloadqemu-56ef123777b7a29f5b813696a69865d6033c3c78.zip
qemu-56ef123777b7a29f5b813696a69865d6033c3c78.tar.gz
qemu-56ef123777b7a29f5b813696a69865d6033c3c78.tar.bz2
qga: skip bind mounts in fs list
The filesystem list in build_fs_mount_list should skip bind mounts. This because we end up in locking situations when doing fsFreeze. Like mentioned in [1] and [2]. Next to that, the build_fs_mount_list call did a fallback via build_fs_mount_list_from_mtab if mountinfo did not exist. There it skipped bind mounts, but this is broken for newer OS. This as mounts does not return the path of the bind mount but the underlying dev/partition, so S_ISDIR will never return true in dev_major_minor call. This patch simply checks the existing devmajor:devminor tuple in the mounts, and if it already exists, this means we have the same devices mounted again, a bind mount. So skip this. Same approach is used in open-vm-tools [3]. [1]: https://gitlab.com/qemu-project/qemu/-/issues/592 [2]: https://gitlab.com/qemu-project/qemu/-/issues/520 [3]: https://github.com/vmware/open-vm-tools/commit/d58847b497e212737007958c945af1df22a8ab58 Signed-off-by: Jean-Louis Dupond <jean-louis@dupond.be> Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com> Link: https://lore.kernel.org/r/20241002100634.162499-2-jean-louis@dupond.be Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Diffstat (limited to 'qga')
-rw-r--r--qga/commands-linux.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/qga/commands-linux.c b/qga/commands-linux.c
index cf077eb..9e8a934 100644
--- a/qga/commands-linux.c
+++ b/qga/commands-linux.c
@@ -58,6 +58,22 @@ static int dev_major_minor(const char *devpath,
return -1;
}
+/*
+ * Check if we already have the devmajor:devminor in the mounts
+ * If thats the case return true.
+ */
+static bool dev_exists(FsMountList *mounts, unsigned int devmajor, unsigned int devminor)
+{
+ FsMount *mount;
+
+ QTAILQ_FOREACH(mount, mounts, next) {
+ if (mount->devmajor == devmajor && mount->devminor == devminor) {
+ return true;
+ }
+ }
+ return false;
+}
+
static bool build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp)
{
struct mntent *ment;
@@ -88,6 +104,10 @@ static bool build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp)
/* Skip bind mounts */
continue;
}
+ if (dev_exists(mounts, devmajor, devminor)) {
+ /* Skip already existing devices (bind mounts) */
+ continue;
+ }
mount = g_new0(FsMount, 1);
mount->dirname = g_strdup(ment->mnt_dir);
@@ -171,6 +191,11 @@ bool build_fs_mount_list(FsMountList *mounts, Error **errp)
}
}
+ if (dev_exists(mounts, devmajor, devminor)) {
+ /* Skip already existing devices (bind mounts) */
+ continue;
+ }
+
mount = g_new0(FsMount, 1);
mount->dirname = g_strdup(line + dir_s);
mount->devtype = g_strdup(dash + type_s);