diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2021-02-10 22:13:03 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2021-03-12 22:15:20 -0500 |
commit | 3bcb39b086bf8d7c3cff013564f86162ec497d90 (patch) | |
tree | fd242a8f4b39060cb0fa7ba8ac19f2ffd94548f6 /fs/cifs | |
parent | 4ab5260dab28109979a1b47a8996c9922219927f (diff) | |
download | lwn-3bcb39b086bf8d7c3cff013564f86162ec497d90.tar.gz lwn-3bcb39b086bf8d7c3cff013564f86162ec497d90.zip |
cifs: have ->mkdir() handle race with another client sanely
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>
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/inode.c | 12 |
1 files changed, 11 insertions, 1 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index d46b36d52211..80c487fcf10e 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -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 |