Get rid of path_lookup in autofs4

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2009-04-07 11:08:56 -04:00
parent 73422811d2
commit 4e44b6852e

View File

@ -192,77 +192,42 @@ static int autofs_dev_ioctl_protosubver(struct file *fp,
return 0; return 0;
} }
/* static int find_autofs_mount(const char *pathname,
* Walk down the mount stack looking for an autofs mount that struct path *res,
* has the requested device number (aka. new_encode_dev(sb->s_dev). int test(struct path *path, void *data),
*/ void *data)
static int autofs_dev_ioctl_find_super(struct nameidata *nd, dev_t devno)
{ {
struct dentry *dentry; struct path path;
struct inode *inode; int err = kern_path(pathname, 0, &path);
struct super_block *sb; if (err)
dev_t s_dev; return err;
unsigned int err;
err = -ENOENT; err = -ENOENT;
while (path.dentry == path.mnt->mnt_root) {
/* Lookup the dentry name at the base of our mount point */ if (path.mnt->mnt_sb->s_magic == AUTOFS_SUPER_MAGIC) {
dentry = d_lookup(nd->path.dentry, &nd->last); if (test(&path, data)) {
if (!dentry) path_get(&path);
goto out; if (!err) /* already found some */
path_put(res);
dput(nd->path.dentry); *res = path;
nd->path.dentry = dentry;
/* And follow the mount stack looking for our autofs mount */
while (follow_down(&nd->path.mnt, &nd->path.dentry)) {
inode = nd->path.dentry->d_inode;
if (!inode)
break;
sb = inode->i_sb;
s_dev = new_encode_dev(sb->s_dev);
if (devno == s_dev) {
if (sb->s_magic == AUTOFS_SUPER_MAGIC) {
err = 0; err = 0;
break;
} }
} }
if (!follow_up(&path.mnt, &path.dentry))
break;
} }
out: path_put(&path);
return err; return err;
} }
/* static int test_by_dev(struct path *path, void *p)
* Walk down the mount stack looking for an autofs mount that
* has the requested mount type (ie. indirect, direct or offset).
*/
static int autofs_dev_ioctl_find_sbi_type(struct nameidata *nd, unsigned int type)
{ {
struct dentry *dentry; return path->mnt->mnt_sb->s_dev == *(dev_t *)p;
struct autofs_info *ino; }
unsigned int err;
err = -ENOENT; static int test_by_type(struct path *path, void *p)
{
/* Lookup the dentry name at the base of our mount point */ struct autofs_info *ino = autofs4_dentry_ino(path->dentry);
dentry = d_lookup(nd->path.dentry, &nd->last); return ino && ino->sbi->type & *(unsigned *)p;
if (!dentry)
goto out;
dput(nd->path.dentry);
nd->path.dentry = dentry;
/* And follow the mount stack looking for our autofs mount */
while (follow_down(&nd->path.mnt, &nd->path.dentry)) {
ino = autofs4_dentry_ino(nd->path.dentry);
if (ino && ino->sbi->type & type) {
err = 0;
break;
}
}
out:
return err;
} }
static void autofs_dev_ioctl_fd_install(unsigned int fd, struct file *file) static void autofs_dev_ioctl_fd_install(unsigned int fd, struct file *file)
@ -283,31 +248,25 @@ static void autofs_dev_ioctl_fd_install(unsigned int fd, struct file *file)
* Open a file descriptor on the autofs mount point corresponding * Open a file descriptor on the autofs mount point corresponding
* to the given path and device number (aka. new_encode_dev(sb->s_dev)). * to the given path and device number (aka. new_encode_dev(sb->s_dev)).
*/ */
static int autofs_dev_ioctl_open_mountpoint(const char *path, dev_t devid) static int autofs_dev_ioctl_open_mountpoint(const char *name, dev_t devid)
{ {
struct file *filp;
struct nameidata nd;
int err, fd; int err, fd;
fd = get_unused_fd(); fd = get_unused_fd();
if (likely(fd >= 0)) { if (likely(fd >= 0)) {
/* Get nameidata of the parent directory */ struct file *filp;
err = path_lookup(path, LOOKUP_PARENT, &nd); struct path path;
err = find_autofs_mount(name, &path, test_by_dev, &devid);
if (err) if (err)
goto out; goto out;
/* /*
* Search down, within the parent, looking for an * Find autofs super block that has the device number
* autofs super block that has the device number
* corresponding to the autofs fs we want to open. * corresponding to the autofs fs we want to open.
*/ */
err = autofs_dev_ioctl_find_super(&nd, devid);
if (err) {
path_put(&nd.path);
goto out;
}
filp = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY, filp = dentry_open(path.dentry, path.mnt, O_RDONLY,
current_cred()); current_cred());
if (IS_ERR(filp)) { if (IS_ERR(filp)) {
err = PTR_ERR(filp); err = PTR_ERR(filp);
@ -340,7 +299,7 @@ static int autofs_dev_ioctl_openmount(struct file *fp,
param->ioctlfd = -1; param->ioctlfd = -1;
path = param->path; path = param->path;
devid = param->openmount.devid; devid = new_decode_dev(param->openmount.devid);
err = 0; err = 0;
fd = autofs_dev_ioctl_open_mountpoint(path, devid); fd = autofs_dev_ioctl_open_mountpoint(path, devid);
@ -475,8 +434,7 @@ static int autofs_dev_ioctl_requester(struct file *fp,
struct autofs_dev_ioctl *param) struct autofs_dev_ioctl *param)
{ {
struct autofs_info *ino; struct autofs_info *ino;
struct nameidata nd; struct path path;
const char *path;
dev_t devid; dev_t devid;
int err = -ENOENT; int err = -ENOENT;
@ -485,32 +443,24 @@ static int autofs_dev_ioctl_requester(struct file *fp,
goto out; goto out;
} }
path = param->path; devid = sbi->sb->s_dev;
devid = new_encode_dev(sbi->sb->s_dev);
param->requester.uid = param->requester.gid = -1; param->requester.uid = param->requester.gid = -1;
/* Get nameidata of the parent directory */ err = find_autofs_mount(param->path, &path, test_by_dev, &devid);
err = path_lookup(path, LOOKUP_PARENT, &nd);
if (err) if (err)
goto out; goto out;
err = autofs_dev_ioctl_find_super(&nd, devid); ino = autofs4_dentry_ino(path.dentry);
if (err)
goto out_release;
ino = autofs4_dentry_ino(nd.path.dentry);
if (ino) { if (ino) {
err = 0; err = 0;
autofs4_expire_wait(nd.path.dentry); autofs4_expire_wait(path.dentry);
spin_lock(&sbi->fs_lock); spin_lock(&sbi->fs_lock);
param->requester.uid = ino->uid; param->requester.uid = ino->uid;
param->requester.gid = ino->gid; param->requester.gid = ino->gid;
spin_unlock(&sbi->fs_lock); spin_unlock(&sbi->fs_lock);
} }
path_put(&path);
out_release:
path_put(&nd.path);
out: out:
return err; return err;
} }
@ -569,8 +519,8 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp,
struct autofs_sb_info *sbi, struct autofs_sb_info *sbi,
struct autofs_dev_ioctl *param) struct autofs_dev_ioctl *param)
{ {
struct nameidata nd; struct path path;
const char *path; const char *name;
unsigned int type; unsigned int type;
unsigned int devid, magic; unsigned int devid, magic;
int err = -ENOENT; int err = -ENOENT;
@ -580,71 +530,46 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp,
goto out; goto out;
} }
path = param->path; name = param->path;
type = param->ismountpoint.in.type; type = param->ismountpoint.in.type;
param->ismountpoint.out.devid = devid = 0; param->ismountpoint.out.devid = devid = 0;
param->ismountpoint.out.magic = magic = 0; param->ismountpoint.out.magic = magic = 0;
if (!fp || param->ioctlfd == -1) { if (!fp || param->ioctlfd == -1) {
if (autofs_type_any(type)) { if (autofs_type_any(type))
struct super_block *sb; err = kern_path(name, LOOKUP_FOLLOW, &path);
else
err = path_lookup(path, LOOKUP_FOLLOW, &nd); err = find_autofs_mount(name, &path, test_by_type, &type);
if (err) if (err)
goto out; goto out;
devid = new_encode_dev(path.mnt->mnt_sb->s_dev);
sb = nd.path.dentry->d_sb;
devid = new_encode_dev(sb->s_dev);
} else {
struct autofs_info *ino;
err = path_lookup(path, LOOKUP_PARENT, &nd);
if (err)
goto out;
err = autofs_dev_ioctl_find_sbi_type(&nd, type);
if (err)
goto out_release;
ino = autofs4_dentry_ino(nd.path.dentry);
devid = autofs4_get_dev(ino->sbi);
}
err = 0; err = 0;
if (nd.path.dentry->d_inode && if (path.dentry->d_inode &&
nd.path.mnt->mnt_root == nd.path.dentry) { path.mnt->mnt_root == path.dentry) {
err = 1; err = 1;
magic = nd.path.dentry->d_inode->i_sb->s_magic; magic = path.dentry->d_inode->i_sb->s_magic;
} }
} else { } else {
dev_t dev = autofs4_get_dev(sbi); dev_t dev = sbi->sb->s_dev;
err = path_lookup(path, LOOKUP_PARENT, &nd); err = find_autofs_mount(name, &path, test_by_dev, &dev);
if (err) if (err)
goto out; goto out;
err = autofs_dev_ioctl_find_super(&nd, dev); devid = new_encode_dev(dev);
if (err)
goto out_release;
devid = dev; err = have_submounts(path.dentry);
err = have_submounts(nd.path.dentry); if (path.mnt->mnt_mountpoint != path.mnt->mnt_root) {
if (follow_down(&path.mnt, &path.dentry))
if (nd.path.mnt->mnt_mountpoint != nd.path.mnt->mnt_root) { magic = path.mnt->mnt_sb->s_magic;
if (follow_down(&nd.path.mnt, &nd.path.dentry)) {
struct inode *inode = nd.path.dentry->d_inode;
magic = inode->i_sb->s_magic;
}
} }
} }
param->ismountpoint.out.devid = devid; param->ismountpoint.out.devid = devid;
param->ismountpoint.out.magic = magic; param->ismountpoint.out.magic = magic;
path_put(&path);
out_release:
path_put(&nd.path);
out: out:
return err; return err;
} }