Skip to content

Commit 8d61637

Browse files
pcacjropsiff
authored andcommitted
smb: client: fix race with concurrent opens in rename(2)
[ Upstream commit d84291fc7453df7881a970716f8256273aca5747 ] Besides sending the rename request to the server, the rename process also involves closing any deferred close, waiting for outstanding I/O to complete 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 on the target file. Fix this by unhashing the dentry in advance to prevent any concurrent opens on the target. Signed-off-by: Paulo Alcantara (Red Hat) <[email protected]> Reviewed-by: David Howells <[email protected]> Cc: Al Viro <[email protected]> Cc: [email protected] Signed-off-by: Steve French <[email protected]> Signed-off-by: Sasha Levin <[email protected]> (cherry picked from commit 24b9ed739c8c5b464d983e12cf308982f3ae93c2)
1 parent ad07955 commit 8d61637

File tree

1 file changed

+18
-0
lines changed

1 file changed

+18
-0
lines changed

fs/smb/client/inode.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2379,6 +2379,7 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
23792379
struct cifs_sb_info *cifs_sb;
23802380
struct tcon_link *tlink;
23812381
struct cifs_tcon *tcon;
2382+
bool rehash = false;
23822383
unsigned int xid;
23832384
int rc, tmprc;
23842385
int retry_count = 0;
@@ -2394,6 +2395,17 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
23942395
if (unlikely(cifs_forced_shutdown(cifs_sb)))
23952396
return -EIO;
23962397

2398+
/*
2399+
* Prevent any concurrent opens on the target by unhashing the dentry.
2400+
* VFS already unhashes the target when renaming directories.
2401+
*/
2402+
if (d_is_positive(target_dentry) && !d_is_dir(target_dentry)) {
2403+
if (!d_unhashed(target_dentry)) {
2404+
d_drop(target_dentry);
2405+
rehash = true;
2406+
}
2407+
}
2408+
23972409
tlink = cifs_sb_tlink(cifs_sb);
23982410
if (IS_ERR(tlink))
23992411
return PTR_ERR(tlink);
@@ -2433,6 +2445,8 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
24332445
}
24342446
}
24352447

2448+
if (!rc)
2449+
rehash = false;
24362450
/*
24372451
* No-replace is the natural behavior for CIFS, so skip unlink hacks.
24382452
*/
@@ -2491,12 +2505,16 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
24912505
goto cifs_rename_exit;
24922506
rc = cifs_do_rename(xid, source_dentry, from_name,
24932507
target_dentry, to_name);
2508+
if (!rc)
2509+
rehash = false;
24942510
}
24952511

24962512
/* force revalidate to go get info when needed */
24972513
CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0;
24982514

24992515
cifs_rename_exit:
2516+
if (rehash)
2517+
d_rehash(target_dentry);
25002518
kfree(info_buf_source);
25012519
free_dentry_path(page2);
25022520
free_dentry_path(page1);

0 commit comments

Comments
 (0)