move handle_dots(), follow_dotdot() and follow_dotdot_rcu() past step_into()
pure move; we are going to have step_into() called by that bunch. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Родитель
c9a0f75d81
Коммит
957dd41d88
260
fs/namei.c
260
fs/namei.c
|
@ -1363,70 +1363,6 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int follow_dotdot_rcu(struct nameidata *nd)
|
||||
{
|
||||
struct dentry *parent = NULL;
|
||||
struct inode *inode = nd->inode;
|
||||
unsigned seq;
|
||||
|
||||
while (1) {
|
||||
if (path_equal(&nd->path, &nd->root))
|
||||
break;
|
||||
if (nd->path.dentry != nd->path.mnt->mnt_root) {
|
||||
struct dentry *old = nd->path.dentry;
|
||||
|
||||
parent = old->d_parent;
|
||||
inode = parent->d_inode;
|
||||
seq = read_seqcount_begin(&parent->d_seq);
|
||||
if (unlikely(read_seqcount_retry(&old->d_seq, nd->seq)))
|
||||
return -ECHILD;
|
||||
if (unlikely(!path_connected(nd->path.mnt, parent)))
|
||||
return -ECHILD;
|
||||
break;
|
||||
} else {
|
||||
struct mount *mnt = real_mount(nd->path.mnt);
|
||||
struct mount *mparent = mnt->mnt_parent;
|
||||
struct dentry *mountpoint = mnt->mnt_mountpoint;
|
||||
struct inode *inode2 = mountpoint->d_inode;
|
||||
unsigned seq = read_seqcount_begin(&mountpoint->d_seq);
|
||||
if (unlikely(read_seqretry(&mount_lock, nd->m_seq)))
|
||||
return -ECHILD;
|
||||
if (&mparent->mnt == nd->path.mnt)
|
||||
break;
|
||||
if (unlikely(nd->flags & LOOKUP_NO_XDEV))
|
||||
return -ECHILD;
|
||||
/* we know that mountpoint was pinned */
|
||||
nd->path.dentry = mountpoint;
|
||||
nd->path.mnt = &mparent->mnt;
|
||||
inode = inode2;
|
||||
nd->seq = seq;
|
||||
}
|
||||
}
|
||||
if (unlikely(!parent)) {
|
||||
if (unlikely(nd->flags & LOOKUP_BENEATH))
|
||||
return -ECHILD;
|
||||
} else {
|
||||
nd->path.dentry = parent;
|
||||
nd->seq = seq;
|
||||
}
|
||||
while (unlikely(d_mountpoint(nd->path.dentry))) {
|
||||
struct mount *mounted;
|
||||
mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
|
||||
if (unlikely(read_seqretry(&mount_lock, nd->m_seq)))
|
||||
return -ECHILD;
|
||||
if (!mounted)
|
||||
break;
|
||||
if (unlikely(nd->flags & LOOKUP_NO_XDEV))
|
||||
return -ECHILD;
|
||||
nd->path.mnt = &mounted->mnt;
|
||||
nd->path.dentry = mounted->mnt.mnt_root;
|
||||
inode = nd->path.dentry->d_inode;
|
||||
nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
|
||||
}
|
||||
nd->inode = inode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip to top of mountpoint pile in refwalk mode for follow_dotdot()
|
||||
*/
|
||||
|
@ -1443,38 +1379,6 @@ static void follow_mount(struct path *path)
|
|||
}
|
||||
}
|
||||
|
||||
static int follow_dotdot(struct nameidata *nd)
|
||||
{
|
||||
struct dentry *parent = NULL;
|
||||
while (1) {
|
||||
if (path_equal(&nd->path, &nd->root))
|
||||
break;
|
||||
if (nd->path.dentry != nd->path.mnt->mnt_root) {
|
||||
/* rare case of legitimate dget_parent()... */
|
||||
parent = dget_parent(nd->path.dentry);
|
||||
if (unlikely(!path_connected(nd->path.mnt, parent))) {
|
||||
dput(parent);
|
||||
return -ENOENT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!follow_up(&nd->path))
|
||||
break;
|
||||
if (unlikely(nd->flags & LOOKUP_NO_XDEV))
|
||||
return -EXDEV;
|
||||
}
|
||||
if (unlikely(!parent)) {
|
||||
if (unlikely(nd->flags & LOOKUP_BENEATH))
|
||||
return -EXDEV;
|
||||
} else {
|
||||
dput(nd->path.dentry);
|
||||
nd->path.dentry = parent;
|
||||
}
|
||||
follow_mount(&nd->path);
|
||||
nd->inode = nd->path.dentry->d_inode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This looks up the name in dcache and possibly revalidates the found dentry.
|
||||
* NULL is returned if the dentry does not exist in the cache.
|
||||
|
@ -1654,40 +1558,6 @@ static inline int may_lookup(struct nameidata *nd)
|
|||
return inode_permission(nd->inode, MAY_EXEC);
|
||||
}
|
||||
|
||||
static inline int handle_dots(struct nameidata *nd, int type)
|
||||
{
|
||||
if (type == LAST_DOTDOT) {
|
||||
int error = 0;
|
||||
|
||||
if (!nd->root.mnt) {
|
||||
error = set_root(nd);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
if (nd->flags & LOOKUP_RCU)
|
||||
error = follow_dotdot_rcu(nd);
|
||||
else
|
||||
error = follow_dotdot(nd);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (unlikely(nd->flags & LOOKUP_IS_SCOPED)) {
|
||||
/*
|
||||
* If there was a racing rename or mount along our
|
||||
* path, then we can't be sure that ".." hasn't jumped
|
||||
* above nd->root (and so userspace should retry or use
|
||||
* some fallback).
|
||||
*/
|
||||
smp_rmb();
|
||||
if (unlikely(__read_seqcount_retry(&mount_lock.seqcount, nd->m_seq)))
|
||||
return -EAGAIN;
|
||||
if (unlikely(__read_seqcount_retry(&rename_lock.seqcount, nd->r_seq)))
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum {WALK_TRAILING = 1, WALK_MORE = 2, WALK_NOFOLLOW = 4};
|
||||
|
||||
static const char *pick_link(struct nameidata *nd, struct path *link,
|
||||
|
@ -1817,6 +1687,136 @@ static const char *step_into(struct nameidata *nd, int flags,
|
|||
return pick_link(nd, &path, inode, seq, flags);
|
||||
}
|
||||
|
||||
static int follow_dotdot_rcu(struct nameidata *nd)
|
||||
{
|
||||
struct dentry *parent = NULL;
|
||||
struct inode *inode = nd->inode;
|
||||
unsigned seq;
|
||||
|
||||
while (1) {
|
||||
if (path_equal(&nd->path, &nd->root))
|
||||
break;
|
||||
if (nd->path.dentry != nd->path.mnt->mnt_root) {
|
||||
struct dentry *old = nd->path.dentry;
|
||||
|
||||
parent = old->d_parent;
|
||||
inode = parent->d_inode;
|
||||
seq = read_seqcount_begin(&parent->d_seq);
|
||||
if (unlikely(read_seqcount_retry(&old->d_seq, nd->seq)))
|
||||
return -ECHILD;
|
||||
if (unlikely(!path_connected(nd->path.mnt, parent)))
|
||||
return -ECHILD;
|
||||
break;
|
||||
} else {
|
||||
struct mount *mnt = real_mount(nd->path.mnt);
|
||||
struct mount *mparent = mnt->mnt_parent;
|
||||
struct dentry *mountpoint = mnt->mnt_mountpoint;
|
||||
struct inode *inode2 = mountpoint->d_inode;
|
||||
unsigned seq = read_seqcount_begin(&mountpoint->d_seq);
|
||||
if (unlikely(read_seqretry(&mount_lock, nd->m_seq)))
|
||||
return -ECHILD;
|
||||
if (&mparent->mnt == nd->path.mnt)
|
||||
break;
|
||||
if (unlikely(nd->flags & LOOKUP_NO_XDEV))
|
||||
return -ECHILD;
|
||||
/* we know that mountpoint was pinned */
|
||||
nd->path.dentry = mountpoint;
|
||||
nd->path.mnt = &mparent->mnt;
|
||||
inode = inode2;
|
||||
nd->seq = seq;
|
||||
}
|
||||
}
|
||||
if (unlikely(!parent)) {
|
||||
if (unlikely(nd->flags & LOOKUP_BENEATH))
|
||||
return -ECHILD;
|
||||
} else {
|
||||
nd->path.dentry = parent;
|
||||
nd->seq = seq;
|
||||
}
|
||||
while (unlikely(d_mountpoint(nd->path.dentry))) {
|
||||
struct mount *mounted;
|
||||
mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
|
||||
if (unlikely(read_seqretry(&mount_lock, nd->m_seq)))
|
||||
return -ECHILD;
|
||||
if (!mounted)
|
||||
break;
|
||||
if (unlikely(nd->flags & LOOKUP_NO_XDEV))
|
||||
return -ECHILD;
|
||||
nd->path.mnt = &mounted->mnt;
|
||||
nd->path.dentry = mounted->mnt.mnt_root;
|
||||
inode = nd->path.dentry->d_inode;
|
||||
nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
|
||||
}
|
||||
nd->inode = inode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int follow_dotdot(struct nameidata *nd)
|
||||
{
|
||||
struct dentry *parent = NULL;
|
||||
while (1) {
|
||||
if (path_equal(&nd->path, &nd->root))
|
||||
break;
|
||||
if (nd->path.dentry != nd->path.mnt->mnt_root) {
|
||||
/* rare case of legitimate dget_parent()... */
|
||||
parent = dget_parent(nd->path.dentry);
|
||||
if (unlikely(!path_connected(nd->path.mnt, parent))) {
|
||||
dput(parent);
|
||||
return -ENOENT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!follow_up(&nd->path))
|
||||
break;
|
||||
if (unlikely(nd->flags & LOOKUP_NO_XDEV))
|
||||
return -EXDEV;
|
||||
}
|
||||
if (unlikely(!parent)) {
|
||||
if (unlikely(nd->flags & LOOKUP_BENEATH))
|
||||
return -EXDEV;
|
||||
} else {
|
||||
dput(nd->path.dentry);
|
||||
nd->path.dentry = parent;
|
||||
}
|
||||
follow_mount(&nd->path);
|
||||
nd->inode = nd->path.dentry->d_inode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int handle_dots(struct nameidata *nd, int type)
|
||||
{
|
||||
if (type == LAST_DOTDOT) {
|
||||
int error = 0;
|
||||
|
||||
if (!nd->root.mnt) {
|
||||
error = set_root(nd);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
if (nd->flags & LOOKUP_RCU)
|
||||
error = follow_dotdot_rcu(nd);
|
||||
else
|
||||
error = follow_dotdot(nd);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (unlikely(nd->flags & LOOKUP_IS_SCOPED)) {
|
||||
/*
|
||||
* If there was a racing rename or mount along our
|
||||
* path, then we can't be sure that ".." hasn't jumped
|
||||
* above nd->root (and so userspace should retry or use
|
||||
* some fallback).
|
||||
*/
|
||||
smp_rmb();
|
||||
if (unlikely(__read_seqcount_retry(&mount_lock.seqcount, nd->m_seq)))
|
||||
return -EAGAIN;
|
||||
if (unlikely(__read_seqcount_retry(&rename_lock.seqcount, nd->r_seq)))
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *walk_component(struct nameidata *nd, int flags)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
|
|
Загрузка…
Ссылка в новой задаче