cifs: Fix the target file was deleted when rename failed.
authorZhang Xiaoxu <zhangxiaoxu5@huawei.com>
Mon, 29 Jun 2020 01:06:38 +0000 (21:06 -0400)
committerSteve French <stfrench@microsoft.com>
Thu, 2 Jul 2020 00:41:56 +0000 (19:41 -0500)
When xfstest generic/035, we found the target file was deleted
if the rename return -EACESS.

In cifs_rename2, we unlink the positive target dentry if rename
failed with EACESS or EEXIST, even if the target dentry is positived
before rename. Then the existing file was deleted.

We should just delete the target file which created during the
rename.

Reported-by: Hulk Robot <hulkci@huawei.com>
Signed-off-by: Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
Cc: stable@vger.kernel.org
Signed-off-by: Steve French <stfrench@microsoft.com>
Reviewed-by: Aurelien Aptel <aaptel@suse.com>
fs/cifs/inode.c

index ce95801e9b6644dcd8d6e8ae79bcc3308b5a4491..49c3ea8aa84588d08c8e37671153fc0a40bc1519 100644 (file)
@@ -2044,6 +2044,7 @@ cifs_rename2(struct inode *source_dir, struct dentry *source_dentry,
        FILE_UNIX_BASIC_INFO *info_buf_target;
        unsigned int xid;
        int rc, tmprc;
+       bool new_target = d_really_is_negative(target_dentry);
 
        if (flags & ~RENAME_NOREPLACE)
                return -EINVAL;
@@ -2120,8 +2121,13 @@ cifs_rename2(struct inode *source_dir, struct dentry *source_dentry,
         */
 
 unlink_target:
-       /* Try unlinking the target dentry if it's not negative */
-       if (d_really_is_positive(target_dentry) && (rc == -EACCES || rc == -EEXIST)) {
+       /*
+        * If the target dentry was created during the rename, try
+        * unlinking it if it's not negative
+        */
+       if (new_target &&
+           d_really_is_positive(target_dentry) &&
+           (rc == -EACCES || rc == -EEXIST)) {
                if (d_is_dir(target_dentry))
                        tmprc = cifs_rmdir(target_dir, target_dentry);
                else