Skip to content

Commit dc0325b

Browse files
pcacjrsmfrench
authored andcommitted
smb: client: get rid of d_drop()+d_add()
Replace d_drop()+d_add() in cifs_tmpfile() and cifs_create() with d_instantiate(), and in cifs_atomic_open() with d_splice_alias() if in-lookup, otherwise d_instantiate(). Reported-by: Al Viro <viro@zeniv.linux.org.uk> Closes: https://lore.kernel.org/r/20260408065719.GF3836593@ZenIV Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.org> Cc: David Howells <dhowells@redhat.com> Cc: NeilBrown <neilb@ownmail.net> Cc: linux-fsdevel@vger.kernel.org Cc: linux-cifs@vger.kernel.org Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent 62e0208 commit dc0325b

2 files changed

Lines changed: 40 additions & 26 deletions

File tree

fs/smb/client/cifsfs.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ void cifs_sb_deactive(struct super_block *sb);
5252
/* Functions related to inodes */
5353
extern const struct inode_operations cifs_dir_inode_ops;
5454
struct inode *cifs_root_iget(struct super_block *sb);
55-
int cifs_create(struct mnt_idmap *idmap, struct inode *inode,
55+
int cifs_create(struct mnt_idmap *idmap, struct inode *dir,
5656
struct dentry *direntry, umode_t mode, bool excl);
57-
int cifs_atomic_open(struct inode *inode, struct dentry *direntry,
57+
int cifs_atomic_open(struct inode *dir, struct dentry *direntry,
5858
struct file *file, unsigned int oflags, umode_t mode);
5959
int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
6060
struct file *file, umode_t mode);

fs/smb/client/dir.c

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ static int __cifs_do_create(struct inode *dir, struct dentry *direntry,
219219
int rdwr_for_fscache = 0;
220220
__le32 lease_flags = 0;
221221

222+
*inode = NULL;
222223
*oplock = 0;
223224
if (tcon->ses->server->oplocks)
224225
*oplock = REQ_OPLOCK;
@@ -462,7 +463,6 @@ static int __cifs_do_create(struct inode *dir, struct dentry *direntry,
462463
goto out_err;
463464
}
464465

465-
d_drop(direntry);
466466
*inode = newinode;
467467
return rc;
468468

@@ -478,11 +478,11 @@ static int cifs_do_create(struct inode *dir, struct dentry *direntry,
478478
unsigned int xid, struct tcon_link *tlink,
479479
unsigned int oflags, umode_t mode,
480480
__u32 *oplock, struct cifs_fid *fid,
481-
struct cifs_open_info_data *buf)
481+
struct cifs_open_info_data *buf,
482+
struct inode **inode)
482483
{
483484
void *page = alloc_dentry_path();
484485
const char *full_path;
485-
struct inode *inode;
486486
int rc;
487487

488488
full_path = build_path_from_dentry(direntry, page);
@@ -491,9 +491,7 @@ static int cifs_do_create(struct inode *dir, struct dentry *direntry,
491491
} else {
492492
rc = __cifs_do_create(dir, direntry, full_path, xid,
493493
tlink, oflags, mode, oplock,
494-
fid, buf, &inode);
495-
if (!rc)
496-
d_add(direntry, inode);
494+
fid, buf, inode);
497495
}
498496
free_dentry_path(page);
499497
return rc;
@@ -504,13 +502,13 @@ static int cifs_do_create(struct inode *dir, struct dentry *direntry,
504502
* Look up, create and open a CIFS file.
505503
*
506504
* The initial dentry state is in-lookup or hashed-negative. On success, dentry
507-
* will become hashed-positive by calling d_drop() & d_add(), respectively.
505+
* will become hashed-positive by calling d_splice_alias() if in-lookup,
506+
* otherwise d_instantiate().
508507
*/
509-
int
510-
cifs_atomic_open(struct inode *inode, struct dentry *direntry,
511-
struct file *file, unsigned int oflags, umode_t mode)
508+
int cifs_atomic_open(struct inode *dir, struct dentry *direntry,
509+
struct file *file, unsigned int oflags, umode_t mode)
512510
{
513-
struct cifs_sb_info *cifs_sb = CIFS_SB(inode);
511+
struct cifs_sb_info *cifs_sb = CIFS_SB(dir);
514512
struct cifs_open_info_data buf = {};
515513
struct TCP_Server_Info *server;
516514
struct cifsFileInfo *file_info;
@@ -519,6 +517,8 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
519517
struct tcon_link *tlink;
520518
struct cifs_tcon *tcon;
521519
unsigned int sbflags;
520+
struct dentry *alias;
521+
struct inode *inode;
522522
unsigned int xid;
523523
__u32 oplock;
524524
int rc;
@@ -545,13 +545,13 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
545545
if (!d_in_lookup(direntry))
546546
return -ENOENT;
547547

548-
return finish_no_open(file, cifs_lookup(inode, direntry, 0));
548+
return finish_no_open(file, cifs_lookup(dir, direntry, 0));
549549
}
550550

551551
xid = get_xid();
552552

553553
cifs_dbg(FYI, "parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
554-
inode, direntry, direntry);
554+
dir, direntry, direntry);
555555

556556
tlink = cifs_sb_tlink(cifs_sb);
557557
if (IS_ERR(tlink)) {
@@ -572,13 +572,21 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
572572

573573
cifs_add_pending_open(&fid, tlink, &open);
574574

575-
rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
576-
&oplock, &fid, &buf);
575+
rc = cifs_do_create(dir, direntry, xid, tlink, oflags, mode,
576+
&oplock, &fid, &buf, &inode);
577577
if (rc) {
578578
cifs_del_pending_open(&open);
579579
goto out;
580580
}
581581

582+
if (d_in_lookup(direntry)) {
583+
alias = d_splice_alias(inode, direntry);
584+
if (!IS_ERR_OR_NULL(alias))
585+
direntry = alias;
586+
} else {
587+
d_instantiate(direntry, inode);
588+
}
589+
582590
if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
583591
file->f_mode |= FMODE_CREATED;
584592

@@ -622,11 +630,12 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
622630
* Create a CIFS file.
623631
*
624632
* The initial dentry state is hashed-negative. On success, dentry will become
625-
* hashed-positive by calling d_drop() & d_add(), respectively.
633+
* hashed-positive by calling d_instantiate().
626634
*/
627-
int cifs_create(struct mnt_idmap *idmap, struct inode *inode,
635+
int cifs_create(struct mnt_idmap *idmap, struct inode *dir,
628636
struct dentry *direntry, umode_t mode, bool excl)
629637
{
638+
struct cifs_sb_info *cifs_sb = CIFS_SB(dir);
630639
int rc;
631640
unsigned int xid = get_xid();
632641
/*
@@ -640,19 +649,20 @@ int cifs_create(struct mnt_idmap *idmap, struct inode *inode,
640649
struct tcon_link *tlink;
641650
struct cifs_tcon *tcon;
642651
struct TCP_Server_Info *server;
652+
struct inode *inode;
643653
struct cifs_fid fid;
644654
__u32 oplock;
645655
struct cifs_open_info_data buf = {};
646656

647657
cifs_dbg(FYI, "cifs_create parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
648-
inode, direntry, direntry);
658+
dir, direntry, direntry);
649659

650-
if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb)))) {
660+
if (unlikely(cifs_forced_shutdown(cifs_sb))) {
651661
rc = smb_EIO(smb_eio_trace_forced_shutdown);
652662
goto out_free_xid;
653663
}
654664

655-
tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb));
665+
tlink = cifs_sb_tlink(cifs_sb);
656666
rc = PTR_ERR(tlink);
657667
if (IS_ERR(tlink))
658668
goto out_free_xid;
@@ -663,9 +673,13 @@ int cifs_create(struct mnt_idmap *idmap, struct inode *inode,
663673
if (server->ops->new_lease_key)
664674
server->ops->new_lease_key(&fid);
665675

666-
rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, &oplock, &fid, &buf);
667-
if (!rc && server->ops->close)
668-
server->ops->close(xid, tcon, &fid);
676+
rc = cifs_do_create(dir, direntry, xid, tlink, oflags,
677+
mode, &oplock, &fid, &buf, &inode);
678+
if (!rc) {
679+
d_instantiate(direntry, inode);
680+
if (server->ops->close)
681+
server->ops->close(xid, tcon, &fid);
682+
}
669683

670684
cifs_free_open_info(&buf);
671685
cifs_put_tlink(tlink);
@@ -1035,7 +1049,7 @@ static int set_tmpfile_attr(const unsigned int xid, unsigned int oflags,
10351049
* Create a hidden temporary CIFS file with delete-on-close bit set.
10361050
*
10371051
* The initial dentry state is unhashed-negative. On success, dentry will
1038-
* become unhashed-positive by calling d_drop() & d_instantiate(), respectively.
1052+
* become unhashed-positive by calling d_instantiate().
10391053
*/
10401054
int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
10411055
struct file *file, umode_t mode)

0 commit comments

Comments
 (0)