summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorIan Kent <raven@themaw.net>2013-09-08 16:47:23 +0800
committerAl Viro <viro@zeniv.linux.org.uk>2013-09-08 22:07:47 -0400
commitac8387199656b019dcef5e3bbe029c2e9b01a195 (patch)
tree0527b48b9293e395fda4048bedcd410cc802eda8 /fs
parent2d8646510120bb1eb251ae3381e950805a877763 (diff)
downloadlinux-ac8387199656b019dcef5e3bbe029c2e9b01a195.tar.gz
linux-ac8387199656b019dcef5e3bbe029c2e9b01a195.tar.bz2
linux-ac8387199656b019dcef5e3bbe029c2e9b01a195.zip
autofs4 - fix device ioctl mount lookup
When reconnecting to automounts at startup an autofs ioctl is used to find the device and inode of existing mounts so they can be used to open a file descriptor of possibly covered mounts. At this time the the caller might not yet "own" the mount so it can trigger calling ->d_automount(). This causes automount to hang when trying to reconnect to direct or offset mount types. Consequently kern_path() can't be used but kern_path_mountpoint() can be. Signed-off-by: Ian Kent <raven@themaw.net> Cc: Jeff Layton <jlayton@redhat.com> Cc: Al Viro <viro@ZenIV.linux.org.uk> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/autofs4/dev-ioctl.c23
1 files changed, 12 insertions, 11 deletions
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c
index 743c7c2c949d..0f00da329e71 100644
--- a/fs/autofs4/dev-ioctl.c
+++ b/fs/autofs4/dev-ioctl.c
@@ -183,13 +183,14 @@ static int autofs_dev_ioctl_protosubver(struct file *fp,
return 0;
}
+/* Find the topmost mount satisfying test() */
static int find_autofs_mount(const char *pathname,
struct path *res,
int test(struct path *path, void *data),
void *data)
{
struct path path;
- int err = kern_path(pathname, 0, &path);
+ int err = kern_path_mountpoint(AT_FDCWD, pathname, &path, 0);
if (err)
return err;
err = -ENOENT;
@@ -197,10 +198,9 @@ static int find_autofs_mount(const char *pathname,
if (path.dentry->d_sb->s_magic == AUTOFS_SUPER_MAGIC) {
if (test(&path, data)) {
path_get(&path);
- if (!err) /* already found some */
- path_put(res);
*res = path;
err = 0;
+ break;
}
}
if (!follow_up(&path))
@@ -486,12 +486,11 @@ static int autofs_dev_ioctl_askumount(struct file *fp,
* mount if there is one or 0 if it isn't a mountpoint.
*
* If we aren't supplied with a file descriptor then we
- * lookup the nameidata of the path and check if it is the
- * root of a mount. If a type is given we are looking for
- * a particular autofs mount and if we don't find a match
- * we return fail. If the located nameidata path is the
- * root of a mount we return 1 along with the super magic
- * of the mount or 0 otherwise.
+ * lookup the path and check if it is the root of a mount.
+ * If a type is given we are looking for a particular autofs
+ * mount and if we don't find a match we return fail. If the
+ * located path is the root of a mount we return 1 along with
+ * the super magic of the mount or 0 otherwise.
*
* In both cases the the device number (as returned by
* new_encode_dev()) is also returned.
@@ -519,9 +518,11 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp,
if (!fp || param->ioctlfd == -1) {
if (autofs_type_any(type))
- err = kern_path(name, LOOKUP_FOLLOW, &path);
+ err = kern_path_mountpoint(AT_FDCWD,
+ name, &path, LOOKUP_FOLLOW);
else
- err = find_autofs_mount(name, &path, test_by_type, &type);
+ err = find_autofs_mount(name, &path,
+ test_by_type, &type);
if (err)
goto out;
devid = new_encode_dev(path.dentry->d_sb->s_dev);