提交 0a73d163 编写于 作者: A Al Viro 提交者: Joseph Qi

fs/namei.c: keep track of nd->root refcount status

to #26323588

commit 84a2bd39405ffd5fa6d6d77e408c5b9210da98de upstream.

The rules for nd->root are messy:
	* if we have LOOKUP_ROOT, it doesn't contribute to refcounts
	* if we have LOOKUP_RCU, it doesn't contribute to refcounts
	* if nd->root.mnt is NULL, it doesn't contribute to refcounts
	* otherwise it does contribute

terminate_walk() needs to drop the references if they are contributing.
So everything else should be careful not to confuse it, leading to
rather convoluted code.

It's easier to keep track of whether we'd grabbed the reference(s)
explicitly.  Use a new flag for that.  Don't bother with zeroing
nd->root.mnt on unlazy failures and in terminate_walk - it's not
needed anymore (terminate_walk() won't care and the next path_init()
will zero nd->root in !LOOKUP_ROOT case anyway).

Resulting rules for nd->root refcounts are much simpler: they are
contributing iff LOOKUP_ROOT_GRABBED is set in nd->flags.
Signed-off-by: NAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: NJoseph Qi <joseph.qi@linux.alibaba.com>
Acked-by: NXiaoguang Wang <xiaoguang.wang@linux.alibaba.com>
上级 40107f78
......@@ -598,14 +598,12 @@ 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->root.mnt && !(nd->flags & LOOKUP_ROOT)) {
if (nd->flags & LOOKUP_ROOT_GRABBED) {
path_put(&nd->root);
nd->root.mnt = NULL;
nd->flags &= ~LOOKUP_ROOT_GRABBED;
}
} else {
nd->flags &= ~LOOKUP_RCU;
if (!(nd->flags & LOOKUP_ROOT))
nd->root.mnt = NULL;
rcu_read_unlock();
}
nd->depth = 0;
......@@ -647,6 +645,7 @@ static bool legitimize_root(struct nameidata *nd)
{
if (!nd->root.mnt || (nd->flags & LOOKUP_ROOT))
return true;
nd->flags |= LOOKUP_ROOT_GRABBED;
return legitimize_path(nd, &nd->root, nd->root_seq);
}
......@@ -680,21 +679,18 @@ static int unlazy_walk(struct nameidata *nd)
nd->flags &= ~LOOKUP_RCU;
if (unlikely(!legitimize_links(nd)))
goto out2;
if (unlikely(!legitimize_path(nd, &nd->path, nd->seq)))
goto out1;
if (unlikely(!legitimize_path(nd, &nd->path, nd->seq)))
goto out;
if (unlikely(!legitimize_root(nd)))
goto out;
rcu_read_unlock();
BUG_ON(nd->inode != parent->d_inode);
return 0;
out2:
out1:
nd->path.mnt = NULL;
nd->path.dentry = NULL;
out1:
if (!(nd->flags & LOOKUP_ROOT))
nd->root.mnt = NULL;
out:
rcu_read_unlock();
return -ECHILD;
......@@ -734,21 +730,14 @@ static int unlazy_child(struct nameidata *nd, struct dentry *dentry, unsigned se
*/
if (unlikely(!lockref_get_not_dead(&dentry->d_lockref)))
goto out;
if (unlikely(read_seqcount_retry(&dentry->d_seq, seq))) {
rcu_read_unlock();
dput(dentry);
goto drop_root_mnt;
}
if (unlikely(read_seqcount_retry(&dentry->d_seq, seq)))
goto out_dput;
/*
* Sequence counts matched. Now make sure that the root is
* still valid and get it if required.
*/
if (unlikely(!legitimize_root(nd))) {
rcu_read_unlock();
dput(dentry);
return -ECHILD;
}
if (unlikely(!legitimize_root(nd)))
goto out_dput;
rcu_read_unlock();
return 0;
......@@ -758,9 +747,10 @@ static int unlazy_child(struct nameidata *nd, struct dentry *dentry, unsigned se
nd->path.dentry = NULL;
out:
rcu_read_unlock();
drop_root_mnt:
if (!(nd->flags & LOOKUP_ROOT))
nd->root.mnt = NULL;
return -ECHILD;
out_dput:
rcu_read_unlock();
dput(dentry);
return -ECHILD;
}
......@@ -824,6 +814,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;
}
return 0;
}
......@@ -1785,8 +1776,6 @@ static int pick_link(struct nameidata *nd, struct path *link,
nd->flags &= ~LOOKUP_RCU;
nd->path.mnt = NULL;
nd->path.dentry = NULL;
if (!(nd->flags & LOOKUP_ROOT))
nd->root.mnt = NULL;
rcu_read_unlock();
} else if (likely(unlazy_walk(nd)) == 0)
error = nd_alloc_stack(nd);
......
......@@ -44,6 +44,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
#define LOOKUP_JUMPED 0x1000
#define LOOKUP_ROOT 0x2000
#define LOOKUP_ROOT_GRABBED 0x0008
#define LOOKUP_EMPTY 0x4000
#define LOOKUP_DOWN 0x8000
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册