Re: [PATCHES v2][RFC][CFR] mount-related stuff

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

 



On 24/6/25 02:55, Al Viro wrote:
On Mon, Jun 23, 2025 at 05:06:52PM +0800, Ian Kent wrote:

I also have revived my patch to make may_umount_tree() namespace aware

and it still seems to work fine.
Could you post it?


Not sure the formatting will be ok since my email setup is a mess.

It's against the v1 of your series.


Your advice (and Christian and others) would be much appreciated.


vfs: make may_umount_tree() mount namespace aware

From: Ian Kent <ikent@xxxxxxxxxx>

Change may_umount_tree() to also check if propagated mounts are busy
during autofs expire runs.

Also alter may_umount_tree() to take a flag to indicate a reference to
the passed in mount is held.

This avoids unnecessary umount requests being sent to the automount
daemon if a mount in another mount namespace is in use when the expire
check is done.

Signed-off-by: Ian Kent <raven@xxxxxxxxxx>
---
 fs/autofs/expire.c    |    4 ++--
 fs/namespace.c        |   36 ++++++++++++++++++++++++++++++------
 fs/pnode.c            |   32 ++++++++++++++++++++++++++++++++
 fs/pnode.h            |    1 +
 include/linux/mount.h |    5 ++++-
 5 files changed, 69 insertions(+), 9 deletions(-)

diff --git a/fs/autofs/expire.c b/fs/autofs/expire.c
index 5c2d459e1e48..c303d11f4c12 100644
--- a/fs/autofs/expire.c
+++ b/fs/autofs/expire.c
@@ -55,7 +55,7 @@ static int autofs_mount_busy(struct vfsmount *mnt,
     }

     /* Update the expiry counter if fs is busy */
-    if (!may_umount_tree(path.mnt)) {
+    if (!may_umount_tree(path.mnt, TREE_BUSY_REFERENCED)) {
         struct autofs_info *ino;

         ino = autofs_dentry_ino(top);
@@ -156,7 +156,7 @@ static int autofs_direct_busy(struct vfsmount *mnt,
         return 0;

     /* If it's busy update the expiry counters */
-    if (!may_umount_tree(mnt)) {
+    if (!may_umount_tree(mnt, TREE_BUSY_REFERENCED)) {
         struct autofs_info *ino;

         ino = autofs_dentry_ino(top);
diff --git a/fs/namespace.c b/fs/namespace.c
index bb95e5102916..3cb90bb46b94 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1635,25 +1635,49 @@ const struct seq_operations mounts_op = {
 /**
  * may_umount_tree - check if a mount tree is busy
  * @m: root of mount tree
+ * @flags: behaviour modifier flags:
+ *     TREE_BUSY_REFERENCED caller holds additional reference
+ *     to @m.
  *
  * This is called to check if a tree of mounts has any
  * open files, pwds, chroots or sub mounts that are
  * busy.
  */
-int may_umount_tree(struct vfsmount *m)
+bool may_umount_tree(struct vfsmount *m, unsigned int flags)
 {
     struct mount *mnt = real_mount(m);
+    struct mount *p, *q;
     bool busy = false;

-    /* write lock needed for mnt_get_count */
+    down_read(&namespace_sem);
     lock_mount_hash();
-    for (struct mount *p = mnt; p; p = next_mnt(p, mnt)) {
-        if (mnt_get_count(p) > (p == mnt ? 2 : 1)) {
-            busy = true;
-            break;
+    for (p = mnt; p; p = next_mnt(p, mnt)) {
+        unsigned int f = 0;
+
+        if (p->mnt_mountpoint != mnt->mnt.mnt_root) {
+            if (p == mnt)
+                f = flags;
+            if (propagate_mount_tree_busy(p, f)) {
+                busy = true;
+                break;
+            }
+            continue;
+        }
+
+        /* p is a covering mnt, need to check if p or any of its
+         * children are in use. A reference to p is not held so
+         * don't pass TREE_BUSY_REFERENCED to the propagation
+         * helper.
+         */
+        for (q = p; q; q = next_mnt(q, p)) {
+            if (propagate_mount_tree_busy(q, f)) {
+                busy = true;
+                break;
+            }
         }
     }
     unlock_mount_hash();
+    up_read(&namespace_sem);

     return !busy;
 }
diff --git a/fs/pnode.c b/fs/pnode.c
index efed6bb20c72..e4222a008039 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -429,6 +429,38 @@ int propagate_mount_busy(struct mount *mnt, int refcnt)
     return 0;
 }

+/*
+ * Check if the mount tree at 'mnt' is in use or any of its
+ * propogated mounts are in use.
+ * @mnt: the mount to be checked
+ * @flags: see may_umount_tree() for modifier descriptions.
+ *
+ * Check if mnt or any of its propogated mounts have a reference
+ * count greater than the minimum reference count (ie. are in use).
+ */
+int propagate_mount_tree_busy(struct mount *mnt, unsigned int flags)
+{
+    struct mount *m;
+    struct mount *parent = mnt->mnt_parent;
+    int refcnt = flags & TREE_BUSY_REFERENCED ? 2 : 1;
+
+    if (do_refcount_check(mnt, refcnt))
+        return 1;
+
+    for (m = propagation_next(parent, parent); m;
+            m = propagation_next(m, parent)) {
+        struct mount *child;
+
+        child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint);
+        if (!child)
+            continue;
+
+        if (do_refcount_check(child, 1))
+            return 1;
+    }
+    return 0;
+}
+
 /*
  * Clear MNT_LOCKED when it can be shown to be safe.
  *
diff --git a/fs/pnode.h b/fs/pnode.h
index bfc10c095cbf..a0d2974e57d7 100644
--- a/fs/pnode.h
+++ b/fs/pnode.h
@@ -46,6 +46,7 @@ int propagate_mnt(struct mount *, struct mountpoint *, struct mount *,
         struct hlist_head *);
 void propagate_umount(struct list_head *);
 int propagate_mount_busy(struct mount *, int);
+int propagate_mount_tree_busy(struct mount *, unsigned int);
 void propagate_mount_unlock(struct mount *);
 void mnt_release_group_id(struct mount *);
 int get_dominating_id(struct mount *mnt, const struct path *root);
diff --git a/include/linux/mount.h b/include/linux/mount.h
index cae7324650b6..d66555cc8e96 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -114,7 +114,10 @@ extern bool our_mnt(struct vfsmount *mnt);

 extern struct vfsmount *kern_mount(struct file_system_type *);
 extern void kern_unmount(struct vfsmount *mnt);
-extern int may_umount_tree(struct vfsmount *);
+
+#define TREE_BUSY_REFERENCED        0x01
+
+extern bool may_umount_tree(struct vfsmount *, unsigned int);
 extern int may_umount(struct vfsmount *);
 int do_mount(const char *, const char __user *,
              const char *, unsigned long, void *);





[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux