]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
smb: client: fix file open check in __cifs_unlink()
authorPaulo Alcantara <pc@manguebit.org>
Thu, 18 Sep 2025 15:30:32 +0000 (12:30 -0300)
committerSteve French <stfrench@microsoft.com>
Thu, 18 Sep 2025 21:37:59 +0000 (16:37 -0500)
Fix the file open check to decide whether or not silly-rename the file
in SMB2+.

Fixes: c5ea3065586d ("smb: client: fix data loss due to broken rename(2)")
Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
Cc: Frank Sorenson <sorenson@redhat.com>
Reviewed-by: David Howells <dhowells@redhat.com>
Cc: linux-cifs@vger.kernel.org
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/inode.c

index 1703f1285d36d27f8ce49763a78a1f28d05a998a..0f0d2dae6283adb26b27558efe05209f545aba88 100644 (file)
@@ -2003,8 +2003,21 @@ retry_std_delete:
                goto psx_del_no_retry;
        }
 
-       if (sillyrename || (server->vals->protocol_id > SMB10_PROT_ID &&
-                           d_is_positive(dentry) && d_count(dentry) > 2))
+       /* For SMB2+, if the file is open, we always perform a silly rename.
+        *
+        * We check for d_count() right after calling
+        * cifs_close_deferred_file_under_dentry() to make sure that the
+        * dentry's refcount gets dropped in case the file had any deferred
+        * close.
+        */
+       if (!sillyrename && server->vals->protocol_id > SMB10_PROT_ID) {
+               spin_lock(&dentry->d_lock);
+               if (d_count(dentry) > 1)
+                       sillyrename = true;
+               spin_unlock(&dentry->d_lock);
+       }
+
+       if (sillyrename)
                rc = -EBUSY;
        else
                rc = server->ops->unlink(xid, tcon, full_path, cifs_sb, dentry);