* [RFC PATCH 1/8] vfs - change d_manage() to take a struct path
2016-10-03 0:46 [RFC PATCH 0/8] Patch series to fix autofs unreliable usage of d_mountpoint() Ian Kent
@ 2016-10-03 0:46 ` Ian Kent
2016-10-03 0:46 ` [RFC PATCH 2/8] vfs - add path_is_mountpoint() helper Ian Kent
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ian Kent @ 2016-10-03 0:46 UTC (permalink / raw)
To: Kernel Mailing List
Cc: autofs mailing list, Al Viro, linux-fsdevel, Omar Sandoval,
Andrew Morton, Eric W. Biederman
For the autofs module to be able to reliably check if a dentry is a
mountpoint in a multiple namespace environment the ->d_manage() dentry
operation will need to take a path argument instead of a dentry.
Signed-off-by: Ian Kent <raven@themaw.net>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Omar Sandoval <osandov@osandov.com>
---
Documentation/filesystems/Locking | 2 +-
Documentation/filesystems/vfs.txt | 2 +-
fs/autofs4/root.c | 5 +++--
fs/namei.c | 13 ++++++-------
include/linux/dcache.h | 2 +-
5 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index d30fb2c..189ea98 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -20,7 +20,7 @@ prototypes:
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
struct vfsmount *(*d_automount)(struct path *path);
- int (*d_manage)(struct dentry *, bool);
+ int (*d_manage)(struct path *, bool);
struct dentry *(*d_real)(struct dentry *, const struct inode *,
unsigned int);
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 9ace359..0035ac8 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -939,7 +939,7 @@ struct dentry_operations {
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *);
- int (*d_manage)(struct dentry *, bool);
+ int (*d_manage)(struct path *, bool);
struct dentry *(*d_real)(struct dentry *, const struct inode *,
unsigned int);
};
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index fa84bb8..0705daa 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -32,7 +32,7 @@ static int autofs4_dir_open(struct inode *inode, struct file *file);
static struct dentry *autofs4_lookup(struct inode *,
struct dentry *, unsigned int);
static struct vfsmount *autofs4_d_automount(struct path *);
-static int autofs4_d_manage(struct dentry *, bool);
+static int autofs4_d_manage(struct path *, bool);
static void autofs4_dentry_release(struct dentry *);
const struct file_operations autofs4_root_operations = {
@@ -421,8 +421,9 @@ done:
return NULL;
}
-static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
+static int autofs4_d_manage(struct path *path, bool rcu_walk)
{
+ struct dentry *dentry = path->dentry;
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry);
int status;
diff --git a/fs/namei.c b/fs/namei.c
index adb0414..e86b9d0 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1200,7 +1200,7 @@ static int follow_managed(struct path *path, struct nameidata *nd)
if (managed & DCACHE_MANAGE_TRANSIT) {
BUG_ON(!path->dentry->d_op);
BUG_ON(!path->dentry->d_op->d_manage);
- ret = path->dentry->d_op->d_manage(path->dentry, false);
+ ret = path->dentry->d_op->d_manage(path, false);
if (ret < 0)
break;
}
@@ -1263,10 +1263,10 @@ int follow_down_one(struct path *path)
}
EXPORT_SYMBOL(follow_down_one);
-static inline int managed_dentry_rcu(struct dentry *dentry)
+static inline int managed_dentry_rcu(struct path *path)
{
- return (dentry->d_flags & DCACHE_MANAGE_TRANSIT) ?
- dentry->d_op->d_manage(dentry, true) : 0;
+ return (path->dentry->d_flags & DCACHE_MANAGE_TRANSIT) ?
+ path->dentry->d_op->d_manage(path, true) : 0;
}
/*
@@ -1282,7 +1282,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
* Don't forget we might have a non-mountpoint managed dentry
* that wants to block transit.
*/
- switch (managed_dentry_rcu(path->dentry)) {
+ switch (managed_dentry_rcu(path)) {
case -ECHILD:
default:
return false;
@@ -1392,8 +1392,7 @@ int follow_down(struct path *path)
if (managed & DCACHE_MANAGE_TRANSIT) {
BUG_ON(!path->dentry->d_op);
BUG_ON(!path->dentry->d_op->d_manage);
- ret = path->dentry->d_op->d_manage(
- path->dentry, false);
+ ret = path->dentry->d_op->d_manage(path, false);
if (ret < 0)
return ret == -EISDIR ? 0 : ret;
}
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 5ff3e9a..ad2df92 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -139,7 +139,7 @@ struct dentry_operations {
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *);
- int (*d_manage)(struct dentry *, bool);
+ int (*d_manage)(struct path *, bool);
struct dentry *(*d_real)(struct dentry *, const struct inode *,
unsigned int);
} ____cacheline_aligned;
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [RFC PATCH 2/8] vfs - add path_is_mountpoint() helper
2016-10-03 0:46 [RFC PATCH 0/8] Patch series to fix autofs unreliable usage of d_mountpoint() Ian Kent
2016-10-03 0:46 ` [RFC PATCH 1/8] vfs - change d_manage() to take a struct path Ian Kent
@ 2016-10-03 0:46 ` Ian Kent
2016-10-03 0:46 ` [RFC PATCH 3/8] vfs - add path_has_submounts() Ian Kent
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ian Kent @ 2016-10-03 0:46 UTC (permalink / raw)
To: Kernel Mailing List
Cc: autofs mailing list, Al Viro, linux-fsdevel, Omar Sandoval,
Andrew Morton, Eric W. Biederman
From: Ian Kent <ikent@redhat.com>
d_mountpoint() can only be used reliably to establish if a dentry is
not mounted in any namespace. It isn't aware of the possibility there
may be multiple mounts using a given dentry that may be in a different
namespace.
Add helper functions, path_is_mountpoint() and an rcu version , that
checks if a struct path is a mountpoint for this case.
Signed-off-by: Ian Kent <raven@themaw.net>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Omar Sandoval <osandov@osandov.com>
---
fs/namespace.c | 43 +++++++++++++++++++++++++++++++++++++++++++
include/linux/fs.h | 2 ++
2 files changed, 45 insertions(+)
diff --git a/fs/namespace.c b/fs/namespace.c
index 7bb2cda..ca1faaa 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1153,6 +1153,49 @@ struct vfsmount *mntget(struct vfsmount *mnt)
}
EXPORT_SYMBOL(mntget);
+static bool __path_is_mountpoint(struct path *path)
+{
+ struct mount *mount;
+ struct vfsmount *mnt;
+ unsigned seq;
+
+ do {
+ seq = read_seqbegin(&mount_lock);
+ mount = __lookup_mnt(path->mnt, path->dentry);
+ mnt = mount ? &mount->mnt : NULL;
+ } while (mnt &&
+ !(mnt->mnt_flags & MNT_SYNC_UMOUNT) &&
+ read_seqretry(&mount_lock, seq));
+
+ return mnt != NULL;
+}
+
+/* Check if path is a mount in current namespace */
+bool path_is_mountpoint(struct path *path)
+{
+ bool res;
+
+ if (!d_mountpoint(path->dentry))
+ return 0;
+
+ rcu_read_lock();
+ res = __path_is_mountpoint(path);
+ rcu_read_unlock();
+
+ return res;
+}
+EXPORT_SYMBOL(path_is_mountpoint);
+
+/* Check if path is a mount in current namespace */
+bool path_is_mountpoint_rcu(struct path *path)
+{
+ if (!d_mountpoint(path->dentry))
+ return 0;
+
+ return __path_is_mountpoint(path);
+}
+EXPORT_SYMBOL(path_is_mountpoint_rcu);
+
struct vfsmount *mnt_clone_internal(struct path *path)
{
struct mount *p;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 901e25d..d588b26 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2117,6 +2117,8 @@ extern int vfs_ustat(dev_t, struct kstatfs *);
extern int freeze_super(struct super_block *super);
extern int thaw_super(struct super_block *super);
extern bool our_mnt(struct vfsmount *mnt);
+extern bool path_is_mountpoint(struct path *);
+extern bool path_is_mountpoint_rcu(struct path *);
extern int current_umask(void);
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [RFC PATCH 3/8] vfs - add path_has_submounts()
2016-10-03 0:46 [RFC PATCH 0/8] Patch series to fix autofs unreliable usage of d_mountpoint() Ian Kent
2016-10-03 0:46 ` [RFC PATCH 1/8] vfs - change d_manage() to take a struct path Ian Kent
2016-10-03 0:46 ` [RFC PATCH 2/8] vfs - add path_is_mountpoint() helper Ian Kent
@ 2016-10-03 0:46 ` Ian Kent
2016-10-03 0:46 ` [RFC PATCH 4/8] autofs - change autofs4_expire_wait() to take struct path Ian Kent
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ian Kent @ 2016-10-03 0:46 UTC (permalink / raw)
To: Kernel Mailing List
Cc: autofs mailing list, Al Viro, linux-fsdevel, Omar Sandoval,
Andrew Morton, Eric W. Biederman
From: Ian Kent <ikent@redhat.com>
d_mountpoint() can only be used reliably to establish if a dentry is
not mounted in any namespace. It isn't aware of the possibility there
may be multiple mounts using the given dentry, possibly in a different
namespace.
Add function, path_has_submounts(), that checks is a struct path contains
mounts (or is a mountpoint itself) to handle this case.
Signed-off-by: Ian Kent <raven@themaw.net>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Omar Sandoval <osandov@osandov.com>
---
fs/dcache.c | 35 +++++++++++++++++++++++++++++++++++
include/linux/dcache.h | 1 +
2 files changed, 36 insertions(+)
diff --git a/fs/dcache.c b/fs/dcache.c
index 5c7cc95..872f04e 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1306,6 +1306,41 @@ int have_submounts(struct dentry *parent)
}
EXPORT_SYMBOL(have_submounts);
+struct check_mount {
+ struct vfsmount *mnt;
+ unsigned int mounted;
+};
+
+static enum d_walk_ret path_check_mount(void *data, struct dentry *dentry)
+{
+ struct check_mount *info = data;
+ struct path path = { .mnt = info->mnt, .dentry = dentry };
+
+ if (path_is_mountpoint(&path)) {
+ info->mounted = 1;
+ return D_WALK_QUIT;
+ }
+ return D_WALK_CONTINUE;
+}
+
+/**
+ * path_has_submounts - check for mounts over a dentry in the
+ * current namespace.
+ * @parent: path to check.
+ *
+ * Return true if the parent or its subdirectories contain
+ * a mount point in the current namespace.
+ */
+int path_has_submounts(struct path *parent)
+{
+ struct check_mount data = { .mnt = parent->mnt, .mounted = 0 };
+
+ d_walk(parent->dentry, &data, path_check_mount, NULL);
+
+ return data.mounted;
+}
+EXPORT_SYMBOL(path_has_submounts);
+
/*
* Called by mount code to set a mountpoint and check if the mountpoint is
* reachable (e.g. NFS can unhash a directory dentry and then the complete
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index ad2df92..5c5d197 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -255,6 +255,7 @@ extern void d_prune_aliases(struct inode *);
/* test whether we have any submounts in a subdir tree */
extern int have_submounts(struct dentry *);
+extern int path_has_submounts(struct path *);
/*
* This adds the entry to the hash queues.
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [RFC PATCH 4/8] autofs - change autofs4_expire_wait() to take struct path
2016-10-03 0:46 [RFC PATCH 0/8] Patch series to fix autofs unreliable usage of d_mountpoint() Ian Kent
` (2 preceding siblings ...)
2016-10-03 0:46 ` [RFC PATCH 3/8] vfs - add path_has_submounts() Ian Kent
@ 2016-10-03 0:46 ` Ian Kent
2016-10-03 0:46 ` [RFC PATCH 5/8] autofs - change autofs4_wait() " Ian Kent
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ian Kent @ 2016-10-03 0:46 UTC (permalink / raw)
To: Kernel Mailing List
Cc: autofs mailing list, Al Viro, linux-fsdevel, Omar Sandoval,
Andrew Morton, Eric W. Biederman
From: Ian Kent <ikent@redhat.com>
In order to use the functions path_is_mountpoint() (or it's rcu-walk
variant) and path_has_submounts() autofs needs to pass a struct path
in several places.
Start by changing autofs4_expire_wait() to take a struct path instead
of a struct dentry.
Signed-off-by: Ian Kent <raven@themaw.net>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Omar Sandoval <osandov@osandov.com>
---
fs/autofs4/autofs_i.h | 2 +-
fs/autofs4/dev-ioctl.c | 2 +-
fs/autofs4/expire.c | 3 ++-
fs/autofs4/root.c | 12 +++++++-----
4 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index a439548..b548ee6 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -148,7 +148,7 @@ void autofs4_free_ino(struct autofs_info *);
/* Expiration */
int is_autofs4_dentry(struct dentry *);
-int autofs4_expire_wait(struct dentry *dentry, int rcu_walk);
+int autofs4_expire_wait(struct path *path, int rcu_walk);
int autofs4_expire_run(struct super_block *, struct vfsmount *,
struct autofs_sb_info *,
struct autofs_packet_expire __user *);
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c
index c7fcc74..3cd96e6 100644
--- a/fs/autofs4/dev-ioctl.c
+++ b/fs/autofs4/dev-ioctl.c
@@ -457,7 +457,7 @@ static int autofs_dev_ioctl_requester(struct file *fp,
ino = autofs4_dentry_ino(path.dentry);
if (ino) {
err = 0;
- autofs4_expire_wait(path.dentry, 0);
+ autofs4_expire_wait(&path, 0);
spin_lock(&sbi->fs_lock);
param->requester.uid =
from_kuid_munged(current_user_ns(), ino->uid);
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index d8e6d42..7eac498 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -495,8 +495,9 @@ found:
return expired;
}
-int autofs4_expire_wait(struct dentry *dentry, int rcu_walk)
+int autofs4_expire_wait(struct path *path, int rcu_walk)
{
+ struct dentry *dentry = path->dentry;
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry);
int status;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 0705daa..e5ed061 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -286,22 +286,24 @@ static int autofs4_mount_wait(struct dentry *dentry, bool rcu_walk)
return status;
}
-static int do_expire_wait(struct dentry *dentry, bool rcu_walk)
+static int do_expire_wait(struct path *path, bool rcu_walk)
{
+ struct dentry *dentry = path->dentry;
struct dentry *expiring;
expiring = autofs4_lookup_expiring(dentry, rcu_walk);
if (IS_ERR(expiring))
return PTR_ERR(expiring);
if (!expiring)
- return autofs4_expire_wait(dentry, rcu_walk);
+ return autofs4_expire_wait(path, rcu_walk);
else {
+ struct path this = { .mnt = path->mnt, .dentry = expiring };
/*
* If we are racing with expire the request might not
* be quite complete, but the directory has been removed
* so it must have been successful, just wait for it.
*/
- autofs4_expire_wait(expiring, 0);
+ autofs4_expire_wait(&this, 0);
autofs4_del_expiring(expiring);
dput(expiring);
}
@@ -354,7 +356,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
* and the directory was removed, so just go ahead and try
* the mount.
*/
- status = do_expire_wait(dentry, 0);
+ status = do_expire_wait(path, 0);
if (status && status != -EAGAIN)
return NULL;
@@ -438,7 +440,7 @@ static int autofs4_d_manage(struct path *path, bool rcu_walk)
}
/* Wait for pending expires */
- if (do_expire_wait(dentry, rcu_walk) == -ECHILD)
+ if (do_expire_wait(path, rcu_walk) == -ECHILD)
return -ECHILD;
/*
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [RFC PATCH 5/8] autofs - change autofs4_wait() to take struct path
2016-10-03 0:46 [RFC PATCH 0/8] Patch series to fix autofs unreliable usage of d_mountpoint() Ian Kent
` (3 preceding siblings ...)
2016-10-03 0:46 ` [RFC PATCH 4/8] autofs - change autofs4_expire_wait() to take struct path Ian Kent
@ 2016-10-03 0:46 ` Ian Kent
2016-10-03 0:46 ` [RFC PATCH 6/8] autofs - use path_is_mountpoint() to fix unreliable d_mountpoint() checks Ian Kent
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ian Kent @ 2016-10-03 0:46 UTC (permalink / raw)
To: Kernel Mailing List
Cc: autofs mailing list, Al Viro, linux-fsdevel, Omar Sandoval,
Andrew Morton, Eric W. Biederman
From: Ian Kent <ikent@redhat.com>
In order to use the functions path_is_mountpoint() (or its rcu-walk
variant) and path_has_submounts() autofs needs to pass a struct path
in several places.
Now change autofs4_wait() to take a struct path instead of a struct
dentry.
Signed-off-by: Ian Kent <raven@themaw.net>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Omar Sandoval <osandov@osandov.com>
---
fs/autofs4/autofs_i.h | 2 +-
fs/autofs4/expire.c | 5 +++--
fs/autofs4/root.c | 16 ++++++++--------
fs/autofs4/waitq.c | 3 ++-
4 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index b548ee6..1b6ed78 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -220,7 +220,7 @@ static inline int autofs_prepare_pipe(struct file *pipe)
/* Queue management functions */
-int autofs4_wait(struct autofs_sb_info *, struct dentry *, enum autofs_notify);
+int autofs4_wait(struct autofs_sb_info *, struct path *, enum autofs_notify);
int autofs4_wait_release(struct autofs_sb_info *, autofs_wqt_t, int);
void autofs4_catatonic_mode(struct autofs_sb_info *);
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index 7eac498..a37ba40 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -526,7 +526,7 @@ retry:
pr_debug("waiting for expire %p name=%pd\n", dentry, dentry);
- status = autofs4_wait(sbi, dentry, NFY_NONE);
+ status = autofs4_wait(sbi, path, NFY_NONE);
wait_for_completion(&ino->expire_complete);
pr_debug("expire done status=%d\n", status);
@@ -593,11 +593,12 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
if (dentry) {
struct autofs_info *ino = autofs4_dentry_ino(dentry);
+ struct path path = { .mnt = mnt, .dentry = dentry };
/* This is synchronous because it makes the daemon a
* little easier
*/
- ret = autofs4_wait(sbi, dentry, NFY_EXPIRE);
+ ret = autofs4_wait(sbi, &path, NFY_EXPIRE);
spin_lock(&sbi->fs_lock);
/* avoid rapid-fire expire attempts if expiry fails */
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index e5ed061..a12c248 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -269,17 +269,17 @@ next:
return NULL;
}
-static int autofs4_mount_wait(struct dentry *dentry, bool rcu_walk)
+static int autofs4_mount_wait(struct path *path, bool rcu_walk)
{
- struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
- struct autofs_info *ino = autofs4_dentry_ino(dentry);
+ struct autofs_sb_info *sbi = autofs4_sbi(path->dentry->d_sb);
+ struct autofs_info *ino = autofs4_dentry_ino(path->dentry);
int status = 0;
if (ino->flags & AUTOFS_INF_PENDING) {
if (rcu_walk)
return -ECHILD;
- pr_debug("waiting for mount name=%pd\n", dentry);
- status = autofs4_wait(sbi, dentry, NFY_MOUNT);
+ pr_debug("waiting for mount name=%pd\n", path->dentry);
+ status = autofs4_wait(sbi, path, NFY_MOUNT);
pr_debug("mount wait done status=%d\n", status);
}
ino->last_used = jiffies;
@@ -364,7 +364,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
spin_lock(&sbi->fs_lock);
if (ino->flags & AUTOFS_INF_PENDING) {
spin_unlock(&sbi->fs_lock);
- status = autofs4_mount_wait(dentry, 0);
+ status = autofs4_mount_wait(path, 0);
if (status)
return ERR_PTR(status);
goto done;
@@ -405,7 +405,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
}
ino->flags |= AUTOFS_INF_PENDING;
spin_unlock(&sbi->fs_lock);
- status = autofs4_mount_wait(dentry, 0);
+ status = autofs4_mount_wait(path, 0);
spin_lock(&sbi->fs_lock);
ino->flags &= ~AUTOFS_INF_PENDING;
if (status) {
@@ -447,7 +447,7 @@ static int autofs4_d_manage(struct path *path, bool rcu_walk)
* This dentry may be under construction so wait on mount
* completion.
*/
- status = autofs4_mount_wait(dentry, rcu_walk);
+ status = autofs4_mount_wait(path, rcu_walk);
if (status)
return status;
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 431fd7e..f757f87 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -345,8 +345,9 @@ static int validate_request(struct autofs_wait_queue **wait,
}
int autofs4_wait(struct autofs_sb_info *sbi,
- struct dentry *dentry, enum autofs_notify notify)
+ struct path *path, enum autofs_notify notify)
{
+ struct dentry *dentry = path->dentry;
struct autofs_wait_queue *wq;
struct qstr qstr;
char *name;
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [RFC PATCH 6/8] autofs - use path_is_mountpoint() to fix unreliable d_mountpoint() checks
2016-10-03 0:46 [RFC PATCH 0/8] Patch series to fix autofs unreliable usage of d_mountpoint() Ian Kent
` (4 preceding siblings ...)
2016-10-03 0:46 ` [RFC PATCH 5/8] autofs - change autofs4_wait() " Ian Kent
@ 2016-10-03 0:46 ` Ian Kent
2016-10-03 0:46 ` [RFC PATCH 7/8] autofs - use path_has_submounts() to fix unreliable have_submount() checks Ian Kent
2016-10-03 0:47 ` [RFC PATCH 8/8] vfs - remove unused have_submounts() function Ian Kent
7 siblings, 0 replies; 9+ messages in thread
From: Ian Kent @ 2016-10-03 0:46 UTC (permalink / raw)
To: Kernel Mailing List
Cc: autofs mailing list, Al Viro, linux-fsdevel, Omar Sandoval,
Andrew Morton, Eric W. Biederman
From: Ian Kent <ikent@redhat.com>
If an automount mount is clone(2)ed into a file system that is propagation
private, when it later expires in the originating namespace, subsequent
calls to autofs ->d_automount() for that dentry in the original namespace
will return ELOOP until the mount is umounted in the cloned namespace.
Now that a struct path is available where needed use path_is_mountpoint()
instead of d_mountpoint() so we don't get false positives when checking
if a dentry is a mount point in the current namespace.
Signed-off-by: Ian Kent <raven@themaw.net>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Omar Sandoval <osandov@osandov.com>
---
fs/autofs4/root.c | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index a12c248..0f5d264 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -107,12 +107,15 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
{
struct dentry *dentry = file->f_path.dentry;
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+ struct path path;
pr_debug("file=%p dentry=%p %pd\n", file, dentry, dentry);
if (autofs4_oz_mode(sbi))
goto out;
+ path = file->f_path;
+
/*
* An empty directory in an autofs file system is always a
* mount point. The daemon must have failed to mount this
@@ -123,7 +126,7 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
* it.
*/
spin_lock(&sbi->lookup_lock);
- if (!d_mountpoint(dentry) && simple_empty(dentry)) {
+ if (!path_is_mountpoint(&path) && simple_empty(dentry)) {
spin_unlock(&sbi->lookup_lock);
return -ENOENT;
}
@@ -372,15 +375,15 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
/*
* If the dentry is a symlink it's equivalent to a directory
- * having d_mountpoint() true, so there's no need to call back
- * to the daemon.
+ * having path_is_mountpoint() true, so there's no need to call
+ * back to the daemon.
*/
if (d_really_is_positive(dentry) && d_is_symlink(dentry)) {
spin_unlock(&sbi->fs_lock);
goto done;
}
- if (!d_mountpoint(dentry)) {
+ if (!path_is_mountpoint(path)) {
/*
* It's possible that user space hasn't removed directories
* after umounting a rootless multi-mount, although it
@@ -434,8 +437,13 @@ static int autofs4_d_manage(struct path *path, bool rcu_walk)
/* The daemon never waits. */
if (autofs4_oz_mode(sbi)) {
- if (!d_mountpoint(dentry))
- return -EISDIR;
+ if (rcu_walk) {
+ if (!path_is_mountpoint_rcu(path))
+ return -EISDIR;
+ } else {
+ if (!path_is_mountpoint(path))
+ return -EISDIR;
+ }
return 0;
}
@@ -463,7 +471,7 @@ static int autofs4_d_manage(struct path *path, bool rcu_walk)
if (ino->flags & AUTOFS_INF_WANT_EXPIRE)
return 0;
- if (d_mountpoint(dentry))
+ if (path_is_mountpoint_rcu(path))
return 0;
inode = d_inode_rcu(dentry);
if (inode && S_ISLNK(inode->i_mode))
@@ -490,7 +498,7 @@ static int autofs4_d_manage(struct path *path, bool rcu_walk)
* we can avoid needless calls ->d_automount() and avoid
* an incorrect ELOOP error return.
*/
- if ((!d_mountpoint(dentry) && !simple_empty(dentry)) ||
+ if ((!path_is_mountpoint(path) && !simple_empty(dentry)) ||
(d_really_is_positive(dentry) && d_is_symlink(dentry)))
status = -EISDIR;
}
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [RFC PATCH 7/8] autofs - use path_has_submounts() to fix unreliable have_submount() checks
2016-10-03 0:46 [RFC PATCH 0/8] Patch series to fix autofs unreliable usage of d_mountpoint() Ian Kent
` (5 preceding siblings ...)
2016-10-03 0:46 ` [RFC PATCH 6/8] autofs - use path_is_mountpoint() to fix unreliable d_mountpoint() checks Ian Kent
@ 2016-10-03 0:46 ` Ian Kent
2016-10-03 0:47 ` [RFC PATCH 8/8] vfs - remove unused have_submounts() function Ian Kent
7 siblings, 0 replies; 9+ messages in thread
From: Ian Kent @ 2016-10-03 0:46 UTC (permalink / raw)
To: Kernel Mailing List
Cc: autofs mailing list, Al Viro, linux-fsdevel, Omar Sandoval,
Andrew Morton, Eric W. Biederman
From: Ian Kent <ikent@redhat.com>
If an automount mount is clone(2)ed into a file system that is propagation
private, when it later expires in the originating namespace, subsequent
calls to autofs ->d_automount() for that dentry in the original namespace
will return ELOOP until the mount is umounted in the cloned namespace.
Now that a struct path is available where needed use path_has_submounts()
instead of have_submounts() so we don't get false positives when checking
if a dentry is a mount point or contains mounts in the current namespace.
Signed-off-by: Ian Kent <raven@themaw.net>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Omar Sandoval <osandov@osandov.com>
---
fs/autofs4/dev-ioctl.c | 2 +-
fs/autofs4/root.c | 14 +++++++-------
fs/autofs4/waitq.c | 10 +++++++---
3 files changed, 15 insertions(+), 11 deletions(-)
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c
index 3cd96e6..953e790 100644
--- a/fs/autofs4/dev-ioctl.c
+++ b/fs/autofs4/dev-ioctl.c
@@ -564,7 +564,7 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp,
devid = new_encode_dev(dev);
- err = have_submounts(path.dentry);
+ err = path_has_submounts(&path);
if (follow_down_one(&path))
magic = path.dentry->d_sb->s_magic;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 0f5d264..cf90d37 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -387,16 +387,16 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
/*
* It's possible that user space hasn't removed directories
* after umounting a rootless multi-mount, although it
- * should. For v5 have_submounts() is sufficient to handle
- * this because the leaves of the directory tree under the
- * mount never trigger mounts themselves (they have an autofs
- * trigger mount mounted on them). But v4 pseudo direct mounts
- * do need the leaves to trigger mounts. In this case we
- * have no choice but to use the list_empty() check and
+ * should. For v5 path_has_submounts() is sufficient to
+ * handle this because the leaves of the directory tree under
+ * the mount never trigger mounts themselves (they have an
+ * autofs trigger mount mounted on them). But v4 pseudo direct
+ * mounts do need the leaves to trigger mounts. In this case
+ * we have no choice but to use the list_empty() check and
* require user space behave.
*/
if (sbi->version > 4) {
- if (have_submounts(dentry)) {
+ if (path_has_submounts(path)) {
spin_unlock(&sbi->fs_lock);
goto done;
}
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index f757f87..ed05cae 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -250,8 +250,9 @@ autofs4_find_wait(struct autofs_sb_info *sbi, const struct qstr *qstr)
static int validate_request(struct autofs_wait_queue **wait,
struct autofs_sb_info *sbi,
const struct qstr *qstr,
- struct dentry *dentry, enum autofs_notify notify)
+ struct path *path, enum autofs_notify notify)
{
+ struct dentry *dentry = path->dentry;
struct autofs_wait_queue *wq;
struct autofs_info *ino;
@@ -314,6 +315,7 @@ static int validate_request(struct autofs_wait_queue **wait,
*/
if (notify == NFY_MOUNT) {
struct dentry *new = NULL;
+ struct path this;
int valid = 1;
/*
@@ -333,7 +335,9 @@ static int validate_request(struct autofs_wait_queue **wait,
dentry = new;
}
}
- if (have_submounts(dentry))
+ this.mnt = path->mnt;
+ this.dentry = dentry;
+ if (path_has_submounts(&this))
valid = 0;
if (new)
@@ -406,7 +410,7 @@ int autofs4_wait(struct autofs_sb_info *sbi,
return -EINTR;
}
- ret = validate_request(&wq, sbi, &qstr, dentry, notify);
+ ret = validate_request(&wq, sbi, &qstr, path, notify);
if (ret <= 0) {
if (ret != -EINTR)
mutex_unlock(&sbi->wq_mutex);
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [RFC PATCH 8/8] vfs - remove unused have_submounts() function
2016-10-03 0:46 [RFC PATCH 0/8] Patch series to fix autofs unreliable usage of d_mountpoint() Ian Kent
` (6 preceding siblings ...)
2016-10-03 0:46 ` [RFC PATCH 7/8] autofs - use path_has_submounts() to fix unreliable have_submount() checks Ian Kent
@ 2016-10-03 0:47 ` Ian Kent
7 siblings, 0 replies; 9+ messages in thread
From: Ian Kent @ 2016-10-03 0:47 UTC (permalink / raw)
To: Kernel Mailing List
Cc: autofs mailing list, Al Viro, linux-fsdevel, Omar Sandoval,
Andrew Morton, Eric W. Biederman
Now that path_has_submounts() has been added have_submounts() is no
longer used so remove it.
Signed-off-by: Ian Kent <raven@themaw.net>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Omar Sandoval <osandov@osandov.com>
---
fs/dcache.c | 33 ---------------------------------
include/linux/dcache.h | 1 -
2 files changed, 34 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index 872f04e..719d8b4 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1273,39 +1273,6 @@ rename_retry:
goto again;
}
-/*
- * Search for at least 1 mount point in the dentry's subdirs.
- * We descend to the next level whenever the d_subdirs
- * list is non-empty and continue searching.
- */
-
-static enum d_walk_ret check_mount(void *data, struct dentry *dentry)
-{
- int *ret = data;
- if (d_mountpoint(dentry)) {
- *ret = 1;
- return D_WALK_QUIT;
- }
- return D_WALK_CONTINUE;
-}
-
-/**
- * have_submounts - check for mounts over a dentry
- * @parent: dentry to check.
- *
- * Return true if the parent or its subdirectories contain
- * a mount point
- */
-int have_submounts(struct dentry *parent)
-{
- int ret = 0;
-
- d_walk(parent, &ret, check_mount, NULL);
-
- return ret;
-}
-EXPORT_SYMBOL(have_submounts);
-
struct check_mount {
struct vfsmount *mnt;
unsigned int mounted;
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 5c5d197..384c87c 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -254,7 +254,6 @@ extern struct dentry *d_find_alias(struct inode *);
extern void d_prune_aliases(struct inode *);
/* test whether we have any submounts in a subdir tree */
-extern int have_submounts(struct dentry *);
extern int path_has_submounts(struct path *);
/*
^ permalink raw reply related [flat|nested] 9+ messages in thread