cifs: have ->mkdir() handle race with another client sanely
authorAl Viro <viro@zeniv.linux.org.uk>
Thu, 11 Feb 2021 03:13:03 +0000 (22:13 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Sat, 13 Mar 2021 03:15:20 +0000 (22:15 -0500)
if we have mkdir request reported successful *and* simulating lookup
gets us a non-directory (which is possible if another client has
managed to get rmdir and create in between), the sane action is not
to mangle ->i_mode of non-directory inode to S_IFDIR | mode, it's
"report success and return with dentry negative unhashed" - that
way the next lookup will do the right thing.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/cifs/inode.c

index d46b36d52211a4ca8d99d63df496e979aa9e84c8..80c487fcf10e540cd07b1006acbf639202731d66 100644 (file)
@@ -1739,6 +1739,16 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
        if (rc)
                return rc;
 
+       if (!S_ISDIR(inode->i_mode)) {
+               /*
+                * mkdir succeeded, but another client has managed to remove the
+                * sucker and replace it with non-directory.  Return success,
+                * but don't leave the child in dcache.
+                */
+                iput(inode);
+                d_drop(dentry);
+                return 0;
+       }
        /*
         * setting nlink not necessary except in cases where we failed to get it
         * from the server or was set bogus. Also, since this is a brand new
@@ -1790,7 +1800,7 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
                }
        }
        d_instantiate(dentry, inode);
-       return rc;
+       return 0;
 }
 
 static int