@@ -31,10 +31,13 @@ static int autofs_mount_busy(struct vfsmount *mnt,
{
struct dentry *top = dentry;
struct path path = {.mnt = mnt, .dentry = dentry};
+ unsigned int flags;
int status = 1;
pr_debug("dentry %p %pd\n", dentry, dentry);
+ /* A reference to the mount is held. */
+ flags = TREE_BUSY_REFERENCED;
path_get(&path);
if (!follow_down_one(&path))
@@ -55,7 +58,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, flags)) {
struct autofs_info *ino;
ino = autofs_dentry_ino(top);
@@ -152,14 +155,21 @@ static int autofs_direct_busy(struct vfsmount *mnt,
unsigned long timeout,
unsigned int how)
{
+ unsigned int flags;
+
pr_debug("top %p %pd\n", top, top);
/* Forced expire, user space handles busy mounts */
if (how & AUTOFS_EXP_FORCED)
return 0;
+ /* A mounted direct mount will have an open file handle
+ * associated with it so we need TREE_BUSY_REFERENCED.
+ */
+ flags = TREE_BUSY_REFERENCED;
+
/* If it's busy update the expiry counters */
- if (!may_umount_tree(mnt)) {
+ if (!may_umount_tree(mnt, flags)) {
struct autofs_info *ino;
ino = autofs_dentry_ino(top);
@@ -1431,28 +1431,36 @@ void mnt_cursor_del(struct mnt_namespace *ns, struct mount *cursor)
* open files, pwds, chroots or sub mounts that are
* busy.
*/
-int may_umount_tree(struct vfsmount *m)
+int may_umount_tree(struct vfsmount *m, unsigned int flags)
{
struct mount *mnt = real_mount(m);
- int actual_refs = 0;
- int minimum_refs = 0;
struct mount *p;
+ int ret = 1;
+
BUG_ON(!m);
- /* write lock needed for mnt_get_count */
+ down_read(&namespace_sem);
lock_mount_hash();
- for (p = mnt; p; p = next_mnt(p, mnt)) {
- actual_refs += mnt_get_count(p);
- minimum_refs += 2;
+ if (propagate_mount_tree_busy(mnt, flags)) {
+ ret = 0;
+ goto out;
}
+ /* Only the passed in mount will have a reference held by
+ * the caller.
+ */
+ flags &= ~TREE_BUSY_REFERENCED;
+ for (p = next_mnt(mnt, mnt); p; p = next_mnt(p, mnt)) {
+ if (propagate_mount_tree_busy(p, flags)) {
+ ret = 0;
+ break;
+ }
+ }
+out:
unlock_mount_hash();
+ up_read(&namespace_sem);
- if (actual_refs > minimum_refs)
- return 0;
-
- return 1;
+ return ret;
}
-
EXPORT_SYMBOL(may_umount_tree);
/**
@@ -30,8 +30,6 @@
#define CL_COPY_ALL (CL_COPY_UNBINDABLE | CL_COPY_MNT_NS_FILE)
-#define TREE_BUSY_REFERENCED 0x01
-
static inline void set_mnt_shared(struct mount *mnt)
{
mnt->mnt.mnt_flags &= ~MNT_SHARED_MASK;
@@ -112,7 +112,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 int may_umount_tree(struct vfsmount *m, unsigned int flags);
extern int may_umount(struct vfsmount *);
extern long do_mount(const char *, const char __user *,
const char *, unsigned long, void *);
Change may_umount_tree() (and the associated autofs code) to use the propagate_mount_tree_busy() helper so it also checks if propagated mounts are busy. This avoids unnecessary umount requests being sent to the automount daemon when a mount in another mount namespace is in use when the expire check is done. Signed-off-by: Ian Kent <raven@themaw.net> --- fs/autofs/expire.c | 14 ++++++++++++-- fs/namespace.c | 32 ++++++++++++++++++++------------ fs/pnode.h | 2 -- include/linux/mount.h | 5 ++++- 4 files changed, 36 insertions(+), 17 deletions(-)