aboutsummaryrefslogtreecommitdiffstats
path: root/fs/kernfs
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2014-02-03 14:09:11 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-02-07 18:52:48 -0500
commitb9c9dad0c457d32cf8c7d2e413463c8414c7a7a7 (patch)
treec20eaec5b60bb56f4b4873c2e06cde65edb59d7e /fs/kernfs
parent6a7fed4eefddad48224f1c9d534b4e262f0897f6 (diff)
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>
Diffstat (limited to 'fs/kernfs')
-rw-r--r--fs/kernfs/dir.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index f58d2f16eaf7..89f8462f337e 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -629,7 +629,7 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir,
629 kn = kernfs_find_ns(parent, dentry->d_name.name, ns); 629 kn = kernfs_find_ns(parent, dentry->d_name.name, ns);
630 630
631 /* no such entry */ 631 /* no such entry */
632 if (!kn) { 632 if (!kn || !kernfs_active(kn)) {
633 ret = NULL; 633 ret = NULL;
634 goto out_unlock; 634 goto out_unlock;
635 } 635 }
@@ -1112,8 +1112,8 @@ static struct kernfs_node *kernfs_dir_pos(const void *ns,
1112 break; 1112 break;
1113 } 1113 }
1114 } 1114 }
1115 /* Skip over entries in the wrong namespace */ 1115 /* Skip over entries which are dying/dead or in the wrong namespace */
1116 while (pos && pos->ns != ns) { 1116 while (pos && (!kernfs_active(pos) || pos->ns != ns)) {
1117 struct rb_node *node = rb_next(&pos->rb); 1117 struct rb_node *node = rb_next(&pos->rb);
1118 if (!node) 1118 if (!node)
1119 pos = NULL; 1119 pos = NULL;
@@ -1127,14 +1127,15 @@ static struct kernfs_node *kernfs_dir_next_pos(const void *ns,
1127 struct kernfs_node *parent, ino_t ino, struct kernfs_node *pos) 1127 struct kernfs_node *parent, ino_t ino, struct kernfs_node *pos)
1128{ 1128{
1129 pos = kernfs_dir_pos(ns, parent, ino, pos); 1129 pos = kernfs_dir_pos(ns, parent, ino, pos);
1130 if (pos) 1130 if (pos) {
1131 do { 1131 do {
1132 struct rb_node *node = rb_next(&pos->rb); 1132 struct rb_node *node = rb_next(&pos->rb);
1133 if (!node) 1133 if (!node)
1134 pos = NULL; 1134 pos = NULL;
1135 else 1135 else
1136 pos = rb_to_kn(node); 1136 pos = rb_to_kn(node);
1137 } while (pos && pos->ns != ns); 1137 } while (pos && (!kernfs_active(pos) || pos->ns != ns));
1138 }
1138 return pos; 1139 return pos;
1139} 1140}
1140 1141