All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/8] vfs - change d_manage() to take a struct path
@ 2016-10-11  5:33 Ian Kent
  2016-10-11  5:33 ` [PATCH 2/8] vfs - add path_is_mountpoint() helper Ian Kent
                   ` (8 more replies)
  0 siblings, 9 replies; 18+ messages in thread
From: Ian Kent @ 2016-10-11  5:33 UTC (permalink / raw)
  To: Andrew Morton
  Cc: autofs mailing list, Kernel Mailing List, Eric W. Biederman,
	linux-fsdevel, Omar Sandoval, Al Viro

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 fe15682..1949ac4 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 bc3b8e0..db70d71 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -934,7 +934,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 a11f731..5cbd4e1 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 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
 	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 a7f601c..704766a 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 5beed7b..798bc04 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	[flat|nested] 18+ messages in thread

* [PATCH 2/8] vfs - add path_is_mountpoint() helper
  2016-10-11  5:33 [PATCH 1/8] vfs - change d_manage() to take a struct path Ian Kent
@ 2016-10-11  5:33 ` Ian Kent
  2016-10-11  5:34 ` [PATCH 3/8] vfs - add path_has_submounts() Ian Kent
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 18+ messages in thread
From: Ian Kent @ 2016-10-11  5:33 UTC (permalink / raw)
  To: Andrew Morton
  Cc: autofs mailing list, Kernel Mailing List, Eric W. Biederman,
	linux-fsdevel, Omar Sandoval, Al Viro

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 ff1cd14..5ef9618 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1160,6 +1160,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 09a8c41..deaf08b 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2142,6 +2142,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	[flat|nested] 18+ messages in thread

* [PATCH 3/8] vfs - add path_has_submounts()
  2016-10-11  5:33 [PATCH 1/8] vfs - change d_manage() to take a struct path Ian Kent
  2016-10-11  5:33 ` [PATCH 2/8] vfs - add path_is_mountpoint() helper Ian Kent
@ 2016-10-11  5:34 ` Ian Kent
  2016-10-11  5:34 ` [PATCH 4/8] autofs - change autofs4_expire_wait() to take struct path Ian Kent
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 18+ messages in thread
From: Ian Kent @ 2016-10-11  5:34 UTC (permalink / raw)
  To: Andrew Morton
  Cc: autofs mailing list, Kernel Mailing List, Eric W. Biederman,
	linux-fsdevel, Omar Sandoval, Al Viro

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 798bc04..e351646 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	[flat|nested] 18+ messages in thread

* [PATCH 4/8] autofs - change autofs4_expire_wait() to take struct path
  2016-10-11  5:33 [PATCH 1/8] vfs - change d_manage() to take a struct path Ian Kent
  2016-10-11  5:33 ` [PATCH 2/8] vfs - add path_is_mountpoint() helper Ian Kent
  2016-10-11  5:34 ` [PATCH 3/8] vfs - add path_has_submounts() Ian Kent
@ 2016-10-11  5:34 ` Ian Kent
  2016-10-11  5:34 ` [PATCH 5/8] autofs - change autofs4_wait() " Ian Kent
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 18+ messages in thread
From: Ian Kent @ 2016-10-11  5:34 UTC (permalink / raw)
  To: Andrew Morton
  Cc: autofs mailing list, Kernel Mailing List, Eric W. Biederman,
	linux-fsdevel, Omar Sandoval, Al Viro

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 a1fba42..6d72bba 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -145,7 +145,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 fc09eb7..40c69f9 100644
--- a/fs/autofs4/dev-ioctl.c
+++ b/fs/autofs4/dev-ioctl.c
@@ -468,7 +468,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 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
 	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 5cbd4e1..35096e3 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	[flat|nested] 18+ messages in thread

* [PATCH 5/8] autofs - change autofs4_wait() to take struct path
  2016-10-11  5:33 [PATCH 1/8] vfs - change d_manage() to take a struct path Ian Kent
                   ` (2 preceding siblings ...)
  2016-10-11  5:34 ` [PATCH 4/8] autofs - change autofs4_expire_wait() to take struct path Ian Kent
@ 2016-10-11  5:34 ` Ian Kent
  2016-10-11  5:34 ` [PATCH 6/8] autofs - use path_is_mountpoint() to fix unreliable d_mountpoint() checks Ian Kent
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 18+ messages in thread
From: Ian Kent @ 2016-10-11  5:34 UTC (permalink / raw)
  To: Andrew Morton
  Cc: autofs mailing list, Kernel Mailing List, Eric W. Biederman,
	linux-fsdevel, Omar Sandoval, Al Viro

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 6d72bba..14cef41 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -217,7 +217,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 @@ int autofs4_expire_wait(struct path *path, int rcu_walk)
 
 		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 35096e3..d47930ad 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -269,17 +269,17 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry,
 	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	[flat|nested] 18+ messages in thread

* [PATCH 6/8] autofs - use path_is_mountpoint() to fix unreliable d_mountpoint() checks
  2016-10-11  5:33 [PATCH 1/8] vfs - change d_manage() to take a struct path Ian Kent
                   ` (3 preceding siblings ...)
  2016-10-11  5:34 ` [PATCH 5/8] autofs - change autofs4_wait() " Ian Kent
@ 2016-10-11  5:34 ` Ian Kent
  2016-10-27  2:17   ` Al Viro
  2016-10-11  5:34 ` [PATCH 7/8] autofs - use path_has_submounts() to fix unreliable have_submount() checks Ian Kent
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 18+ messages in thread
From: Ian Kent @ 2016-10-11  5:34 UTC (permalink / raw)
  To: Andrew Morton
  Cc: autofs mailing list, Kernel Mailing List, Eric W. Biederman,
	linux-fsdevel, Omar Sandoval, Al Viro

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 d47930ad..d7e48fe 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	[flat|nested] 18+ messages in thread

* [PATCH 7/8] autofs - use path_has_submounts() to fix unreliable have_submount() checks
  2016-10-11  5:33 [PATCH 1/8] vfs - change d_manage() to take a struct path Ian Kent
                   ` (4 preceding siblings ...)
  2016-10-11  5:34 ` [PATCH 6/8] autofs - use path_is_mountpoint() to fix unreliable d_mountpoint() checks Ian Kent
@ 2016-10-11  5:34 ` Ian Kent
  2016-10-11  5:34 ` [PATCH 8/8] vfs - remove unused have_submounts() function Ian Kent
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 18+ messages in thread
From: Ian Kent @ 2016-10-11  5:34 UTC (permalink / raw)
  To: Andrew Morton
  Cc: autofs mailing list, Kernel Mailing List, Eric W. Biederman,
	linux-fsdevel, Omar Sandoval, Al Viro

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 40c69f9..afacdaa 100644
--- a/fs/autofs4/dev-ioctl.c
+++ b/fs/autofs4/dev-ioctl.c
@@ -575,7 +575,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 d7e48fe..c4df881 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	[flat|nested] 18+ messages in thread

* [PATCH 8/8] vfs - remove unused have_submounts() function
  2016-10-11  5:33 [PATCH 1/8] vfs - change d_manage() to take a struct path Ian Kent
                   ` (5 preceding siblings ...)
  2016-10-11  5:34 ` [PATCH 7/8] autofs - use path_has_submounts() to fix unreliable have_submount() checks Ian Kent
@ 2016-10-11  5:34 ` Ian Kent
  2016-10-11 16:04 ` [PATCH 1/8] vfs - change d_manage() to take a struct path Eric W. Biederman
  2016-10-19 19:40 ` Andrew Morton
  8 siblings, 0 replies; 18+ messages in thread
From: Ian Kent @ 2016-10-11  5:34 UTC (permalink / raw)
  To: Andrew Morton
  Cc: autofs mailing list, Kernel Mailing List, Eric W. Biederman,
	linux-fsdevel, Omar Sandoval, Al Viro

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 @@ static void d_walk(struct dentry *parent, void *data,
 	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 e351646..44a9a9b 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	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/8] vfs - change d_manage() to take a struct path
  2016-10-11  5:33 [PATCH 1/8] vfs - change d_manage() to take a struct path Ian Kent
                   ` (6 preceding siblings ...)
  2016-10-11  5:34 ` [PATCH 8/8] vfs - remove unused have_submounts() function Ian Kent
@ 2016-10-11 16:04 ` Eric W. Biederman
  2016-10-11 23:47   ` Ian Kent
  2016-10-19 19:40 ` Andrew Morton
  8 siblings, 1 reply; 18+ messages in thread
From: Eric W. Biederman @ 2016-10-11 16:04 UTC (permalink / raw)
  To: Ian Kent
  Cc: Andrew Morton, autofs mailing list, Kernel Mailing List,
	linux-fsdevel, Omar Sandoval, Al Viro

Ian Kent <raven@themaw.net> writes:

> 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.

Taking a quick look overall I see no issues with this series.  Overall
it seems straight forward.

On the nit side I expect saying const struct path * in the functions
that now take a struct path would be useful.

I suspect it would also be useful to say
	const struct path *path;
        path = &file->f_path;

In the one part of the code where you do that.  Instead of copying the
path out of the struct file.

Overall I expect that will keep down bugs at no reduction in usability.
Just a statement that the struct path won't change when it is passed
to various functions.

Eric

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/8] vfs - change d_manage() to take a struct path
  2016-10-11 16:04 ` [PATCH 1/8] vfs - change d_manage() to take a struct path Eric W. Biederman
@ 2016-10-11 23:47   ` Ian Kent
  0 siblings, 0 replies; 18+ messages in thread
From: Ian Kent @ 2016-10-11 23:47 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Andrew Morton, autofs mailing list, Kernel Mailing List,
	linux-fsdevel, Omar Sandoval, Al Viro

On Tue, 2016-10-11 at 11:04 -0500, Eric W. Biederman wrote:
> Ian Kent <raven@themaw.net> writes:
> 
> > 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.
> 
> Taking a quick look overall I see no issues with this series.  Overall
> it seems straight forward.
> 
> On the nit side I expect saying const struct path * in the functions
> that now take a struct path would be useful.
> 
> I suspect it would also be useful to say
> 	const struct path *path;
>         path = &file->f_path;
> 
> In the one part of the code where you do that.  Instead of copying the
> path out of the struct file.
> 
> Overall I expect that will keep down bugs at no reduction in usability.
> Just a statement that the struct path won't change when it is passed
> to various functions.

Thanks Eric, that's a good suggestion for a follow up patch, will do.

Ian

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/8] vfs - change d_manage() to take a struct path
  2016-10-11  5:33 [PATCH 1/8] vfs - change d_manage() to take a struct path Ian Kent
                   ` (7 preceding siblings ...)
  2016-10-11 16:04 ` [PATCH 1/8] vfs - change d_manage() to take a struct path Eric W. Biederman
@ 2016-10-19 19:40 ` Andrew Morton
  2016-10-20 23:39   ` Ian Kent
  8 siblings, 1 reply; 18+ messages in thread
From: Andrew Morton @ 2016-10-19 19:40 UTC (permalink / raw)
  To: Ian Kent
  Cc: autofs mailing list, Kernel Mailing List, Eric W. Biederman,
	linux-fsdevel, Omar Sandoval, Al Viro

On Tue, 11 Oct 2016 13:33:52 +0800 Ian Kent <raven@themaw.net> wrote:

> 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.

This patchset contains lots of ViroStuff.  I'll queue it up for some
testing and will go into wait-and-see mode.

Some patches had an explicit From: Ian Kent <ikent@redhat.com> and some
did not.  I assumed that this was intended for all patches.  So all
patches now have different From: and Signed-off-by: email addresses. 
Unclear if this was your intent ;)

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/8] vfs - change d_manage() to take a struct path
  2016-10-19 19:40 ` Andrew Morton
@ 2016-10-20 23:39   ` Ian Kent
  2016-10-27  2:11     ` Al Viro
  0 siblings, 1 reply; 18+ messages in thread
From: Ian Kent @ 2016-10-20 23:39 UTC (permalink / raw)
  To: Andrew Morton
  Cc: autofs mailing list, Kernel Mailing List, Eric W. Biederman,
	linux-fsdevel, Omar Sandoval, Al Viro

On Wed, 2016-10-19 at 12:40 -0700, Andrew Morton wrote:
> On Tue, 11 Oct 2016 13:33:52 +0800 Ian Kent <raven@themaw.net> wrote:
> 
> > 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.
> 
> This patchset contains lots of ViroStuff.  I'll queue it up for some
> testing and will go into wait-and-see mode.

Thanks Andrew.

Maybe Al has been too busy to comment, he has been on the Cc from the start.

Hopefully this email will prompt a review, Al?

> 
> Some patches had an explicit From: Ian Kent <ikent@redhat.com> and some
> did not.  I assumed that this was intended for all patches.  So all
> patches now have different From: and Signed-off-by: email addresses. 
> Unclear if this was your intent ;)

Umm ... sorry about that, I didn't pay enough attention to the From of the
patches when I resurrected them from an earlier attempt at this.

Since the time I did this with an earlier patch series I have elected to not
change my git config and set these in the local tree config so it shouldn't
happen for new work. I'll pay special attention to this if I need to resurrect
any other older patches too.

I know this looks confusing and isn't the best but both email addresses have
been present on my gpg key for a long time so it's verifiable the patches are
from me.

Once again sorry about that.
Ian

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/8] vfs - change d_manage() to take a struct path
  2016-10-20 23:39   ` Ian Kent
@ 2016-10-27  2:11     ` Al Viro
  2016-10-27  2:47       ` Ian Kent
  0 siblings, 1 reply; 18+ messages in thread
From: Al Viro @ 2016-10-27  2:11 UTC (permalink / raw)
  To: Ian Kent
  Cc: Andrew Morton, autofs mailing list, Kernel Mailing List,
	Eric W. Biederman, linux-fsdevel, Omar Sandoval

On Fri, Oct 21, 2016 at 07:39:36AM +0800, Ian Kent wrote:

> Maybe Al has been too busy to comment, he has been on the Cc from the start.

That's... a very mild version of what's been going on.  Let's just say that
the last few weeks had been really interesting.  Not that the shit has
settled, but there was some slackening in the shitstorm last few days.
Unlikely to last, I'm afraid, but...
 
> Hopefully this email will prompt a review, Al?

Aside of the Eric's note re constifying struct path (strongly seconded),
I'm not sure if expiration-related side of that is correct.  OTOH,
since the expiration happens from userland...

How much testing did it get?  I've several test setups involving
autofs, but they are nowhere near exhaustive and I don't have good
enough feel of the codebase to slap together something with decent
coverage...

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 6/8] autofs - use path_is_mountpoint() to fix unreliable d_mountpoint() checks
  2016-10-11  5:34 ` [PATCH 6/8] autofs - use path_is_mountpoint() to fix unreliable d_mountpoint() checks Ian Kent
@ 2016-10-27  2:17   ` Al Viro
  2016-10-27  2:51     ` Ian Kent
  0 siblings, 1 reply; 18+ messages in thread
From: Al Viro @ 2016-10-27  2:17 UTC (permalink / raw)
  To: Ian Kent
  Cc: Andrew Morton, autofs mailing list, Kernel Mailing List,
	Eric W. Biederman, linux-fsdevel, Omar Sandoval

On Tue, Oct 11, 2016 at 01:34:18PM +0800, Ian Kent wrote:
> +	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)) {

Why not &file->f_path, provided that you constify that thing properly?

> +		if (rcu_walk) {
> +			if (!path_is_mountpoint_rcu(path))
> +				return -EISDIR;
> +		} else {
> +			if (!path_is_mountpoint(path))
> +				return -EISDIR;

IDGI.  What's the point of _having_ the _rcu() variant, anyway?  Here you
are probably paying more in terms of i-cache footprint/branch prediction
than you win on not doing that rcu_read_lock()/rcu_read_unlock()...

_rcu variants make sense when non-RCU case does something you can't do
under RCU; here your path_is_mountpoint() is pretty close to being
rcu_read_lock()+path_is_mountpoint_rcu()+rcu_read_unlock() anyway...

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/8] vfs - change d_manage() to take a struct path
  2016-10-27  2:11     ` Al Viro
@ 2016-10-27  2:47       ` Ian Kent
  2016-10-27  6:50         ` Ian Kent
  0 siblings, 1 reply; 18+ messages in thread
From: Ian Kent @ 2016-10-27  2:47 UTC (permalink / raw)
  To: Al Viro
  Cc: Andrew Morton, autofs mailing list, Kernel Mailing List,
	Eric W. Biederman, linux-fsdevel, Omar Sandoval

On Thu, 2016-10-27 at 03:11 +0100, Al Viro wrote:
> On Fri, Oct 21, 2016 at 07:39:36AM +0800, Ian Kent wrote:
> 
> > 
> > Maybe Al has been too busy to comment, he has been on the Cc from the start.
> That's... a very mild version of what's been going on.  Let's just say that
> the last few weeks had been really interesting.  Not that the shit has
> settled, but there was some slackening in the shitstorm last few days.
> Unlikely to last, I'm afraid, but...
>  
> > 
> > Hopefully this email will prompt a review, Al?
> Aside of the Eric's note re constifying struct path (strongly seconded),
> I'm not sure if expiration-related side of that is correct.  OTOH,
> since the expiration happens from userland...

Sure, I have a follow up series to do the constifying as recommended by Eric and
now yourself.

> 
> How much testing did it get?  I've several test setups involving
> autofs, but they are nowhere near exhaustive and I don't have good
> enough feel of the codebase to slap together something with decent
> coverage...

It got my standard testing.

For that I use a modified version of the autofs Connectathon system.

It's more about testing a wide variety of syntax and map setups and so exercises
a large number of different types of autofs mounts.

It's meant to check normal operation but not so much stress testing even though
it does perform quite a few mounts (around 250-300, not to mention the autofs
mounts themselves).

I have another standard test I call the submount-test and it was originally done
to stress test the most common problem I see, concurrent expire to mount.

I didn't see any problems I couldn't explain in these but I might need to re-
visit the submount-test to see if it is still doing what I want.

OTOH, the pattern of mount and umount I see when the submount-test is run does
look like it is doing what I want but it might not be getting all the way to the
top of the tree of mounts enough times over the course of the test.

So I'm happy with my testing, just not as happy as I could be.

Ian

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 6/8] autofs - use path_is_mountpoint() to fix unreliable d_mountpoint() checks
  2016-10-27  2:17   ` Al Viro
@ 2016-10-27  2:51     ` Ian Kent
  0 siblings, 0 replies; 18+ messages in thread
From: Ian Kent @ 2016-10-27  2:51 UTC (permalink / raw)
  To: Al Viro
  Cc: Andrew Morton, autofs mailing list, Kernel Mailing List,
	Eric W. Biederman, linux-fsdevel, Omar Sandoval

On Thu, 2016-10-27 at 03:17 +0100, Al Viro wrote:
> On Tue, Oct 11, 2016 at 01:34:18PM +0800, Ian Kent wrote:
> > 
> > +	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)) {
> Why not &file->f_path, provided that you constify that thing properly?

Yep, my bad, as pointed out by Eric.

Patches to fix that and constify a bunch of things will follow.

> 
> > 
> > +		if (rcu_walk) {
> > +			if (!path_is_mountpoint_rcu(path))
> > +				return -EISDIR;
> > +		} else {
> > +			if (!path_is_mountpoint(path))
> > +				return -EISDIR;
> IDGI.  What's the point of _having_ the _rcu() variant, anyway?  Here you
> are probably paying more in terms of i-cache footprint/branch prediction
> than you win on not doing that rcu_read_lock()/rcu_read_unlock()...
> 
> _rcu variants make sense when non-RCU case does something you can't do
> under RCU; here your path_is_mountpoint() is pretty close to being
> rcu_read_lock()+path_is_mountpoint_rcu()+rcu_read_unlock() anyway...

Again, my bad, I'll merge these two and post along with the follow up patches
above.

Thanks Al,
Ian

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/8] vfs - change d_manage() to take a struct path
  2016-10-27  2:47       ` Ian Kent
@ 2016-10-27  6:50         ` Ian Kent
  2016-11-01  2:02           ` Ian Kent
  0 siblings, 1 reply; 18+ messages in thread
From: Ian Kent @ 2016-10-27  6:50 UTC (permalink / raw)
  To: Al Viro
  Cc: Andrew Morton, autofs mailing list, Kernel Mailing List,
	Eric W. Biederman, linux-fsdevel, Omar Sandoval

On Thu, 2016-10-27 at 10:47 +0800, Ian Kent wrote:
> On Thu, 2016-10-27 at 03:11 +0100, Al Viro wrote:
> > 
> > 
> > How much testing did it get?  I've several test setups involving
> > autofs, but they are nowhere near exhaustive and I don't have good
> > enough feel of the codebase to slap together something with decent
> > coverage...
> It got my standard testing.
> 
> For that I use a modified version of the autofs Connectathon system.
> 
> It's more about testing a wide variety of syntax and map setups and so
> exercises
> a large number of different types of autofs mounts.
> 
> It's meant to check normal operation but not so much stress testing even
> though
> it does perform quite a few mounts (around 250-300, not to mention the autofs
> mounts themselves).
> 
> I have another standard test I call the submount-test and it was originally
> done
> to stress test the most common problem I see, concurrent expire to mount.
> 
> I didn't see any problems I couldn't explain in these but I might need to re-
> visit the submount-test to see if it is still doing what I want.
> 
> OTOH, the pattern of mount and umount I see when the submount-test is run does
> look like it is doing what I want but it might not be getting all the way to
> the
> top of the tree of mounts enough times over the course of the test.
> 
> So I'm happy with my testing, just not as happy as I could be.

Well, almost happy with my testing.

Naturally I also tested the specific case this series is meant to fix.

Basically:
ls /mnt/foo            # do the initial automount
unshare -m sleep 10 &  # hold the automount in a new namespace
umount /mnt/foo        # pretend the mount timed out
ls /mnt/foo            # try to access it again
ls: cannot open directory '/mnt/foo': Too many levels of symbolic links

as seen on the autofs mailing list. My specific test was a little different but
verified this was resolved.

Now that Al seems reasonably OK with the series, with some changes, I'll test
some other use cases, mainly to verify the expire still functions as required.
That might need more work.

Ian

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/8] vfs - change d_manage() to take a struct path
  2016-10-27  6:50         ` Ian Kent
@ 2016-11-01  2:02           ` Ian Kent
  0 siblings, 0 replies; 18+ messages in thread
From: Ian Kent @ 2016-11-01  2:02 UTC (permalink / raw)
  To: Al Viro
  Cc: Andrew Morton, autofs mailing list, Kernel Mailing List,
	Eric W. Biederman, linux-fsdevel, Omar Sandoval

On Thu, 2016-10-27 at 14:50 +0800, Ian Kent wrote:
> On Thu, 2016-10-27 at 10:47 +0800, Ian Kent wrote:
> > 
> > On Thu, 2016-10-27 at 03:11 +0100, Al Viro wrote:
> > > 
> > >  
> > > 
> > > How much testing did it get?  I've several test setups involving
> > > autofs, but they are nowhere near exhaustive and I don't have good
> > > enough feel of the codebase to slap together something with decent
> > > coverage...
> > It got my standard testing.
> > 
> > For that I use a modified version of the autofs Connectathon system.
> > 
> > It's more about testing a wide variety of syntax and map setups and so
> > exercises
> > a large number of different types of autofs mounts.
> > 
> > It's meant to check normal operation but not so much stress testing even
> > though
> > it does perform quite a few mounts (around 250-300, not to mention the
> > autofs
> > mounts themselves).
> > 
> > I have another standard test I call the submount-test and it was originally
> > done
> > to stress test the most common problem I see, concurrent expire to mount.
> > 
> > I didn't see any problems I couldn't explain in these but I might need to
> > re-
> > visit the submount-test to see if it is still doing what I want.
> > 
> > OTOH, the pattern of mount and umount I see when the submount-test is run
> > does
> > look like it is doing what I want but it might not be getting all the way to
> > the
> > top of the tree of mounts enough times over the course of the test.
> > 
> > So I'm happy with my testing, just not as happy as I could be.
> Well, almost happy with my testing.
> 
> Naturally I also tested the specific case this series is meant to fix.
> 
> Basically:
> ls /mnt/foo            # do the initial automount
> unshare -m sleep 10 &  # hold the automount in a new namespace
> umount /mnt/foo        # pretend the mount timed out
> ls /mnt/foo            # try to access it again
> ls: cannot open directory '/mnt/foo': Too many levels of symbolic links
> 
> as seen on the autofs mailing list. My specific test was a little different
> but
> verified this was resolved.
> 
> Now that Al seems reasonably OK with the series, with some changes, I'll test
> some other use cases, mainly to verify the expire still functions as required.
> That might need more work.

I have done some further tests, specifically for (what I believe are) the two
most common use cases.

First, using automount(8) entirely within a container, as expected works fine.

But the second case, one where automount(8) is run in the root namespace and has
automount directories bound into a container does have a problem.

The problem is due to may_umount_tree() only considering mounts in the root
namespace and leads to expire attempts on mounts even if they are in use in
another namespace.

It's not a serious problem as the umount attempt fails because the mount is busy
but it would be good to avoid the call back overhead.

Unfortunately it looks like transforming may_umount_tree() to use a similar
check to may_umount() introduces a race (picked up by my submount-test) which
I'm struggling to understand, I'll continue to work on it.

Ian

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2016-11-01  2:02 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-11  5:33 [PATCH 1/8] vfs - change d_manage() to take a struct path Ian Kent
2016-10-11  5:33 ` [PATCH 2/8] vfs - add path_is_mountpoint() helper Ian Kent
2016-10-11  5:34 ` [PATCH 3/8] vfs - add path_has_submounts() Ian Kent
2016-10-11  5:34 ` [PATCH 4/8] autofs - change autofs4_expire_wait() to take struct path Ian Kent
2016-10-11  5:34 ` [PATCH 5/8] autofs - change autofs4_wait() " Ian Kent
2016-10-11  5:34 ` [PATCH 6/8] autofs - use path_is_mountpoint() to fix unreliable d_mountpoint() checks Ian Kent
2016-10-27  2:17   ` Al Viro
2016-10-27  2:51     ` Ian Kent
2016-10-11  5:34 ` [PATCH 7/8] autofs - use path_has_submounts() to fix unreliable have_submount() checks Ian Kent
2016-10-11  5:34 ` [PATCH 8/8] vfs - remove unused have_submounts() function Ian Kent
2016-10-11 16:04 ` [PATCH 1/8] vfs - change d_manage() to take a struct path Eric W. Biederman
2016-10-11 23:47   ` Ian Kent
2016-10-19 19:40 ` Andrew Morton
2016-10-20 23:39   ` Ian Kent
2016-10-27  2:11     ` Al Viro
2016-10-27  2:47       ` Ian Kent
2016-10-27  6:50         ` Ian Kent
2016-11-01  2:02           ` Ian Kent

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.