Blame SOURCES/ovt-Track-Linux-filesystem-id-FSID-for-quiesced-frozen-f.patch

79b9e8
From 88826c7f64f3180711943b5311c4414d4b1dc1d1 Mon Sep 17 00:00:00 2001
79b9e8
From: Katy Feng <fkaty@vmware.com>
79b9e8
Date: Tue, 17 Jan 2023 19:08:33 -0800
79b9e8
Subject: [PATCH] Track Linux filesystem id (FSID) for quiesced (frozen)
79b9e8
 filesystems
79b9e8
79b9e8
RH-Author: Ani Sinha <None>
79b9e8
RH-MergeRequest: 14: Track Linux filesystem id (FSID) for quiesced (frozen) filesystems
79b9e8
RH-Bugzilla: 1880404 1994590
79b9e8
RH-Acked-by: Cathy Avery <cavery@redhat.com>
79b9e8
RH-Commit: [1/1] c4ed73561eba36e7112cf96384f0c28f28489934
79b9e8
79b9e8
Tracking the filesystem FSID along with each file descriptor (FD)
79b9e8
as the ioctl FIFREEZE is done.  An EBUSY could be seen because of
79b9e8
an attempt to freeze the same superblock more than once depending
79b9e8
on the OS configuration (e.g. usage of bind mounts).  An EBUSY could
79b9e8
also mean another process has locked or frozen that filesystem.
79b9e8
79b9e8
When an EBUSY is received, the filesyste FSID is checked against the
79b9e8
list of filesystems that have already be quiesced.  If not previously
79b9e8
seen, a warning that the filesystem is controlled by another process
79b9e8
is logged and the quiesced snapshot request will be rejected.
79b9e8
79b9e8
(cherry picked from commit 9d458c53a7a656d4d1ba3a28d090cce82ac4af0e)
79b9e8
Signed-off-by: Ani Sinha <anisinha@redhat.com>
79b9e8
---
79b9e8
 .../lib/syncDriver/syncDriverLinux.c          | 112 +++++++++++++++---
79b9e8
 1 file changed, 96 insertions(+), 16 deletions(-)
79b9e8
79b9e8
diff --git a/open-vm-tools/lib/syncDriver/syncDriverLinux.c b/open-vm-tools/lib/syncDriver/syncDriverLinux.c
79b9e8
index eef65a2e..6d9a3568 100644
79b9e8
--- a/open-vm-tools/lib/syncDriver/syncDriverLinux.c
79b9e8
+++ b/open-vm-tools/lib/syncDriver/syncDriverLinux.c
79b9e8
@@ -1,5 +1,5 @@
79b9e8
 /*********************************************************
79b9e8
- * Copyright (C) 2011-2018 VMware, Inc. All rights reserved.
79b9e8
+ * Copyright (C) 2011-2018, 2023 VMware, Inc. All rights reserved.
79b9e8
  *
79b9e8
  * This program is free software; you can redistribute it and/or modify it
79b9e8
  * under the terms of the GNU Lesser General Public License as published
79b9e8
@@ -32,6 +32,7 @@
79b9e8
 #include <sys/ioctl.h>
79b9e8
 #include <sys/types.h>
79b9e8
 #include <sys/stat.h>
79b9e8
+#include <sys/statfs.h>
79b9e8
 #include "debug.h"
79b9e8
 #include "dynbuf.h"
79b9e8
 #include "syncDriverInt.h"
79b9e8
@@ -43,12 +44,53 @@
79b9e8
 #endif
79b9e8
 
79b9e8
 
79b9e8
+
79b9e8
+typedef struct LinuxFsInfo {
79b9e8
+   int fd;
79b9e8
+   fsid_t fsid;
79b9e8
+} LinuxFsInfo;
79b9e8
+
79b9e8
 typedef struct LinuxDriver {
79b9e8
    SyncHandle  driver;
79b9e8
    size_t      fdCnt;
79b9e8
-   int        *fds;
79b9e8
+   LinuxFsInfo *fds;
79b9e8
 } LinuxDriver;
79b9e8
 
79b9e8
+static
79b9e8
+const fsid_t MISSING_FSID = {};
79b9e8
+
79b9e8
+
79b9e8
+/*
79b9e8
+ *******************************************************************************
79b9e8
+ * LinuxFiFsIdMatch --
79b9e8
+ *
79b9e8
+ * Check the collection of filesystems previously frozen for the specific
79b9e8
+ * FSID.
79b9e8
+ *
79b9e8
+ * @param[in] fds    List of LinuxFsInfo data for filesystems previously
79b9e8
+ *                   frozen.
79b9e8
+ * @param[in] count  Number of fds in the list.
79b9e8
+ * @param[in] nfsid  The Filesystem ID of interest.
79b9e8
+ *
79b9e8
+ * @return TRUE if the FSID matches one previously processed.  Otherwise FALSE
79b9e8
+ *
79b9e8
+ *******************************************************************************
79b9e8
+ */
79b9e8
+
79b9e8
+static Bool
79b9e8
+LinuxFiFsIdMatch(const LinuxFsInfo *fds,
79b9e8
+                 const size_t count,
79b9e8
+                 const fsid_t *nfsid) {
79b9e8
+   size_t i;
79b9e8
+
79b9e8
+   for (i = 0; i < count; i++) {
79b9e8
+      if (fds[i].fsid.__val[0] == nfsid->__val[0] &&
79b9e8
+          fds[i].fsid.__val[1] == nfsid->__val[1]) {
79b9e8
+         return TRUE;
79b9e8
+      }
79b9e8
+   }
79b9e8
+   return FALSE;
79b9e8
+}
79b9e8
 
79b9e8
 /*
79b9e8
  *******************************************************************************
79b9e8
@@ -75,9 +117,11 @@ LinuxFiThaw(const SyncDriverHandle handle)
79b9e8
     * Thaw in the reverse order of freeze
79b9e8
     */
79b9e8
    for (i = sync->fdCnt; i > 0; i--) {
79b9e8
-      Debug(LGPFX "Thawing fd=%d.\n", sync->fds[i-1]);
79b9e8
-      if (ioctl(sync->fds[i-1], FITHAW) == -1) {
79b9e8
-         Debug(LGPFX "Thaw failed for fd=%d.\n", sync->fds[i-1]);
79b9e8
+      int fd = sync->fds[i-1].fd;
79b9e8
+
79b9e8
+      Debug(LGPFX "Thawing fd=%d.\n", fd);
79b9e8
+      if (ioctl(fd, FITHAW) == -1) {
79b9e8
+         Debug(LGPFX "Thaw failed for fd=%d.\n", fd);
79b9e8
          err = SD_ERROR;
79b9e8
       }
79b9e8
    }
79b9e8
@@ -108,8 +152,10 @@ LinuxFiClose(SyncDriverHandle handle)
79b9e8
     * Close in the reverse order of open
79b9e8
     */
79b9e8
    for (i = sync->fdCnt; i > 0; i--) {
79b9e8
-      Debug(LGPFX "Closing fd=%d.\n", sync->fds[i-1]);
79b9e8
-      close(sync->fds[i-1]);
79b9e8
+      int fd = sync->fds[i-1].fd;
79b9e8
+
79b9e8
+      Debug(LGPFX "Closing fd=%d.\n", fd);
79b9e8
+      close(fd);
79b9e8
    }
79b9e8
    free(sync->fds);
79b9e8
    free(sync);
79b9e8
@@ -196,8 +242,11 @@ LinuxDriver_Freeze(const GSList *paths,
79b9e8
     */
79b9e8
    while (paths != NULL) {
79b9e8
       int fd;
79b9e8
+      LinuxFsInfo fsInfo;
79b9e8
       struct stat sbuf;
79b9e8
+      struct statfs fsbuf;
79b9e8
       const char *path = paths->data;
79b9e8
+
79b9e8
       Debug(LGPFX "opening path '%s'.\n", path);
79b9e8
       paths = g_slist_next(paths);
79b9e8
       fd = open(path, O_RDONLY);
79b9e8
@@ -258,23 +307,53 @@ LinuxDriver_Freeze(const GSList *paths,
79b9e8
          continue;
79b9e8
       }
79b9e8
 
79b9e8
+      if (fstatfs(fd, &fsbuf) == 0) {
79b9e8
+         fsInfo.fsid = fsbuf.f_fsid;
79b9e8
+      } else {
79b9e8
+         Debug(LGPFX "failed to get file system id for path '%s'.\n", path);
79b9e8
+         fsInfo.fsid = MISSING_FSID;
79b9e8
+      }
79b9e8
       Debug(LGPFX "freezing path '%s' (fd=%d).\n", path, fd);
79b9e8
       if (ioctl(fd, FIFREEZE) == -1) {
79b9e8
          int ioctlerr = errno;
79b9e8
+
79b9e8
+         close(fd);
79b9e8
+         Debug(LGPFX "freeze on '%s' returned: %d (%s)\n",
79b9e8
+               path, ioctlerr, strerror(ioctlerr));
79b9e8
+         /*
79b9e8
+          * Previously, an EBUSY error was ignored, assuming that we may try
79b9e8
+          * to freeze the same superblock more than once depending on the
79b9e8
+          * OS configuration (e.g., usage of bind mounts).
79b9e8
+          * Using the filesystem Id to check if this is a filesystem that we
79b9e8
+          * have seen previously and will ignore this FD only if that is
79b9e8
+          * the case.  Log a warning otherwise since the quiesced snapshot
79b9e8
+          * attempt will fail.
79b9e8
+          */
79b9e8
+         if (ioctlerr == EBUSY) {
79b9e8
+            if (LinuxFiFsIdMatch(DynBuf_Get(&fds),
79b9e8
+                                 DynBuf_GetSize(&fds),
79b9e8
+                                 &fsInfo.fsid)) {
79b9e8
+               /*
79b9e8
+                * We have previous knowledge of this file system by another
79b9e8
+                * mount point.  Safe to ignore.
79b9e8
+                */
79b9e8
+               Debug(LGPFX "skipping path '%s' - previously frozen", path);
79b9e8
+               continue;
79b9e8
+            }
79b9e8
+            /*
79b9e8
+             * It appears that this FS has been locked or frozen by another
79b9e8
+             * process.  We cannot proceed with the quiesced snapshot request.
79b9e8
+             */
79b9e8
+            Warning(LGPFX "'%s' appears locked or frozen by another process.  "
79b9e8
+                    "Cannot complete the quiesced snapshot request.\n", path);
79b9e8
+         }
79b9e8
          /*
79b9e8
           * If the ioctl does not exist, Linux will return ENOTTY. If it's not
79b9e8
           * supported on the device, we get EOPNOTSUPP. Ignore the latter,
79b9e8
           * since freezing does not make sense for all fs types, and some
79b9e8
           * Linux fs drivers may not have been hooked up in the running kernel.
79b9e8
-          *
79b9e8
-          * Also ignore EBUSY since we may try to freeze the same superblock
79b9e8
-          * more than once depending on the OS configuration (e.g., usage of
79b9e8
-          * bind mounts).
79b9e8
           */
79b9e8
-         close(fd);
79b9e8
-         Debug(LGPFX "freeze on '%s' returned: %d (%s)\n",
79b9e8
-               path, ioctlerr, strerror(ioctlerr));
79b9e8
-         if (ioctlerr != EBUSY && ioctlerr != EOPNOTSUPP) {
79b9e8
+         if (ioctlerr != EOPNOTSUPP) {
79b9e8
             Debug(LGPFX "failed to freeze '%s': %d (%s)\n",
79b9e8
                   path, ioctlerr, strerror(ioctlerr));
79b9e8
             err = first && ioctlerr == ENOTTY ? SD_UNAVAILABLE : SD_ERROR;
79b9e8
@@ -282,7 +361,8 @@ LinuxDriver_Freeze(const GSList *paths,
79b9e8
          }
79b9e8
       } else {
79b9e8
          Debug(LGPFX "successfully froze '%s' (fd=%d).\n", path, fd);
79b9e8
-         if (!DynBuf_Append(&fds, &fd, sizeof fd)) {
79b9e8
+         fsInfo.fd = fd;
79b9e8
+         if (!DynBuf_Append(&fds, &fsInfo, sizeof fsInfo)) {
79b9e8
             if (ioctl(fd, FITHAW) == -1) {
79b9e8
                Warning(LGPFX "failed to thaw '%s': %d (%s)\n",
79b9e8
                        path, errno, strerror(errno));
79b9e8
-- 
79b9e8
2.39.1
79b9e8