LOOKUP_MOUNTPOINT: fold path_mountpointat() into path_lookupat()
New LOOKUP flag, telling path_lookupat() to act as path_mountpointat(). IOW, traverse mounts at the final point and skip revalidation of the location where it ends up. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
cbae4d12ee
commit
161aff1d93
@ -186,7 +186,7 @@ static int find_autofs_mount(const char *pathname,
|
|||||||
struct path path;
|
struct path path;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = kern_path_mountpoint(AT_FDCWD, pathname, &path, 0);
|
err = kern_path(pathname, LOOKUP_MOUNTPOINT, &path);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
err = -ENOENT;
|
err = -ENOENT;
|
||||||
@ -519,8 +519,8 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp,
|
|||||||
|
|
||||||
if (!fp || param->ioctlfd == -1) {
|
if (!fp || param->ioctlfd == -1) {
|
||||||
if (autofs_type_any(type))
|
if (autofs_type_any(type))
|
||||||
err = kern_path_mountpoint(AT_FDCWD,
|
err = kern_path(name, LOOKUP_FOLLOW | LOOKUP_MOUNTPOINT,
|
||||||
name, &path, LOOKUP_FOLLOW);
|
&path);
|
||||||
else
|
else
|
||||||
err = find_autofs_mount(name, &path,
|
err = find_autofs_mount(name, &path,
|
||||||
test_by_type, &type);
|
test_by_type, &type);
|
||||||
|
@ -61,7 +61,6 @@ extern int finish_clean_context(struct fs_context *fc);
|
|||||||
*/
|
*/
|
||||||
extern int filename_lookup(int dfd, struct filename *name, unsigned flags,
|
extern int filename_lookup(int dfd, struct filename *name, unsigned flags,
|
||||||
struct path *path, struct path *root);
|
struct path *path, struct path *root);
|
||||||
extern int user_path_mountpoint_at(int, const char __user *, unsigned int, struct path *);
|
|
||||||
extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
|
extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
|
||||||
const char *, unsigned int, struct path *);
|
const char *, unsigned int, struct path *);
|
||||||
long do_mknodat(int dfd, const char __user *filename, umode_t mode,
|
long do_mknodat(int dfd, const char __user *filename, umode_t mode,
|
||||||
|
89
fs/namei.c
89
fs/namei.c
@ -2382,6 +2382,10 @@ static int path_lookupat(struct nameidata *nd, unsigned flags, struct path *path
|
|||||||
if (!err && nd->flags & LOOKUP_DIRECTORY)
|
if (!err && nd->flags & LOOKUP_DIRECTORY)
|
||||||
if (!d_can_lookup(nd->path.dentry))
|
if (!d_can_lookup(nd->path.dentry))
|
||||||
err = -ENOTDIR;
|
err = -ENOTDIR;
|
||||||
|
if (!err && unlikely(nd->flags & LOOKUP_MOUNTPOINT)) {
|
||||||
|
err = handle_lookup_down(nd);
|
||||||
|
nd->flags &= ~LOOKUP_JUMPED; // no d_weak_revalidate(), please...
|
||||||
|
}
|
||||||
if (!err) {
|
if (!err) {
|
||||||
*path = nd->path;
|
*path = nd->path;
|
||||||
nd->path.mnt = NULL;
|
nd->path.mnt = NULL;
|
||||||
@ -2410,7 +2414,8 @@ int filename_lookup(int dfd, struct filename *name, unsigned flags,
|
|||||||
retval = path_lookupat(&nd, flags | LOOKUP_REVAL, path);
|
retval = path_lookupat(&nd, flags | LOOKUP_REVAL, path);
|
||||||
|
|
||||||
if (likely(!retval))
|
if (likely(!retval))
|
||||||
audit_inode(name, path->dentry, 0);
|
audit_inode(name, path->dentry,
|
||||||
|
flags & LOOKUP_MOUNTPOINT ? AUDIT_INODE_NOEVAL : 0);
|
||||||
restore_nameidata();
|
restore_nameidata();
|
||||||
putname(name);
|
putname(name);
|
||||||
return retval;
|
return retval;
|
||||||
@ -2688,88 +2693,6 @@ int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(user_path_at_empty);
|
EXPORT_SYMBOL(user_path_at_empty);
|
||||||
|
|
||||||
/**
|
|
||||||
* path_mountpoint - look up a path to be umounted
|
|
||||||
* @nd: lookup context
|
|
||||||
* @flags: lookup flags
|
|
||||||
* @path: pointer to container for result
|
|
||||||
*
|
|
||||||
* Look up the given name, but don't attempt to revalidate the last component.
|
|
||||||
* Returns 0 and "path" will be valid on success; Returns error otherwise.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
path_mountpoint(struct nameidata *nd, unsigned flags, struct path *path)
|
|
||||||
{
|
|
||||||
const char *s = path_init(nd, flags);
|
|
||||||
int err;
|
|
||||||
|
|
||||||
while (!(err = link_path_walk(s, nd)) &&
|
|
||||||
(err = lookup_last(nd)) > 0) {
|
|
||||||
s = trailing_symlink(nd);
|
|
||||||
}
|
|
||||||
if (!err && (nd->flags & LOOKUP_RCU))
|
|
||||||
err = unlazy_walk(nd);
|
|
||||||
if (!err)
|
|
||||||
err = handle_lookup_down(nd);
|
|
||||||
if (!err) {
|
|
||||||
*path = nd->path;
|
|
||||||
nd->path.mnt = NULL;
|
|
||||||
nd->path.dentry = NULL;
|
|
||||||
}
|
|
||||||
terminate_walk(nd);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
filename_mountpoint(int dfd, struct filename *name, struct path *path,
|
|
||||||
unsigned int flags)
|
|
||||||
{
|
|
||||||
struct nameidata nd;
|
|
||||||
int error;
|
|
||||||
if (IS_ERR(name))
|
|
||||||
return PTR_ERR(name);
|
|
||||||
set_nameidata(&nd, dfd, name);
|
|
||||||
error = path_mountpoint(&nd, flags | LOOKUP_RCU, path);
|
|
||||||
if (unlikely(error == -ECHILD))
|
|
||||||
error = path_mountpoint(&nd, flags, path);
|
|
||||||
if (unlikely(error == -ESTALE))
|
|
||||||
error = path_mountpoint(&nd, flags | LOOKUP_REVAL, path);
|
|
||||||
if (likely(!error))
|
|
||||||
audit_inode(name, path->dentry, AUDIT_INODE_NOEVAL);
|
|
||||||
restore_nameidata();
|
|
||||||
putname(name);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* user_path_mountpoint_at - lookup a path from userland in order to umount it
|
|
||||||
* @dfd: directory file descriptor
|
|
||||||
* @name: pathname from userland
|
|
||||||
* @flags: lookup flags
|
|
||||||
* @path: pointer to container to hold result
|
|
||||||
*
|
|
||||||
* A umount is a special case for path walking. We're not actually interested
|
|
||||||
* in the inode in this situation, and ESTALE errors can be a problem. We
|
|
||||||
* simply want track down the dentry and vfsmount attached at the mountpoint
|
|
||||||
* and avoid revalidating the last component.
|
|
||||||
*
|
|
||||||
* Returns 0 and populates "path" on success.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
user_path_mountpoint_at(int dfd, const char __user *name, unsigned int flags,
|
|
||||||
struct path *path)
|
|
||||||
{
|
|
||||||
return filename_mountpoint(dfd, getname(name), path, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
kern_path_mountpoint(int dfd, const char *name, struct path *path,
|
|
||||||
unsigned int flags)
|
|
||||||
{
|
|
||||||
return filename_mountpoint(dfd, getname_kernel(name), path, flags);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(kern_path_mountpoint);
|
|
||||||
|
|
||||||
int __check_sticky(struct inode *dir, struct inode *inode)
|
int __check_sticky(struct inode *dir, struct inode *inode)
|
||||||
{
|
{
|
||||||
kuid_t fsuid = current_fsuid();
|
kuid_t fsuid = current_fsuid();
|
||||||
|
@ -1669,7 +1669,7 @@ int ksys_umount(char __user *name, int flags)
|
|||||||
struct path path;
|
struct path path;
|
||||||
struct mount *mnt;
|
struct mount *mnt;
|
||||||
int retval;
|
int retval;
|
||||||
int lookup_flags = 0;
|
int lookup_flags = LOOKUP_MOUNTPOINT;
|
||||||
|
|
||||||
if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW))
|
if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -1680,7 +1680,7 @@ int ksys_umount(char __user *name, int flags)
|
|||||||
if (!(flags & UMOUNT_NOFOLLOW))
|
if (!(flags & UMOUNT_NOFOLLOW))
|
||||||
lookup_flags |= LOOKUP_FOLLOW;
|
lookup_flags |= LOOKUP_FOLLOW;
|
||||||
|
|
||||||
retval = user_path_mountpoint_at(AT_FDCWD, name, lookup_flags, &path);
|
retval = user_path_at(AT_FDCWD, name, lookup_flags, &path);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto out;
|
goto out;
|
||||||
mnt = real_mount(path.mnt);
|
mnt = real_mount(path.mnt);
|
||||||
|
@ -23,6 +23,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
|
|||||||
#define LOOKUP_AUTOMOUNT 0x0004 /* force terminal automount */
|
#define LOOKUP_AUTOMOUNT 0x0004 /* force terminal automount */
|
||||||
#define LOOKUP_EMPTY 0x4000 /* accept empty path [user_... only] */
|
#define LOOKUP_EMPTY 0x4000 /* accept empty path [user_... only] */
|
||||||
#define LOOKUP_DOWN 0x8000 /* follow mounts in the starting point */
|
#define LOOKUP_DOWN 0x8000 /* follow mounts in the starting point */
|
||||||
|
#define LOOKUP_MOUNTPOINT 0x0080 /* follow mounts in the end */
|
||||||
|
|
||||||
#define LOOKUP_REVAL 0x0020 /* tell ->d_revalidate() to trust no cache */
|
#define LOOKUP_REVAL 0x0020 /* tell ->d_revalidate() to trust no cache */
|
||||||
#define LOOKUP_RCU 0x0040 /* RCU pathwalk mode; semi-internal */
|
#define LOOKUP_RCU 0x0040 /* RCU pathwalk mode; semi-internal */
|
||||||
@ -64,7 +65,6 @@ extern struct dentry *kern_path_create(int, const char *, struct path *, unsigne
|
|||||||
extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int);
|
extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int);
|
||||||
extern void done_path_create(struct path *, struct dentry *);
|
extern void done_path_create(struct path *, struct dentry *);
|
||||||
extern struct dentry *kern_path_locked(const char *, struct path *);
|
extern struct dentry *kern_path_locked(const char *, struct path *);
|
||||||
extern int kern_path_mountpoint(int, const char *, struct path *, unsigned int);
|
|
||||||
|
|
||||||
extern struct dentry *try_lookup_one_len(const char *, struct dentry *, int);
|
extern struct dentry *try_lookup_one_len(const char *, struct dentry *, int);
|
||||||
extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
|
extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
|
||||||
|
Loading…
Reference in New Issue
Block a user