Commit b9c9dad0c457d32cf8c7d2e413463c8414c7a7a7

Authored by Tejun Heo
Committed by Greg Kroah-Hartman
1 parent 6a7fed4eef

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>

Showing 1 changed file with 6 additions and 5 deletions Side-by-side Diff

... ... @@ -629,7 +629,7 @@
629 629 kn = kernfs_find_ns(parent, dentry->d_name.name, ns);
630 630  
631 631 /* no such entry */
632   - if (!kn) {
  632 + if (!kn || !kernfs_active(kn)) {
633 633 ret = NULL;
634 634 goto out_unlock;
635 635 }
... ... @@ -1112,8 +1112,8 @@
1112 1112 break;
1113 1113 }
1114 1114 }
1115   - /* Skip over entries in the wrong namespace */
1116   - while (pos && pos->ns != ns) {
  1115 + /* Skip over entries which are dying/dead or in the wrong namespace */
  1116 + while (pos && (!kernfs_active(pos) || pos->ns != ns)) {
1117 1117 struct rb_node *node = rb_next(&pos->rb);
1118 1118 if (!node)
1119 1119 pos = NULL;
1120 1120  
... ... @@ -1127,14 +1127,15 @@
1127 1127 struct kernfs_node *parent, ino_t ino, struct kernfs_node *pos)
1128 1128 {
1129 1129 pos = kernfs_dir_pos(ns, parent, ino, pos);
1130   - if (pos)
  1130 + if (pos) {
1131 1131 do {
1132 1132 struct rb_node *node = rb_next(&pos->rb);
1133 1133 if (!node)
1134 1134 pos = NULL;
1135 1135 else
1136 1136 pos = rb_to_kn(node);
1137   - } while (pos && pos->ns != ns);
  1137 + } while (pos && (!kernfs_active(pos) || pos->ns != ns));
  1138 + }
1138 1139 return pos;
1139 1140 }
1140 1141