|
|
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 |
|