Commit cbf6898f authored by Ian Kent's avatar Ian Kent Committed by Linus Torvalds

autofs: add AUTOFS_EXP_FORCED flag

The userspace automount(8) daemon is meant to perform a forced expire when
sent a SIGUSR2.

But since the expiration is routed through the kernel and the kernel
doesn't send an expire request if the mount is busy this hasn't worked at
least since autofs version 5.

Add an AUTOFS_EXP_FORCED flag to allow implemention of the feature and
bump the protocol version so user space can check if it's implemented if
needed.

Link: http://lkml.kernel.org/r/152937734715.21213.6594007182776598970.stgit@pluto.themaw.netSigned-off-by: default avatarIan Kent <raven@themaw.net>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent e5c85e1f
...@@ -29,7 +29,8 @@ static inline int autofs_can_expire(struct dentry *dentry, ...@@ -29,7 +29,8 @@ static inline int autofs_can_expire(struct dentry *dentry,
} }
/* Check a mount point for busyness */ /* Check a mount point for busyness */
static int autofs_mount_busy(struct vfsmount *mnt, struct dentry *dentry) static int autofs_mount_busy(struct vfsmount *mnt,
struct dentry *dentry, unsigned int how)
{ {
struct dentry *top = dentry; struct dentry *top = dentry;
struct path path = {.mnt = mnt, .dentry = dentry}; struct path path = {.mnt = mnt, .dentry = dentry};
...@@ -50,6 +51,12 @@ static int autofs_mount_busy(struct vfsmount *mnt, struct dentry *dentry) ...@@ -50,6 +51,12 @@ static int autofs_mount_busy(struct vfsmount *mnt, struct dentry *dentry)
goto done; goto done;
} }
/* Not a submount, has a forced expire been requested */
if (how & AUTOFS_EXP_FORCED) {
status = 0;
goto done;
}
/* Update the expiry counter if fs is busy */ /* Update the expiry counter if fs is busy */
if (!may_umount_tree(path.mnt)) { if (!may_umount_tree(path.mnt)) {
struct autofs_info *ino; struct autofs_info *ino;
...@@ -189,6 +196,10 @@ static int autofs_direct_busy(struct vfsmount *mnt, ...@@ -189,6 +196,10 @@ static int autofs_direct_busy(struct vfsmount *mnt,
{ {
pr_debug("top %p %pd\n", top, top); pr_debug("top %p %pd\n", top, top);
/* Forced expire, user space handles busy mounts */
if (how & AUTOFS_EXP_FORCED)
return 0;
/* If it's busy update the expiry counters */ /* If it's busy update the expiry counters */
if (!may_umount_tree(mnt)) { if (!may_umount_tree(mnt)) {
struct autofs_info *ino; struct autofs_info *ino;
...@@ -235,7 +246,7 @@ static int autofs_tree_busy(struct vfsmount *mnt, ...@@ -235,7 +246,7 @@ static int autofs_tree_busy(struct vfsmount *mnt,
* If the fs is busy update the expiry counter. * If the fs is busy update the expiry counter.
*/ */
if (d_mountpoint(p)) { if (d_mountpoint(p)) {
if (autofs_mount_busy(mnt, p)) { if (autofs_mount_busy(mnt, p, how)) {
top_ino->last_used = jiffies; top_ino->last_used = jiffies;
dput(p); dput(p);
return 1; return 1;
...@@ -258,6 +269,10 @@ static int autofs_tree_busy(struct vfsmount *mnt, ...@@ -258,6 +269,10 @@ static int autofs_tree_busy(struct vfsmount *mnt,
} }
} }
/* Forced expire, user space handles busy mounts */
if (how & AUTOFS_EXP_FORCED)
return 0;
/* Timeout of a tree mount is ultimately determined by its top dentry */ /* Timeout of a tree mount is ultimately determined by its top dentry */
if (!autofs_can_expire(top, timeout, how)) if (!autofs_can_expire(top, timeout, how))
return 1; return 1;
...@@ -280,9 +295,15 @@ static struct dentry *autofs_check_leaves(struct vfsmount *mnt, ...@@ -280,9 +295,15 @@ static struct dentry *autofs_check_leaves(struct vfsmount *mnt,
if (d_mountpoint(p)) { if (d_mountpoint(p)) {
/* Can we umount this guy */ /* Can we umount this guy */
if (autofs_mount_busy(mnt, p)) if (autofs_mount_busy(mnt, p, how))
continue; continue;
/* This isn't a submount so if a forced expire
* has been requested, user space handles busy
* mounts */
if (how & AUTOFS_EXP_FORCED)
return p;
/* Can we expire this guy */ /* Can we expire this guy */
if (autofs_can_expire(p, timeout, how)) if (autofs_can_expire(p, timeout, how))
return p; return p;
...@@ -361,9 +382,15 @@ static struct dentry *should_expire(struct dentry *dentry, ...@@ -361,9 +382,15 @@ static struct dentry *should_expire(struct dentry *dentry,
pr_debug("checking mountpoint %p %pd\n", dentry, dentry); pr_debug("checking mountpoint %p %pd\n", dentry, dentry);
/* Can we umount this guy */ /* Can we umount this guy */
if (autofs_mount_busy(mnt, dentry)) if (autofs_mount_busy(mnt, dentry, how))
return NULL; return NULL;
/* This isn't a submount so if a forced expire
* has been requested, user space handles busy
* mounts */
if (how & AUTOFS_EXP_FORCED)
return dentry;
/* Can we expire this guy */ /* Can we expire this guy */
if (autofs_can_expire(dentry, timeout, how)) if (autofs_can_expire(dentry, timeout, how))
return dentry; return dentry;
...@@ -372,6 +399,11 @@ static struct dentry *should_expire(struct dentry *dentry, ...@@ -372,6 +399,11 @@ static struct dentry *should_expire(struct dentry *dentry,
if (d_really_is_positive(dentry) && d_is_symlink(dentry)) { if (d_really_is_positive(dentry) && d_is_symlink(dentry)) {
pr_debug("checking symlink %p %pd\n", dentry, dentry); pr_debug("checking symlink %p %pd\n", dentry, dentry);
/* Forced expire, user space handles busy mounts */
if (how & AUTOFS_EXP_FORCED)
return dentry;
/* /*
* A symlink can't be "busy" in the usual sense so * A symlink can't be "busy" in the usual sense so
* just check last used for expire timeout. * just check last used for expire timeout.
...@@ -386,10 +418,13 @@ static struct dentry *should_expire(struct dentry *dentry, ...@@ -386,10 +418,13 @@ static struct dentry *should_expire(struct dentry *dentry,
/* Case 2: tree mount, expire iff entire tree is not busy */ /* Case 2: tree mount, expire iff entire tree is not busy */
if (!(how & AUTOFS_EXP_LEAVES)) { if (!(how & AUTOFS_EXP_LEAVES)) {
/* Path walk currently on this dentry? */ /* Not a forced expire? */
ino_count = atomic_read(&ino->count) + 1; if (!(how & AUTOFS_EXP_FORCED)) {
if (d_count(dentry) > ino_count) /* ref-walk currently on this dentry? */
return NULL; ino_count = atomic_read(&ino->count) + 1;
if (d_count(dentry) > ino_count)
return NULL;
}
if (!autofs_tree_busy(mnt, dentry, timeout, how)) if (!autofs_tree_busy(mnt, dentry, timeout, how))
return dentry; return dentry;
...@@ -398,12 +433,15 @@ static struct dentry *should_expire(struct dentry *dentry, ...@@ -398,12 +433,15 @@ static struct dentry *should_expire(struct dentry *dentry,
* (autofs-4.1). * (autofs-4.1).
*/ */
} else { } else {
/* Path walk currently on this dentry? */
struct dentry *expired; struct dentry *expired;
ino_count = atomic_read(&ino->count) + 1; /* Not a forced expire? */
if (d_count(dentry) > ino_count) if (!(how & AUTOFS_EXP_FORCED)) {
return NULL; /* ref-walk currently on this dentry? */
ino_count = atomic_read(&ino->count) + 1;
if (d_count(dentry) > ino_count)
return NULL;
}
expired = autofs_check_leaves(mnt, dentry, timeout, how); expired = autofs_check_leaves(mnt, dentry, timeout, how);
if (expired) { if (expired) {
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#define AUTOFS_MIN_PROTO_VERSION 3 #define AUTOFS_MIN_PROTO_VERSION 3
#define AUTOFS_MAX_PROTO_VERSION 5 #define AUTOFS_MAX_PROTO_VERSION 5
#define AUTOFS_PROTO_SUBVERSION 2 #define AUTOFS_PROTO_SUBVERSION 3
/* /*
* The wait_queue_token (autofs_wqt_t) is part of a structure which is passed * The wait_queue_token (autofs_wqt_t) is part of a structure which is passed
...@@ -90,8 +90,10 @@ enum { ...@@ -90,8 +90,10 @@ enum {
/* autofs version 4 and later definitions */ /* autofs version 4 and later definitions */
/* Mask for expire behaviour */ /* Mask for expire behaviour */
#define AUTOFS_EXP_IMMEDIATE 1 #define AUTOFS_EXP_NORMAL 0x00
#define AUTOFS_EXP_LEAVES 2 #define AUTOFS_EXP_IMMEDIATE 0x01
#define AUTOFS_EXP_LEAVES 0x02
#define AUTOFS_EXP_FORCED 0x04
#define AUTOFS_TYPE_ANY 0U #define AUTOFS_TYPE_ANY 0U
#define AUTOFS_TYPE_INDIRECT 1U #define AUTOFS_TYPE_INDIRECT 1U
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment