提交 42d3b3b2 编写于 作者: A Al Viro 提交者: Zheng Zengkai

take LOOKUP_{ROOT,ROOT_GRABBED,JUMPED} out of LOOKUP_... space

mainline inclusion
from mainline-5.14-rc1
commit bcba1e7d
category: bugfix
bugzilla: 181657 https://gitee.com/openeuler/kernel/issues/I4DDEL
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=bcba1e7d0d520adba895d9e0800a056f734b0a6a

---------------------------

Separate field in nameidata (nd->state) holding the flags that
should be internal-only - that way we both get some spare bits
in LOOKUP_... and get simpler rules for nd->root lifetime rules,
since we can set the replacement of LOOKUP_ROOT (ND_ROOT_PRESET)
at the same time we set nd->root.
Signed-off-by: NAl Viro <viro@zeniv.linux.org.uk>

Conflicts:
	fs/namei.c
	[ Bugfix 7d01ef75("Make sure nd->path.mnt and nd->path.dentry
	  are always valid pointers") is not applid, the problem to be
	  fixed not exists.
	  Feature 6c6ec2b0("fs: add support for LOOKUP_CACHED") is
	  not applied. ]
Signed-off-by: NZhihao Cheng <chengzhihao1@huawei.com>
Reviewed-by: NZhang Yi <yi.zhang@huawei.com>
Signed-off-by: NChen Jun <chenjun102@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 d16f801d
...@@ -1321,18 +1321,18 @@ to lookup: RCU-walk, REF-walk, and REF-walk with forced revalidation. ...@@ -1321,18 +1321,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 yet. This is primarily used to tell the audit subsystem the full
context of a particular access being audited. 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 provided by the caller, so it shouldn't be released when it is no
longer needed. 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 it had the right name but for some other reason. This happens when
following "``..``", following a symlink to ``/``, crossing a mount point following "``..``", following a symlink to ``/``, crossing a mount point
or accessing a "``/proc/$PID/fd/$FD``" symlink (also known as a "magic 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 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 name (with ``d_revalidate()``). In such cases the inode may still need
to be revalidated, so ``d_op->d_weak_revalidate()`` is called if 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. final component or, when creating, unlinking, or renaming, at the penultimate component.
Resolution-restriction flags Resolution-restriction flags
......
...@@ -504,7 +504,7 @@ struct nameidata { ...@@ -504,7 +504,7 @@ struct nameidata {
struct qstr last; struct qstr last;
struct path root; struct path root;
struct inode *inode; /* path.dentry.d_inode */ struct inode *inode; /* path.dentry.d_inode */
unsigned int flags; unsigned int flags, state;
unsigned seq, m_seq, r_seq; unsigned seq, m_seq, r_seq;
int last_type; int last_type;
unsigned depth; unsigned depth;
...@@ -523,6 +523,10 @@ struct nameidata { ...@@ -523,6 +523,10 @@ struct nameidata {
umode_t dir_mode; umode_t dir_mode;
} __randomize_layout; } __randomize_layout;
#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) static void set_nameidata(struct nameidata *p, int dfd, struct filename *name)
{ {
struct nameidata *old = current->nameidata; struct nameidata *old = current->nameidata;
...@@ -531,6 +535,7 @@ static void set_nameidata(struct nameidata *p, int dfd, struct filename *name) ...@@ -531,6 +535,7 @@ static void set_nameidata(struct nameidata *p, int dfd, struct filename *name)
p->name = name; p->name = name;
p->total_link_count = old ? old->total_link_count : 0; p->total_link_count = old ? old->total_link_count : 0;
p->saved = old; p->saved = old;
p->state = 0;
current->nameidata = p; current->nameidata = p;
} }
...@@ -593,9 +598,9 @@ static void terminate_walk(struct nameidata *nd) ...@@ -593,9 +598,9 @@ static void terminate_walk(struct nameidata *nd)
path_put(&nd->path); path_put(&nd->path);
for (i = 0; i < nd->depth; i++) for (i = 0; i < nd->depth; i++)
path_put(&nd->stack[i].link); path_put(&nd->stack[i].link);
if (nd->flags & LOOKUP_ROOT_GRABBED) { if (nd->state & ND_ROOT_GRABBED) {
path_put(&nd->root); path_put(&nd->root);
nd->flags &= ~LOOKUP_ROOT_GRABBED; nd->state &= ~ND_ROOT_GRABBED;
} }
} else { } else {
nd->flags &= ~LOOKUP_RCU; nd->flags &= ~LOOKUP_RCU;
...@@ -651,9 +656,9 @@ static bool legitimize_root(struct nameidata *nd) ...@@ -651,9 +656,9 @@ static bool legitimize_root(struct nameidata *nd)
if (!nd->root.mnt && (nd->flags & LOOKUP_IS_SCOPED)) if (!nd->root.mnt && (nd->flags & LOOKUP_IS_SCOPED))
return false; return false;
/* Nothing to do if nd->root is zero or is managed by the VFS user. */ /* 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; return true;
nd->flags |= LOOKUP_ROOT_GRABBED; nd->state |= ND_ROOT_GRABBED;
return legitimize_path(nd, &nd->root, nd->root_seq); return legitimize_path(nd, &nd->root, nd->root_seq);
} }
...@@ -790,8 +795,9 @@ static int complete_walk(struct nameidata *nd) ...@@ -790,8 +795,9 @@ static int complete_walk(struct nameidata *nd)
* We don't want to zero nd->root for scoped-lookups or * We don't want to zero nd->root for scoped-lookups or
* externally-managed nd->root. * externally-managed nd->root.
*/ */
if (!(nd->flags & (LOOKUP_ROOT | LOOKUP_IS_SCOPED))) if (!(nd->state & ND_ROOT_PRESET))
nd->root.mnt = NULL; if (!(nd->flags & LOOKUP_IS_SCOPED))
nd->root.mnt = NULL;
if (!try_to_unlazy(nd)) if (!try_to_unlazy(nd))
return -ECHILD; return -ECHILD;
} }
...@@ -817,7 +823,7 @@ static int complete_walk(struct nameidata *nd) ...@@ -817,7 +823,7 @@ static int complete_walk(struct nameidata *nd)
return -EXDEV; return -EXDEV;
} }
if (likely(!(nd->flags & LOOKUP_JUMPED))) if (likely(!(nd->state & ND_JUMPED)))
return 0; return 0;
if (likely(!(dentry->d_flags & DCACHE_OP_WEAK_REVALIDATE))) if (likely(!(dentry->d_flags & DCACHE_OP_WEAK_REVALIDATE)))
...@@ -855,7 +861,7 @@ static int set_root(struct nameidata *nd) ...@@ -855,7 +861,7 @@ static int set_root(struct nameidata *nd)
} while (read_seqcount_retry(&fs->seq, seq)); } while (read_seqcount_retry(&fs->seq, seq));
} else { } else {
get_fs_root(fs, &nd->root); get_fs_root(fs, &nd->root);
nd->flags |= LOOKUP_ROOT_GRABBED; nd->state |= ND_ROOT_GRABBED;
} }
return 0; return 0;
} }
...@@ -888,7 +894,7 @@ static int nd_jump_root(struct nameidata *nd) ...@@ -888,7 +894,7 @@ static int nd_jump_root(struct nameidata *nd)
path_get(&nd->path); path_get(&nd->path);
nd->inode = nd->path.dentry->d_inode; nd->inode = nd->path.dentry->d_inode;
} }
nd->flags |= LOOKUP_JUMPED; nd->state |= ND_JUMPED;
return 0; return 0;
} }
...@@ -916,7 +922,7 @@ int nd_jump_link(struct path *path) ...@@ -916,7 +922,7 @@ int nd_jump_link(struct path *path)
path_put(&nd->path); path_put(&nd->path);
nd->path = *path; nd->path = *path;
nd->inode = nd->path.dentry->d_inode; nd->inode = nd->path.dentry->d_inode;
nd->flags |= LOOKUP_JUMPED; nd->state |= ND_JUMPED;
return 0; return 0;
err: err:
...@@ -1338,7 +1344,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, ...@@ -1338,7 +1344,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
if (mounted) { if (mounted) {
path->mnt = &mounted->mnt; path->mnt = &mounted->mnt;
dentry = path->dentry = mounted->mnt.mnt_root; dentry = path->dentry = mounted->mnt.mnt_root;
nd->flags |= LOOKUP_JUMPED; nd->state |= ND_JUMPED;
*seqp = read_seqcount_begin(&dentry->d_seq); *seqp = read_seqcount_begin(&dentry->d_seq);
*inode = dentry->d_inode; *inode = dentry->d_inode;
/* /*
...@@ -1383,7 +1389,7 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry, ...@@ -1383,7 +1389,7 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry,
if (unlikely(nd->flags & LOOKUP_NO_XDEV)) if (unlikely(nd->flags & LOOKUP_NO_XDEV))
ret = -EXDEV; ret = -EXDEV;
else else
nd->flags |= LOOKUP_JUMPED; nd->state |= ND_JUMPED;
} }
if (unlikely(ret)) { if (unlikely(ret)) {
dput(path->dentry); dput(path->dentry);
...@@ -2129,7 +2135,7 @@ static int link_path_walk(const char *name, struct nameidata *nd) ...@@ -2129,7 +2135,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
case 2: case 2:
if (name[1] == '.') { if (name[1] == '.') {
type = LAST_DOTDOT; type = LAST_DOTDOT;
nd->flags |= LOOKUP_JUMPED; nd->state |= ND_JUMPED;
} }
break; break;
case 1: case 1:
...@@ -2137,7 +2143,7 @@ static int link_path_walk(const char *name, struct nameidata *nd) ...@@ -2137,7 +2143,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
} }
if (likely(type == LAST_NORM)) { if (likely(type == LAST_NORM)) {
struct dentry *parent = nd->path.dentry; struct dentry *parent = nd->path.dentry;
nd->flags &= ~LOOKUP_JUMPED; nd->state &= ~ND_JUMPED;
if (unlikely(parent->d_flags & DCACHE_OP_HASH)) { if (unlikely(parent->d_flags & DCACHE_OP_HASH)) {
struct qstr this = { { .hash_len = hash_len }, .name = name }; struct qstr this = { { .hash_len = hash_len }, .name = name };
err = parent->d_op->d_hash(parent, &this); err = parent->d_op->d_hash(parent, &this);
...@@ -2207,14 +2213,15 @@ static const char *path_init(struct nameidata *nd, unsigned flags) ...@@ -2207,14 +2213,15 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
if (flags & LOOKUP_RCU) if (flags & LOOKUP_RCU)
rcu_read_lock(); rcu_read_lock();
nd->flags = flags | LOOKUP_JUMPED; nd->flags = flags;
nd->state |= ND_JUMPED;
nd->depth = 0; nd->depth = 0;
nd->m_seq = __read_seqcount_begin(&mount_lock.seqcount); nd->m_seq = __read_seqcount_begin(&mount_lock.seqcount);
nd->r_seq = __read_seqcount_begin(&rename_lock.seqcount); nd->r_seq = __read_seqcount_begin(&rename_lock.seqcount);
smp_rmb(); smp_rmb();
if (flags & LOOKUP_ROOT) { if (nd->state & ND_ROOT_PRESET) {
struct dentry *root = nd->root.dentry; struct dentry *root = nd->root.dentry;
struct inode *inode = root->d_inode; struct inode *inode = root->d_inode;
if (*s && unlikely(!d_can_lookup(root))) if (*s && unlikely(!d_can_lookup(root)))
...@@ -2291,7 +2298,7 @@ static const char *path_init(struct nameidata *nd, unsigned flags) ...@@ -2291,7 +2298,7 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
nd->root_seq = nd->seq; nd->root_seq = nd->seq;
} else { } else {
path_get(&nd->root); path_get(&nd->root);
nd->flags |= LOOKUP_ROOT_GRABBED; nd->state |= ND_ROOT_GRABBED;
} }
} }
return s; return s;
...@@ -2330,7 +2337,7 @@ static int path_lookupat(struct nameidata *nd, unsigned flags, struct path *path ...@@ -2330,7 +2337,7 @@ static int path_lookupat(struct nameidata *nd, unsigned flags, struct path *path
; ;
if (!err && unlikely(nd->flags & LOOKUP_MOUNTPOINT)) { if (!err && unlikely(nd->flags & LOOKUP_MOUNTPOINT)) {
err = handle_lookup_down(nd); 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) if (!err)
err = complete_walk(nd); err = complete_walk(nd);
...@@ -2354,11 +2361,11 @@ int filename_lookup(int dfd, struct filename *name, unsigned flags, ...@@ -2354,11 +2361,11 @@ int filename_lookup(int dfd, struct filename *name, unsigned flags,
struct nameidata nd; struct nameidata nd;
if (IS_ERR(name)) if (IS_ERR(name))
return PTR_ERR(name); return PTR_ERR(name);
set_nameidata(&nd, dfd, name);
if (unlikely(root)) { if (unlikely(root)) {
nd.root = *root; nd.root = *root;
flags |= LOOKUP_ROOT; nd.state = ND_ROOT_PRESET;
} }
set_nameidata(&nd, dfd, name);
retval = path_lookupat(&nd, flags | LOOKUP_RCU, path); retval = path_lookupat(&nd, flags | LOOKUP_RCU, path);
if (unlikely(retval == -ECHILD)) if (unlikely(retval == -ECHILD))
retval = path_lookupat(&nd, flags, path); retval = path_lookupat(&nd, flags, path);
...@@ -3399,7 +3406,7 @@ struct file *do_file_open_root(const struct path *root, ...@@ -3399,7 +3406,7 @@ struct file *do_file_open_root(const struct path *root,
struct nameidata nd; struct nameidata nd;
struct file *file; struct file *file;
struct filename *filename; struct filename *filename;
int flags = op->lookup_flags | LOOKUP_ROOT; int flags = op->lookup_flags;
if (d_is_symlink(root->dentry) && op->intent & LOOKUP_OPEN) if (d_is_symlink(root->dentry) && op->intent & LOOKUP_OPEN)
return ERR_PTR(-ELOOP); return ERR_PTR(-ELOOP);
...@@ -3408,8 +3415,9 @@ struct file *do_file_open_root(const struct path *root, ...@@ -3408,8 +3415,9 @@ struct file *do_file_open_root(const struct path *root,
if (IS_ERR(filename)) if (IS_ERR(filename))
return ERR_CAST(filename); return ERR_CAST(filename);
nd.root = *root;
set_nameidata(&nd, -1, filename); set_nameidata(&nd, -1, filename);
nd.root = *root;
nd.state = ND_ROOT_PRESET;
file = path_openat(&nd, op, flags | LOOKUP_RCU); file = path_openat(&nd, op, flags | LOOKUP_RCU);
if (unlikely(file == ERR_PTR(-ECHILD))) if (unlikely(file == ERR_PTR(-ECHILD)))
file = path_openat(&nd, op, flags); file = path_openat(&nd, op, flags);
......
...@@ -271,8 +271,6 @@ TRACE_DEFINE_ENUM(LOOKUP_OPEN); ...@@ -271,8 +271,6 @@ TRACE_DEFINE_ENUM(LOOKUP_OPEN);
TRACE_DEFINE_ENUM(LOOKUP_CREATE); TRACE_DEFINE_ENUM(LOOKUP_CREATE);
TRACE_DEFINE_ENUM(LOOKUP_EXCL); TRACE_DEFINE_ENUM(LOOKUP_EXCL);
TRACE_DEFINE_ENUM(LOOKUP_RENAME_TARGET); 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_EMPTY);
TRACE_DEFINE_ENUM(LOOKUP_DOWN); TRACE_DEFINE_ENUM(LOOKUP_DOWN);
...@@ -288,8 +286,6 @@ TRACE_DEFINE_ENUM(LOOKUP_DOWN); ...@@ -288,8 +286,6 @@ TRACE_DEFINE_ENUM(LOOKUP_DOWN);
{ LOOKUP_CREATE, "CREATE" }, \ { LOOKUP_CREATE, "CREATE" }, \
{ LOOKUP_EXCL, "EXCL" }, \ { LOOKUP_EXCL, "EXCL" }, \
{ LOOKUP_RENAME_TARGET, "RENAME_TARGET" }, \ { LOOKUP_RENAME_TARGET, "RENAME_TARGET" }, \
{ LOOKUP_JUMPED, "JUMPED" }, \
{ LOOKUP_ROOT, "ROOT" }, \
{ LOOKUP_EMPTY, "EMPTY" }, \ { LOOKUP_EMPTY, "EMPTY" }, \
{ LOOKUP_DOWN, "DOWN" }) { LOOKUP_DOWN, "DOWN" })
......
...@@ -36,9 +36,6 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT}; ...@@ -36,9 +36,6 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT};
/* internal use only */ /* internal use only */
#define LOOKUP_PARENT 0x0010 #define LOOKUP_PARENT 0x0010
#define LOOKUP_JUMPED 0x1000
#define LOOKUP_ROOT 0x2000
#define LOOKUP_ROOT_GRABBED 0x0008
/* Scoping flags for lookup. */ /* Scoping flags for lookup. */
#define LOOKUP_NO_SYMLINKS 0x010000 /* No symlink crossing. */ #define LOOKUP_NO_SYMLINKS 0x010000 /* No symlink crossing. */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册