mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-03 17:40:04 +00:00
kernfs: add missing kernfs_active() checks in directory operations
kernfs_iop_lookup(), kernfs_dir_pos() and kernfs_dir_next_pos() were missing kernfs_active() tests before using the found kernfs_node. As deactivated state is currently visible only while a node is being removed, this doesn't pose an actual problem. e.g. lookup succeeding on a deactivated node doesn't harm anything as the eventual file operations are gonna fail and those failures are indistinguishible from the cases in which the lookups had happened before the node was deactivated. However, we're gonna allow new nodes to be created deactivated and then activated explicitly by the kernfs user when it sees fit. This is to support atomically making multiple nodes visible to userland and thus those nodes must not be visible to userland before activated. Let's plug the lookup and readdir holes so that deactivated nodes are invisible to userland. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
6a7fed4eef
commit
b9c9dad0c4
1 changed files with 6 additions and 5 deletions
|
@ -629,7 +629,7 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir,
|
||||||
kn = kernfs_find_ns(parent, dentry->d_name.name, ns);
|
kn = kernfs_find_ns(parent, dentry->d_name.name, ns);
|
||||||
|
|
||||||
/* no such entry */
|
/* no such entry */
|
||||||
if (!kn) {
|
if (!kn || !kernfs_active(kn)) {
|
||||||
ret = NULL;
|
ret = NULL;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
@ -1112,8 +1112,8 @@ static struct kernfs_node *kernfs_dir_pos(const void *ns,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Skip over entries in the wrong namespace */
|
/* Skip over entries which are dying/dead or in the wrong namespace */
|
||||||
while (pos && pos->ns != ns) {
|
while (pos && (!kernfs_active(pos) || pos->ns != ns)) {
|
||||||
struct rb_node *node = rb_next(&pos->rb);
|
struct rb_node *node = rb_next(&pos->rb);
|
||||||
if (!node)
|
if (!node)
|
||||||
pos = NULL;
|
pos = NULL;
|
||||||
|
@ -1127,14 +1127,15 @@ static struct kernfs_node *kernfs_dir_next_pos(const void *ns,
|
||||||
struct kernfs_node *parent, ino_t ino, struct kernfs_node *pos)
|
struct kernfs_node *parent, ino_t ino, struct kernfs_node *pos)
|
||||||
{
|
{
|
||||||
pos = kernfs_dir_pos(ns, parent, ino, pos);
|
pos = kernfs_dir_pos(ns, parent, ino, pos);
|
||||||
if (pos)
|
if (pos) {
|
||||||
do {
|
do {
|
||||||
struct rb_node *node = rb_next(&pos->rb);
|
struct rb_node *node = rb_next(&pos->rb);
|
||||||
if (!node)
|
if (!node)
|
||||||
pos = NULL;
|
pos = NULL;
|
||||||
else
|
else
|
||||||
pos = rb_to_kn(node);
|
pos = rb_to_kn(node);
|
||||||
} while (pos && pos->ns != ns);
|
} while (pos && (!kernfs_active(pos) || pos->ns != ns));
|
||||||
|
}
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue