From: Sasha Levin <sashal@kernel.org>
To: patches@lists.linux.dev, stable@vger.kernel.org
Cc: Paulo Alcantara <pc@manguebit.org>, Jay Shin <jaeshin@redhat.com>,
David Howells <dhowells@redhat.com>,
Al Viro <viro@zeniv.linux.org.uk>,
linux-cifs@vger.kernel.org, Steve French <stfrench@microsoft.com>,
Sasha Levin <sashal@kernel.org>,
sfrench@samba.org, samba-technical@lists.samba.org
Subject: [PATCH AUTOSEL 6.16-6.1] smb: client: fix race with concurrent opens in unlink(2)
Date: Tue, 19 Aug 2025 13:35:14 -0400 [thread overview]
Message-ID: <20250819173521.1079913-4-sashal@kernel.org> (raw)
In-Reply-To: <20250819173521.1079913-1-sashal@kernel.org>
From: Paulo Alcantara <pc@manguebit.org>
[ Upstream commit 0af1561b2d60bab2a2b00720a5c7b292ecc549ec ]
According to some logs reported by customers, CIFS client might end up
reporting unlinked files as existing in stat(2) due to concurrent
opens racing with unlink(2).
Besides sending the removal request to the server, the unlink process
could involve closing any deferred close as well as marking all
existing open handles as deleted to prevent them from deferring
closes, which increases the race window for potential concurrent
opens.
Fix this by unhashing the dentry in cifs_unlink() to prevent any
subsequent opens. Any open attempts, while we're still unlinking,
will block on parent's i_rwsem.
Reported-by: Jay Shin <jaeshin@redhat.com>
Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
Reviewed-by: David Howells <dhowells@redhat.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: linux-cifs@vger.kernel.org
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
**Backport Status: YES**
This commit should be backported to stable kernel trees. Here's my
extensive analysis:
## Bug Fix Analysis
This commit fixes a **real-world race condition** reported by customers
where unlinked files incorrectly appear as existing in stat(2). The race
occurs between:
1. **unlink(2)** - which involves multiple steps including server
requests, closing deferred handles, and marking handles as deleted
2. **Concurrent open()** operations that can slip through during the
extended unlink window
## Code Changes Analysis
The fix is **minimal and surgical**, adding only 14 lines of code:
1. **Early dentry unhashing** (lines 1956-1962):
```c
/* Unhash dentry in advance to prevent any concurrent opens */
spin_lock(&dentry->d_lock);
if (!d_unhashed(dentry)) {
__d_drop(dentry);
rehash = true;
}
spin_unlock(&dentry->d_lock);
```
This prevents new opens from finding the dentry during unlink
processing.
2. **Conditional rehashing on error** (lines at end):
```c
if (rehash)
d_rehash(dentry);
```
This ensures the dentry is restored if unlink fails, maintaining
correct VFS semantics.
3. **Minor cleanup**: The d_drop() call is replaced with d_delete() for
positive dentries when ENOENT is returned.
## Stable Tree Criteria Met
1. **Fixes a real bug**: Customer-reported race condition causing
incorrect filesystem behavior
2. **Small and contained**: Only 14 lines added, changes confined to
single function
3. **No architectural changes**: Uses existing VFS primitives
(d_drop/d_rehash)
4. **Low regression risk**:
- Protected by proper locking (dentry->d_lock)
- Follows established VFS patterns
- Has proper error recovery path
5. **Similar fix already accepted**: Commit d84291fc7453 shows the same
pattern was successfully applied to rename(2)
## Additional Context
- The fix follows standard VFS practices for preventing races during
filesystem operations
- The pattern of unhashing dentries early is used elsewhere in the
kernel
- The commit has been reviewed by David Howells, a respected VFS
maintainer
- The issue affects data consistency from userspace perspective (stat
showing deleted files)
This is a textbook example of a stable-worthy commit: it fixes a real
bug with minimal, safe changes that don't introduce new features or
architectural modifications.
fs/smb/client/inode.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index 75be4b46bc6f..cf9060f0fc08 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -1943,15 +1943,24 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct tcon_link *tlink;
struct cifs_tcon *tcon;
+ __u32 dosattr = 0, origattr = 0;
struct TCP_Server_Info *server;
struct iattr *attrs = NULL;
- __u32 dosattr = 0, origattr = 0;
+ bool rehash = false;
cifs_dbg(FYI, "cifs_unlink, dir=0x%p, dentry=0x%p\n", dir, dentry);
if (unlikely(cifs_forced_shutdown(cifs_sb)))
return -EIO;
+ /* Unhash dentry in advance to prevent any concurrent opens */
+ spin_lock(&dentry->d_lock);
+ if (!d_unhashed(dentry)) {
+ __d_drop(dentry);
+ rehash = true;
+ }
+ spin_unlock(&dentry->d_lock);
+
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return PTR_ERR(tlink);
@@ -2003,7 +2012,8 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
cifs_drop_nlink(inode);
}
} else if (rc == -ENOENT) {
- d_drop(dentry);
+ if (simple_positive(dentry))
+ d_delete(dentry);
} else if (rc == -EBUSY) {
if (server->ops->rename_pending_delete) {
rc = server->ops->rename_pending_delete(full_path,
@@ -2056,6 +2066,8 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
kfree(attrs);
free_xid(xid);
cifs_put_tlink(tlink);
+ if (rehash)
+ d_rehash(dentry);
return rc;
}
--
2.50.1
next prev parent reply other threads:[~2025-08-19 17:35 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-19 17:35 [PATCH AUTOSEL 6.16] io_uring/io-wq: add check free worker before create new worker Sasha Levin
2025-08-19 17:35 ` [PATCH AUTOSEL 6.16] erofs: Fallback to normal access if DAX is not supported on extra device Sasha Levin
2025-08-19 17:35 ` [PATCH AUTOSEL 6.16-5.4] scsi: core: sysfs: Correct sysfs attributes access rights Sasha Levin
2025-08-19 17:35 ` Sasha Levin [this message]
2025-08-19 17:35 ` [PATCH AUTOSEL 6.16] ASoC: rt721: fix FU33 Boost Volume control not working Sasha Levin
2025-08-19 17:35 ` [PATCH AUTOSEL 6.16] ASoC: rt1320: fix random cycle mute issue Sasha Levin
2025-08-19 17:35 ` [PATCH AUTOSEL 6.16-6.1] smb: client: fix race with concurrent opens in rename(2) Sasha Levin
2025-08-19 17:35 ` [PATCH AUTOSEL 6.16-6.6] erofs: fix atomic context detection when !CONFIG_DEBUG_LOCK_ALLOC Sasha Levin
2025-08-19 17:35 ` [PATCH AUTOSEL 6.16-5.15] ASoC: codecs: tx-macro: correct tx_macro_component_drv name Sasha Levin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250819173521.1079913-4-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=dhowells@redhat.com \
--cc=jaeshin@redhat.com \
--cc=linux-cifs@vger.kernel.org \
--cc=patches@lists.linux.dev \
--cc=pc@manguebit.org \
--cc=samba-technical@lists.samba.org \
--cc=sfrench@samba.org \
--cc=stable@vger.kernel.org \
--cc=stfrench@microsoft.com \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox