qemu-devel
[Top][All Lists]
Advanced

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

[PATCH 3/5] qga: Add UFS freeze/thaw support for FreeBSD


From: Alexander Ivanov
Subject: [PATCH 3/5] qga: Add UFS freeze/thaw support for FreeBSD
Date: Thu, 22 Sep 2022 15:19:59 +0200

UFS supports FS freezing through ioctl UFSSUSPEND on /dev/ufssuspend.
Freezed FS can be thawed by closing /dev/ufssuspend file descriptior.

Use getmntinfo to get a list of mounted FS.

Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
---
 qga/commands-bsd.c    | 109 +++++++++++++++++++++++++++++++++++++++---
 qga/commands-common.h |  11 +++++
 qga/main.c            |   6 +++
 3 files changed, 120 insertions(+), 6 deletions(-)

diff --git a/qga/commands-bsd.c b/qga/commands-bsd.c
index c1e3ed13e9..5d3f46804a 100644
--- a/qga/commands-bsd.c
+++ b/qga/commands-bsd.c
@@ -17,28 +17,125 @@
 #include "qemu/queue.h"
 #include "commands-common.h"
 
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
+#include <paths.h>
+
 #if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
 bool build_fs_mount_list(FsMountList *mounts, Error **errp)
 {
-    error_setg(errp, QERR_UNSUPPORTED);
-    return false;
+    FsMount *mount;
+    struct statfs *mntbuf, *mntp;
+    struct stat statbuf;
+    int i, count, ret;
+
+    count = getmntinfo(&mntbuf, MNT_NOWAIT);
+    if (count == 0) {
+        error_setg_errno(errp, errno, "getmntinfo failed");
+        return false;
+    }
+
+    for (i = 0; i < count; i++) {
+        mntp = &mntbuf[i];
+        ret = stat(mntp->f_mntonname, &statbuf);
+        if (ret != 0) {
+            continue;
+        }
+
+        mount = g_new0(FsMount, 1);
+
+        mount->dirname = g_strdup(mntp->f_mntonname);
+        mount->devtype = g_strdup(mntp->f_fstypename);
+        mount->devmajor = major(mount->dev);
+        mount->devminor = minor(mount->dev);
+        mount->fsid = mntp->f_fsid;
+        mount->dev = statbuf.st_dev;
+
+        QTAILQ_INSERT_TAIL(mounts, mount, next);
+    }
+    return true;
 }
 #endif
 
 #if defined(CONFIG_FSFREEZE)
+static int ufssuspend_fd = -1;
+static int ufssuspend_cnt;
+
 int64_t qmp_guest_fsfreeze_do_freeze_list(bool has_mountpoints,
                                           strList *mountpoints,
                                           FsMountList mounts,
                                           Error **errp)
 {
-    error_setg(errp, QERR_UNSUPPORTED);
-    return 0;
+    int ret;
+    strList *list;
+    struct FsMount *mount;
+
+    if (ufssuspend_fd != -1) {
+        error_setg(errp, "filesystems have already frozen");
+        return -1;
+    }
+
+    ufssuspend_cnt = 0;
+    ufssuspend_fd = qemu_open(_PATH_UFSSUSPEND, O_RDWR, errp);
+    if (ufssuspend_fd == -1) {
+        return -1;
+    }
+
+    QTAILQ_FOREACH_REVERSE(mount, &mounts, next) {
+        /*
+         * To issue fsfreeze in the reverse order of mounts, check if the
+         * mount is listed in the list here
+         */
+        if (has_mountpoints) {
+            for (list = mountpoints; list; list = list->next) {
+                if (strcmp(list->value, mount->dirname) == 0) {
+                    break;
+                }
+            }
+            if (!list) {
+                continue;
+            }
+        }
+
+        /* Only UFS supports suspend */
+        if (strcmp(mount->devtype, "ufs") != 0) {
+            continue;
+        }
+
+        ret = ioctl(ufssuspend_fd, UFSSUSPEND, &mount->fsid);
+        if (ret == -1) {
+            /*
+             * ioctl returns EBUSY for all the FS except the first one
+             * that was suspended
+             */
+            if (errno == EBUSY) {
+                continue;
+            }
+            error_setg_errno(errp, errno, "failed to freeze %s",
+                             mount->dirname);
+            goto error;
+        }
+        ufssuspend_cnt++;
+    }
+    return ufssuspend_cnt;
+error:
+    close(ufssuspend_fd);
+    ufssuspend_fd = -1;
+    return -1;
+
 }
 
 int qmp_guest_fsfreeze_do_thaw(Error **errp)
 {
-    error_setg(errp, QERR_UNSUPPORTED);
-    return 0;
+    int ret = ufssuspend_cnt;
+    ufssuspend_cnt = 0;
+    if (ufssuspend_fd != -1) {
+        close(ufssuspend_fd);
+        ufssuspend_fd = -1;
+    }
+    return ret;
 }
 #endif
 
diff --git a/qga/commands-common.h b/qga/commands-common.h
index aa0472ea4c..c3be6db3a9 100644
--- a/qga/commands-common.h
+++ b/qga/commands-common.h
@@ -41,11 +41,22 @@ void ga_wait_child(pid_t pid, int *status, Error **errp);
 #endif
 #endif /* __linux__*/
 
+#ifdef __FreeBSD__
+#include <ufs/ffs/fs.h>
+#ifdef UFSSUSPEND
+#define CONFIG_FSFREEZE
+#endif
+#endif /* __FreeBSD__ */
+
 #if defined(CONFIG_FSFREEZE) || defined(CONFIG_FSTRIM)
 typedef struct FsMount {
     char *dirname;
     char *devtype;
     unsigned int devmajor, devminor;
+#if defined(__FreeBSD__)
+    dev_t dev;
+    fsid_t fsid;
+#endif
     QTAILQ_ENTRY(FsMount) next;
 } FsMount;
 
diff --git a/qga/main.c b/qga/main.c
index 22b3c0df11..ab420051fb 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -43,6 +43,12 @@
 #define CONFIG_FSFREEZE
 #endif
 #endif
+#ifdef __FreeBSD__
+#include <ufs/ffs/fs.h>
+#ifdef UFSSUSPEND
+#define CONFIG_FSFREEZE
+#endif
+#endif
 
 #ifndef _WIN32
 #ifdef __FreeBSD__
-- 
2.34.1




reply via email to

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