9ns: Fix issues with can_have_children
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 26 Jul 2018 20:24:13 +0000 (16:24 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 30 Jul 2018 20:05:46 +0000 (16:05 -0400)
Two things:
1) We cleared can_have_children even when an rmdir failed.  Then subsequent
renames would fail, since it thought the directory was being removed.
2) We never checked can_have_children when creating files.  Maybe I had a
good reason for this, but it's not apparent.  In this case, you might be
able to add a file (or a negative dentry) to a directory while it is being
removed.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/src/ns/tree_file.c

index 14e5f8d..02b4293 100644 (file)
@@ -343,15 +343,13 @@ static void __link_child(struct tree_file *parent, struct tree_file *child)
 
 static void neuter_directory(struct tree_file *dir)
 {
-       bool throw = false;
-
        qlock(&dir->file.qlock);
-       if (dir->tfs->tf_ops.has_children(dir))
-               throw = true;
+       if (dir->tfs->tf_ops.has_children(dir)) {
+               qunlock(&dir->file.qlock);
+               error(ENOTEMPTY, "can't remove dir with children");
+       }
        dir->can_have_children = false;
        qunlock(&dir->file.qlock);
-       if (throw)
-               error(ENOTEMPTY, "can't remove dir with children");
 }
 
 /* Unlink a child from the tree.  Last ref will clean it up, which will not be
@@ -399,6 +397,10 @@ static struct tree_file *lookup_child_entry(struct tree_file *parent,
                qunlock(&parent->file.qlock);
                return child;
        }
+       if (!parent->can_have_children) {
+               qunlock(&parent->file.qlock);
+               error(ENOENT, "lookup failed, parent dir being removed");
+       }
        child = tree_file_alloc(parent->tfs, parent, name);
        if (waserror()) {
                /* child wasn't fully created, so freeing it may be tricky, esp on the
@@ -635,6 +637,8 @@ struct tree_file *tree_file_create(struct tree_file *parent, const char *name,
        }
        if (!caller_has_tf_perms(parent, O_WRITE))
                error(EACCES, "missing create permission on dir");
+       if (!parent->can_have_children)
+               error(ENOENT, "create failed, parent dir being removed");
        child = wc_lookup_child(parent, name);
        if (child) {
                /* The create(5) message fails if the file exists, which differs from