Fix do_mkdir on root directories
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 27 Aug 2015 02:58:15 +0000 (22:58 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 27 Aug 2015 03:01:42 +0000 (23:01 -0400)
mkdir / should fail with EEXIST, not ENOENT.  The problem, pointed out
by Kevin, was that the parent check happened before the existence check,
and root directories (also for chroots) do not have parents.

This failure caused things like mkdir -p /foo/bar to fail.

Note that the VFS stack is racy, and concurrent mkdirs will probably
cause a lot of trouble.

kern/src/vfs.c

index 18c47b2..8be496c 100644 (file)
@@ -1648,6 +1648,14 @@ int do_mkdir(char *path, int mode)
        int error;
        int retval = -1;
 
+       /* The dir might exist and might be /, so we can't look for the parent */
+       nd->intent = LOOKUP_OPEN;
+       error = path_lookup(path, LOOKUP_FOLLOW, nd);
+       path_release(nd);
+       if (!error) {
+               set_errno(EEXIST);
+               return -1;
+       }
        nd->intent = LOOKUP_CREATE;
        /* get the parent, but don't follow links */
        error = path_lookup(path, LOOKUP_PARENT, nd);
@@ -1655,12 +1663,6 @@ int do_mkdir(char *path, int mode)
                set_errno(-error);
                goto out_path_only;
        }
-       /* see if the target is already there, handle accordingly */
-       dentry = do_lookup(nd->dentry, nd->last.name); 
-       if (dentry) {
-               set_errno(EEXIST);
-               goto out_dentry;
-       }
        /* Doesn't already exist, let's try to make it: */
        dentry = get_dentry(nd->dentry->d_sb, nd->dentry, nd->last.name);
        if (!dentry)