forked from Minki/linux
Merge branch 'work.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs name lookup updates from Al Viro: "Small namei.c patch series, mostly to simplify the rules for nameidata state. It's actually from the previous cycle - but I didn't post it for review in time... Changes visible outside of fs/namei.c: file_open_root() calling conventions change, some freed bits in LOOKUP_... space" * 'work.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: namei: make sure nd->depth is always valid teach set_nameidata() to handle setting the root as well take LOOKUP_{ROOT,ROOT_GRABBED,JUMPED} out of LOOKUP_... space switch file_open_root() to struct path
This commit is contained in:
commit
58ec9059b3
@ -1297,18 +1297,18 @@ to lookup: RCU-walk, REF-walk, and REF-walk with forced revalidation.
|
||||
yet. This is primarily used to tell the audit subsystem the full
|
||||
context of a particular access being audited.
|
||||
|
||||
``LOOKUP_ROOT`` indicates that the ``root`` field in the ``nameidata`` was
|
||||
``ND_ROOT_PRESET`` indicates that the ``root`` field in the ``nameidata`` was
|
||||
provided by the caller, so it shouldn't be released when it is no
|
||||
longer needed.
|
||||
|
||||
``LOOKUP_JUMPED`` means that the current dentry was chosen not because
|
||||
``ND_JUMPED`` means that the current dentry was chosen not because
|
||||
it had the right name but for some other reason. This happens when
|
||||
following "``..``", following a symlink to ``/``, crossing a mount point
|
||||
or accessing a "``/proc/$PID/fd/$FD``" symlink (also known as a "magic
|
||||
link"). In this case the filesystem has not been asked to revalidate the
|
||||
name (with ``d_revalidate()``). In such cases the inode may still need
|
||||
to be revalidated, so ``d_op->d_weak_revalidate()`` is called if
|
||||
``LOOKUP_JUMPED`` is set when the look completes - which may be at the
|
||||
``ND_JUMPED`` is set when the look completes - which may be at the
|
||||
final component or, when creating, unlinking, or renaming, at the penultimate component.
|
||||
|
||||
Resolution-restriction flags
|
||||
|
@ -899,3 +899,12 @@ iov_iter_copy_from_user_atomic() is gone; use copy_page_from_iter_atomic().
|
||||
The difference is copy_page_from_iter_atomic() advances the iterator and
|
||||
you don't need iov_iter_advance() after it. However, if you decide to use
|
||||
only a part of obtained data, you should do iov_iter_revert().
|
||||
|
||||
---
|
||||
|
||||
**mandatory**
|
||||
|
||||
Calling conventions for file_open_root() changed; now it takes struct path *
|
||||
instead of passing mount and dentry separately. For callers that used to
|
||||
pass <mnt, mnt->mnt_root> pair (i.e. the root of given mount), a new helper
|
||||
is provided - file_open_root_mnt(). In-tree users adjusted.
|
||||
|
@ -141,7 +141,7 @@ void mconsole_proc(struct mc_request *req)
|
||||
mconsole_reply(req, "Proc not available", 1, 0);
|
||||
goto out;
|
||||
}
|
||||
file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY, 0);
|
||||
file = file_open_root_mnt(mnt, ptr, O_RDONLY, 0);
|
||||
if (IS_ERR(file)) {
|
||||
mconsole_reply(req, "Failed to open file", 1, 0);
|
||||
printk(KERN_ERR "open /proc/%s: %ld\n", ptr, PTR_ERR(file));
|
||||
|
@ -755,8 +755,8 @@ void do_coredump(const kernel_siginfo_t *siginfo)
|
||||
task_lock(&init_task);
|
||||
get_fs_root(init_task.fs, &root);
|
||||
task_unlock(&init_task);
|
||||
cprm.file = file_open_root(root.dentry, root.mnt,
|
||||
cn.corename, open_flags, 0600);
|
||||
cprm.file = file_open_root(&root, cn.corename,
|
||||
open_flags, 0600);
|
||||
path_put(&root);
|
||||
} else {
|
||||
cprm.file = filp_open(cn.corename, open_flags, 0600);
|
||||
|
@ -229,7 +229,7 @@ static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
|
||||
path_put(&path);
|
||||
return fd;
|
||||
}
|
||||
file = file_open_root(path.dentry, path.mnt, "", open_flag, 0);
|
||||
file = file_open_root(&path, "", open_flag, 0);
|
||||
if (IS_ERR(file)) {
|
||||
put_unused_fd(fd);
|
||||
retval = PTR_ERR(file);
|
||||
|
@ -129,7 +129,7 @@ struct open_flags {
|
||||
};
|
||||
extern struct file *do_filp_open(int dfd, struct filename *pathname,
|
||||
const struct open_flags *op);
|
||||
extern struct file *do_file_open_root(struct dentry *, struct vfsmount *,
|
||||
extern struct file *do_file_open_root(const struct path *,
|
||||
const char *, const struct open_flags *);
|
||||
extern struct open_how build_open_how(int flags, umode_t mode);
|
||||
extern int build_open_flags(const struct open_how *how, struct open_flags *op);
|
||||
|
@ -160,7 +160,7 @@ int kernel_read_file_from_path_initns(const char *path, loff_t offset,
|
||||
get_fs_root(init_task.fs, &root);
|
||||
task_unlock(&init_task);
|
||||
|
||||
file = file_open_root(root.dentry, root.mnt, path, O_RDONLY, 0);
|
||||
file = file_open_root(&root, path, O_RDONLY, 0);
|
||||
path_put(&root);
|
||||
if (IS_ERR(file))
|
||||
return PTR_ERR(file);
|
||||
|
80
fs/namei.c
80
fs/namei.c
@ -554,7 +554,7 @@ struct nameidata {
|
||||
struct qstr last;
|
||||
struct path root;
|
||||
struct inode *inode; /* path.dentry.d_inode */
|
||||
unsigned int flags;
|
||||
unsigned int flags, state;
|
||||
unsigned seq, m_seq, r_seq;
|
||||
int last_type;
|
||||
unsigned depth;
|
||||
@ -573,10 +573,15 @@ struct nameidata {
|
||||
umode_t dir_mode;
|
||||
} __randomize_layout;
|
||||
|
||||
static void set_nameidata(struct nameidata *p, int dfd, struct filename *name)
|
||||
#define ND_ROOT_PRESET 1
|
||||
#define ND_ROOT_GRABBED 2
|
||||
#define ND_JUMPED 4
|
||||
|
||||
static void __set_nameidata(struct nameidata *p, int dfd, struct filename *name)
|
||||
{
|
||||
struct nameidata *old = current->nameidata;
|
||||
p->stack = p->internal;
|
||||
p->depth = 0;
|
||||
p->dfd = dfd;
|
||||
p->name = name;
|
||||
p->path.mnt = NULL;
|
||||
@ -586,6 +591,17 @@ static void set_nameidata(struct nameidata *p, int dfd, struct filename *name)
|
||||
current->nameidata = p;
|
||||
}
|
||||
|
||||
static inline void set_nameidata(struct nameidata *p, int dfd, struct filename *name,
|
||||
const struct path *root)
|
||||
{
|
||||
__set_nameidata(p, dfd, name);
|
||||
p->state = 0;
|
||||
if (unlikely(root)) {
|
||||
p->state = ND_ROOT_PRESET;
|
||||
p->root = *root;
|
||||
}
|
||||
}
|
||||
|
||||
static void restore_nameidata(void)
|
||||
{
|
||||
struct nameidata *now = current->nameidata, *old = now->saved;
|
||||
@ -645,9 +661,9 @@ static void terminate_walk(struct nameidata *nd)
|
||||
path_put(&nd->path);
|
||||
for (i = 0; i < nd->depth; i++)
|
||||
path_put(&nd->stack[i].link);
|
||||
if (nd->flags & LOOKUP_ROOT_GRABBED) {
|
||||
if (nd->state & ND_ROOT_GRABBED) {
|
||||
path_put(&nd->root);
|
||||
nd->flags &= ~LOOKUP_ROOT_GRABBED;
|
||||
nd->state &= ~ND_ROOT_GRABBED;
|
||||
}
|
||||
} else {
|
||||
nd->flags &= ~LOOKUP_RCU;
|
||||
@ -710,9 +726,9 @@ static bool legitimize_root(struct nameidata *nd)
|
||||
if (!nd->root.mnt && (nd->flags & LOOKUP_IS_SCOPED))
|
||||
return false;
|
||||
/* Nothing to do if nd->root is zero or is managed by the VFS user. */
|
||||
if (!nd->root.mnt || (nd->flags & LOOKUP_ROOT))
|
||||
if (!nd->root.mnt || (nd->state & ND_ROOT_PRESET))
|
||||
return true;
|
||||
nd->flags |= LOOKUP_ROOT_GRABBED;
|
||||
nd->state |= ND_ROOT_GRABBED;
|
||||
return legitimize_path(nd, &nd->root, nd->root_seq);
|
||||
}
|
||||
|
||||
@ -849,8 +865,9 @@ static int complete_walk(struct nameidata *nd)
|
||||
* We don't want to zero nd->root for scoped-lookups or
|
||||
* externally-managed nd->root.
|
||||
*/
|
||||
if (!(nd->flags & (LOOKUP_ROOT | LOOKUP_IS_SCOPED)))
|
||||
nd->root.mnt = NULL;
|
||||
if (!(nd->state & ND_ROOT_PRESET))
|
||||
if (!(nd->flags & LOOKUP_IS_SCOPED))
|
||||
nd->root.mnt = NULL;
|
||||
nd->flags &= ~LOOKUP_CACHED;
|
||||
if (!try_to_unlazy(nd))
|
||||
return -ECHILD;
|
||||
@ -877,7 +894,7 @@ static int complete_walk(struct nameidata *nd)
|
||||
return -EXDEV;
|
||||
}
|
||||
|
||||
if (likely(!(nd->flags & LOOKUP_JUMPED)))
|
||||
if (likely(!(nd->state & ND_JUMPED)))
|
||||
return 0;
|
||||
|
||||
if (likely(!(dentry->d_flags & DCACHE_OP_WEAK_REVALIDATE)))
|
||||
@ -915,7 +932,7 @@ static int set_root(struct nameidata *nd)
|
||||
} while (read_seqcount_retry(&fs->seq, seq));
|
||||
} else {
|
||||
get_fs_root(fs, &nd->root);
|
||||
nd->flags |= LOOKUP_ROOT_GRABBED;
|
||||
nd->state |= ND_ROOT_GRABBED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -948,7 +965,7 @@ static int nd_jump_root(struct nameidata *nd)
|
||||
path_get(&nd->path);
|
||||
nd->inode = nd->path.dentry->d_inode;
|
||||
}
|
||||
nd->flags |= LOOKUP_JUMPED;
|
||||
nd->state |= ND_JUMPED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -976,7 +993,7 @@ int nd_jump_link(struct path *path)
|
||||
path_put(&nd->path);
|
||||
nd->path = *path;
|
||||
nd->inode = nd->path.dentry->d_inode;
|
||||
nd->flags |= LOOKUP_JUMPED;
|
||||
nd->state |= ND_JUMPED;
|
||||
return 0;
|
||||
|
||||
err:
|
||||
@ -1423,7 +1440,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
|
||||
if (mounted) {
|
||||
path->mnt = &mounted->mnt;
|
||||
dentry = path->dentry = mounted->mnt.mnt_root;
|
||||
nd->flags |= LOOKUP_JUMPED;
|
||||
nd->state |= ND_JUMPED;
|
||||
*seqp = read_seqcount_begin(&dentry->d_seq);
|
||||
*inode = dentry->d_inode;
|
||||
/*
|
||||
@ -1468,7 +1485,7 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry,
|
||||
if (unlikely(nd->flags & LOOKUP_NO_XDEV))
|
||||
ret = -EXDEV;
|
||||
else
|
||||
nd->flags |= LOOKUP_JUMPED;
|
||||
nd->state |= ND_JUMPED;
|
||||
}
|
||||
if (unlikely(ret)) {
|
||||
dput(path->dentry);
|
||||
@ -2219,7 +2236,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
|
||||
case 2:
|
||||
if (name[1] == '.') {
|
||||
type = LAST_DOTDOT;
|
||||
nd->flags |= LOOKUP_JUMPED;
|
||||
nd->state |= ND_JUMPED;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
@ -2227,7 +2244,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
|
||||
}
|
||||
if (likely(type == LAST_NORM)) {
|
||||
struct dentry *parent = nd->path.dentry;
|
||||
nd->flags &= ~LOOKUP_JUMPED;
|
||||
nd->state &= ~ND_JUMPED;
|
||||
if (unlikely(parent->d_flags & DCACHE_OP_HASH)) {
|
||||
struct qstr this = { { .hash_len = hash_len }, .name = name };
|
||||
err = parent->d_op->d_hash(parent, &this);
|
||||
@ -2301,14 +2318,14 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
|
||||
if (flags & LOOKUP_RCU)
|
||||
rcu_read_lock();
|
||||
|
||||
nd->flags = flags | LOOKUP_JUMPED;
|
||||
nd->depth = 0;
|
||||
nd->flags = flags;
|
||||
nd->state |= ND_JUMPED;
|
||||
|
||||
nd->m_seq = __read_seqcount_begin(&mount_lock.seqcount);
|
||||
nd->r_seq = __read_seqcount_begin(&rename_lock.seqcount);
|
||||
smp_rmb();
|
||||
|
||||
if (flags & LOOKUP_ROOT) {
|
||||
if (nd->state & ND_ROOT_PRESET) {
|
||||
struct dentry *root = nd->root.dentry;
|
||||
struct inode *inode = root->d_inode;
|
||||
if (*s && unlikely(!d_can_lookup(root)))
|
||||
@ -2383,7 +2400,7 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
|
||||
nd->root_seq = nd->seq;
|
||||
} else {
|
||||
path_get(&nd->root);
|
||||
nd->flags |= LOOKUP_ROOT_GRABBED;
|
||||
nd->state |= ND_ROOT_GRABBED;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
@ -2422,7 +2439,7 @@ static int path_lookupat(struct nameidata *nd, unsigned flags, struct path *path
|
||||
;
|
||||
if (!err && unlikely(nd->flags & LOOKUP_MOUNTPOINT)) {
|
||||
err = handle_lookup_down(nd);
|
||||
nd->flags &= ~LOOKUP_JUMPED; // no d_weak_revalidate(), please...
|
||||
nd->state &= ~ND_JUMPED; // no d_weak_revalidate(), please...
|
||||
}
|
||||
if (!err)
|
||||
err = complete_walk(nd);
|
||||
@ -2446,11 +2463,7 @@ int filename_lookup(int dfd, struct filename *name, unsigned flags,
|
||||
struct nameidata nd;
|
||||
if (IS_ERR(name))
|
||||
return PTR_ERR(name);
|
||||
if (unlikely(root)) {
|
||||
nd.root = *root;
|
||||
flags |= LOOKUP_ROOT;
|
||||
}
|
||||
set_nameidata(&nd, dfd, name);
|
||||
set_nameidata(&nd, dfd, name, root);
|
||||
retval = path_lookupat(&nd, flags | LOOKUP_RCU, path);
|
||||
if (unlikely(retval == -ECHILD))
|
||||
retval = path_lookupat(&nd, flags, path);
|
||||
@ -2491,7 +2504,7 @@ static struct filename *filename_parentat(int dfd, struct filename *name,
|
||||
|
||||
if (IS_ERR(name))
|
||||
return name;
|
||||
set_nameidata(&nd, dfd, name);
|
||||
set_nameidata(&nd, dfd, name, NULL);
|
||||
retval = path_parentat(&nd, flags | LOOKUP_RCU, parent);
|
||||
if (unlikely(retval == -ECHILD))
|
||||
retval = path_parentat(&nd, flags, parent);
|
||||
@ -3517,7 +3530,7 @@ struct file *do_filp_open(int dfd, struct filename *pathname,
|
||||
int flags = op->lookup_flags;
|
||||
struct file *filp;
|
||||
|
||||
set_nameidata(&nd, dfd, pathname);
|
||||
set_nameidata(&nd, dfd, pathname, NULL);
|
||||
filp = path_openat(&nd, op, flags | LOOKUP_RCU);
|
||||
if (unlikely(filp == ERR_PTR(-ECHILD)))
|
||||
filp = path_openat(&nd, op, flags);
|
||||
@ -3527,25 +3540,22 @@ struct file *do_filp_open(int dfd, struct filename *pathname,
|
||||
return filp;
|
||||
}
|
||||
|
||||
struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
|
||||
struct file *do_file_open_root(const struct path *root,
|
||||
const char *name, const struct open_flags *op)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct file *file;
|
||||
struct filename *filename;
|
||||
int flags = op->lookup_flags | LOOKUP_ROOT;
|
||||
int flags = op->lookup_flags;
|
||||
|
||||
nd.root.mnt = mnt;
|
||||
nd.root.dentry = dentry;
|
||||
|
||||
if (d_is_symlink(dentry) && op->intent & LOOKUP_OPEN)
|
||||
if (d_is_symlink(root->dentry) && op->intent & LOOKUP_OPEN)
|
||||
return ERR_PTR(-ELOOP);
|
||||
|
||||
filename = getname_kernel(name);
|
||||
if (IS_ERR(filename))
|
||||
return ERR_CAST(filename);
|
||||
|
||||
set_nameidata(&nd, -1, filename);
|
||||
set_nameidata(&nd, -1, filename, root);
|
||||
file = path_openat(&nd, op, flags | LOOKUP_RCU);
|
||||
if (unlikely(file == ERR_PTR(-ECHILD)))
|
||||
file = path_openat(&nd, op, flags);
|
||||
|
@ -280,8 +280,6 @@ TRACE_DEFINE_ENUM(LOOKUP_OPEN);
|
||||
TRACE_DEFINE_ENUM(LOOKUP_CREATE);
|
||||
TRACE_DEFINE_ENUM(LOOKUP_EXCL);
|
||||
TRACE_DEFINE_ENUM(LOOKUP_RENAME_TARGET);
|
||||
TRACE_DEFINE_ENUM(LOOKUP_JUMPED);
|
||||
TRACE_DEFINE_ENUM(LOOKUP_ROOT);
|
||||
TRACE_DEFINE_ENUM(LOOKUP_EMPTY);
|
||||
TRACE_DEFINE_ENUM(LOOKUP_DOWN);
|
||||
|
||||
@ -297,8 +295,6 @@ TRACE_DEFINE_ENUM(LOOKUP_DOWN);
|
||||
{ LOOKUP_CREATE, "CREATE" }, \
|
||||
{ LOOKUP_EXCL, "EXCL" }, \
|
||||
{ LOOKUP_RENAME_TARGET, "RENAME_TARGET" }, \
|
||||
{ LOOKUP_JUMPED, "JUMPED" }, \
|
||||
{ LOOKUP_ROOT, "ROOT" }, \
|
||||
{ LOOKUP_EMPTY, "EMPTY" }, \
|
||||
{ LOOKUP_DOWN, "DOWN" })
|
||||
|
||||
|
@ -1173,7 +1173,7 @@ struct file *filp_open(const char *filename, int flags, umode_t mode)
|
||||
}
|
||||
EXPORT_SYMBOL(filp_open);
|
||||
|
||||
struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
|
||||
struct file *file_open_root(const struct path *root,
|
||||
const char *filename, int flags, umode_t mode)
|
||||
{
|
||||
struct open_flags op;
|
||||
@ -1181,7 +1181,7 @@ struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
|
||||
int err = build_open_flags(&how, &op);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
return do_file_open_root(dentry, mnt, filename, &op);
|
||||
return do_file_open_root(root, filename, &op);
|
||||
}
|
||||
EXPORT_SYMBOL(file_open_root);
|
||||
|
||||
|
@ -1807,7 +1807,7 @@ static int process_sysctl_arg(char *param, char *val,
|
||||
panic("%s: Failed to allocate path for %s\n", __func__, param);
|
||||
strreplace(path, '.', '/');
|
||||
|
||||
file = file_open_root((*proc_mnt)->mnt_root, *proc_mnt, path, O_WRONLY, 0);
|
||||
file = file_open_root_mnt(*proc_mnt, path, O_WRONLY, 0);
|
||||
if (IS_ERR(file)) {
|
||||
err = PTR_ERR(file);
|
||||
if (err == -ENOENT)
|
||||
|
@ -2768,8 +2768,14 @@ extern long do_sys_open(int dfd, const char __user *filename, int flags,
|
||||
umode_t mode);
|
||||
extern struct file *file_open_name(struct filename *, int, umode_t);
|
||||
extern struct file *filp_open(const char *, int, umode_t);
|
||||
extern struct file *file_open_root(struct dentry *, struct vfsmount *,
|
||||
extern struct file *file_open_root(const struct path *,
|
||||
const char *, int, umode_t);
|
||||
static inline struct file *file_open_root_mnt(struct vfsmount *mnt,
|
||||
const char *name, int flags, umode_t mode)
|
||||
{
|
||||
return file_open_root(&(struct path){.mnt = mnt, .dentry = mnt->mnt_root},
|
||||
name, flags, mode);
|
||||
}
|
||||
extern struct file * dentry_open(const struct path *, int, const struct cred *);
|
||||
extern struct file * open_with_fake_path(const struct path *, int,
|
||||
struct inode*, const struct cred *);
|
||||
|
@ -36,9 +36,6 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT};
|
||||
|
||||
/* internal use only */
|
||||
#define LOOKUP_PARENT 0x0010
|
||||
#define LOOKUP_JUMPED 0x1000
|
||||
#define LOOKUP_ROOT 0x2000
|
||||
#define LOOKUP_ROOT_GRABBED 0x0008
|
||||
|
||||
/* Scoping flags for lookup. */
|
||||
#define LOOKUP_NO_SYMLINKS 0x010000 /* No symlink crossing. */
|
||||
|
@ -26,7 +26,7 @@ static struct vfsmount *blob_to_mnt(const void *data, size_t len, const char *na
|
||||
if (IS_ERR(mnt))
|
||||
return mnt;
|
||||
|
||||
file = file_open_root(mnt->mnt_root, mnt, name, O_CREAT | O_WRONLY, 0700);
|
||||
file = file_open_root_mnt(mnt, name, O_CREAT | O_WRONLY, 0700);
|
||||
if (IS_ERR(file)) {
|
||||
mntput(mnt);
|
||||
return ERR_CAST(file);
|
||||
|
Loading…
Reference in New Issue
Block a user