]> git-server-git.apps.pok.os.sepia.ceph.com Git - xfsprogs-dev.git/commitdiff
xfs_healer: use getmntent to find moved filesystems
authorDarrick J. Wong <djwong@kernel.org>
Sun, 22 Feb 2026 22:41:16 +0000 (14:41 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Thu, 9 Apr 2026 22:30:17 +0000 (15:30 -0700)
It's possible that a mounted filesystem can move mountpoints between the
time of the initial mount (at which point xfs_healer starts) and when
it actually wants to start a repair.  When this happens,
weakhandle::mountpoint becomes obsolete and opening it will either fail
with ENOENT or the handle revalidation will return ESTALE.

However, we do still have a means to find the mounted filesystem -- the
fsname parameter (aka the path to the data device at mount time).  This
is record in /proc/mounts, which means that we can iterate getmntent to
see if we can find the mount elsewhere.

As documented a few patches ago, this would be easier if we had
revocable fds that didn't pin mounts, but that's a very huge ask.

This getmntent code enables xfs_healer to find a filesystem that has
been bind mounted in a new place and the original mountpoint detached:

# mount /dev/sda /mnt
# xfs_healer /mnt &
# mount /mnt /opt --bind
# umount /mnt

The key here is that each bind mount gets a separate struct mount
object.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
healer/weakhandle.c

index 849aa2882700d463a3953952204db8904fa9d6aa..5df5207514e38e4cafcfc9d7ed2ed377eceff028 100644 (file)
@@ -65,10 +65,14 @@ out_wh:
        return -1;
 }
 
-/* Reopen a file handle obtained via weak reference. */
-int
-weakhandle_reopen(
+/*
+ * Reopen a file handle obtained via weak reference, using the given path to a
+ * mount point.
+ */
+static int
+weakhandle_reopen_from(
        struct weakhandle       *wh,
+       const char              *path,
        int                     *fd)
 {
        void                    *hanp;
@@ -78,7 +82,7 @@ weakhandle_reopen(
 
        *fd = -1;
 
-       mnt_fd = open(wh->mntpoint, O_RDONLY);
+       mnt_fd = open(path, O_RDONLY);
        if (mnt_fd < 0)
                return -1;
 
@@ -102,6 +106,49 @@ out_mntfd:
        return -1;
 }
 
+/* Reopen a file handle obtained via weak reference. */
+int
+weakhandle_reopen(
+       struct weakhandle       *wh,
+       int                     *fd)
+{
+       FILE                    *mtab;
+       struct mntent           *mnt;
+       int                     ret;
+
+       /* First try reopening using the original mountpoint */
+       ret = weakhandle_reopen_from(wh, wh->mntpoint, fd);
+       if (!ret)
+               return 0;
+
+       /*
+        * That didn't work, so now walk /proc/mounts to find a mount with the
+        * same fsname (aka xfs data device path) as when we started.
+        */
+       mtab = setmntent(_PATH_PROC_MOUNTS, "r");
+       if (!mtab)
+               return -1;
+
+       while ((mnt = getmntent(mtab)) != NULL) {
+               if (strcmp(mnt->mnt_type, "xfs"))
+                       continue;
+               if (strcmp(mnt->mnt_fsname, wh->fsname))
+                       continue;
+
+               ret = weakhandle_reopen_from(wh, mnt->mnt_dir, fd);
+               if (!ret)
+                       break;
+       }
+
+       if (*fd < 0) {
+               errno = ESTALE;
+               ret = -1;
+       }
+
+       endmntent(mtab);
+       return ret;
+}
+
 /* Tear down a weak handle */
 void
 weakhandle_free(