Skip to content

Commit 8376583

Browse files
neilbrownbrauner
authored andcommitted
nfs: change mkdir inode_operation to return alternate dentry if needed.
mkdir now allows a different dentry to be returned which is sometimes relevant for nfs. This patch changes the nfs_rpc_ops mkdir op to return a dentry, and passes that back to the caller. The mkdir nfs_rpc_op will return NULL if the original dentry should be used. This matches the mkdir inode_operation. nfs4_do_create() is duplicated to nfs4_do_mkdir() which is changed to handle the specifics of directories. Consequently the current special handling for directories is removed from nfs4_do_create() Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: NeilBrown <neilb@suse.de> Link: https://lore.kernel.org/r/20250227013949.536172-6-neilb@suse.de Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent d701902 commit 8376583

5 files changed

Lines changed: 60 additions & 39 deletions

File tree

fs/nfs/dir.c

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2426,7 +2426,7 @@ struct dentry *nfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
24262426
struct dentry *dentry, umode_t mode)
24272427
{
24282428
struct iattr attr;
2429-
int error;
2429+
struct dentry *ret;
24302430

24312431
dfprintk(VFS, "NFS: mkdir(%s/%lu), %pd\n",
24322432
dir->i_sb->s_id, dir->i_ino, dentry);
@@ -2435,14 +2435,9 @@ struct dentry *nfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
24352435
attr.ia_mode = mode | S_IFDIR;
24362436

24372437
trace_nfs_mkdir_enter(dir, dentry);
2438-
error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr);
2439-
trace_nfs_mkdir_exit(dir, dentry, error);
2440-
if (error != 0)
2441-
goto out_err;
2442-
return NULL;
2443-
out_err:
2444-
d_drop(dentry);
2445-
return ERR_PTR(error);
2438+
ret = NFS_PROTO(dir)->mkdir(dir, dentry, &attr);
2439+
trace_nfs_mkdir_exit(dir, dentry, PTR_ERR_OR_ZERO(ret));
2440+
return ret;
24462441
}
24472442
EXPORT_SYMBOL_GPL(nfs_mkdir);
24482443

fs/nfs/nfs3proc.c

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -578,22 +578,23 @@ nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct folio *folio,
578578
return status;
579579
}
580580

581-
static int
581+
static struct dentry *
582582
nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
583583
{
584584
struct posix_acl *default_acl, *acl;
585585
struct nfs3_createdata *data;
586-
struct dentry *d_alias;
587-
int status = -ENOMEM;
586+
struct dentry *ret = ERR_PTR(-ENOMEM);
587+
int status;
588588

589589
dprintk("NFS call mkdir %pd\n", dentry);
590590

591591
data = nfs3_alloc_createdata();
592592
if (data == NULL)
593593
goto out;
594594

595-
status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl);
596-
if (status)
595+
ret = ERR_PTR(posix_acl_create(dir, &sattr->ia_mode,
596+
&default_acl, &acl));
597+
if (IS_ERR(ret))
597598
goto out;
598599

599600
data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR];
@@ -602,25 +603,27 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
602603
data->arg.mkdir.len = dentry->d_name.len;
603604
data->arg.mkdir.sattr = sattr;
604605

605-
d_alias = nfs3_do_create(dir, dentry, data);
606-
status = PTR_ERR_OR_ZERO(d_alias);
606+
ret = nfs3_do_create(dir, dentry, data);
607607

608-
if (status != 0)
608+
if (IS_ERR(ret))
609609
goto out_release_acls;
610610

611-
if (d_alias)
612-
dentry = d_alias;
611+
if (ret)
612+
dentry = ret;
613613

614614
status = nfs3_proc_setacls(d_inode(dentry), acl, default_acl);
615+
if (status) {
616+
dput(ret);
617+
ret = ERR_PTR(status);
618+
}
615619

616-
dput(d_alias);
617620
out_release_acls:
618621
posix_acl_release(acl);
619622
posix_acl_release(default_acl);
620623
out:
621624
nfs3_free_createdata(data);
622-
dprintk("NFS reply mkdir: %d\n", status);
623-
return status;
625+
dprintk("NFS reply mkdir: %d\n", PTR_ERR_OR_ZERO(ret));
626+
return ret;
624627
}
625628

626629
static int

fs/nfs/nfs4proc.c

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5133,9 +5133,6 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_
51335133
&data->arg.seq_args, &data->res.seq_res, 1);
51345134
if (status == 0) {
51355135
spin_lock(&dir->i_lock);
5136-
/* Creating a directory bumps nlink in the parent */
5137-
if (data->arg.ftype == NF4DIR)
5138-
nfs4_inc_nlink_locked(dir);
51395136
nfs4_update_changeattr_locked(dir, &data->res.dir_cinfo,
51405137
data->res.fattr->time_start,
51415138
NFS_INO_INVALID_DATA);
@@ -5145,6 +5142,25 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_
51455142
return status;
51465143
}
51475144

5145+
static struct dentry *nfs4_do_mkdir(struct inode *dir, struct dentry *dentry,
5146+
struct nfs4_createdata *data)
5147+
{
5148+
int status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &data->msg,
5149+
&data->arg.seq_args, &data->res.seq_res, 1);
5150+
5151+
if (status)
5152+
return ERR_PTR(status);
5153+
5154+
spin_lock(&dir->i_lock);
5155+
/* Creating a directory bumps nlink in the parent */
5156+
nfs4_inc_nlink_locked(dir);
5157+
nfs4_update_changeattr_locked(dir, &data->res.dir_cinfo,
5158+
data->res.fattr->time_start,
5159+
NFS_INO_INVALID_DATA);
5160+
spin_unlock(&dir->i_lock);
5161+
return nfs_add_or_obtain(dentry, data->res.fh, data->res.fattr);
5162+
}
5163+
51485164
static void nfs4_free_createdata(struct nfs4_createdata *data)
51495165
{
51505166
nfs4_label_free(data->fattr.label);
@@ -5201,47 +5217,50 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
52015217
return err;
52025218
}
52035219

5204-
static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
5205-
struct iattr *sattr, struct nfs4_label *label)
5220+
static struct dentry *_nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
5221+
struct iattr *sattr,
5222+
struct nfs4_label *label)
52065223
{
52075224
struct nfs4_createdata *data;
5208-
int status = -ENOMEM;
5225+
struct dentry *ret = ERR_PTR(-ENOMEM);
52095226

52105227
data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4DIR);
52115228
if (data == NULL)
52125229
goto out;
52135230

52145231
data->arg.label = label;
5215-
status = nfs4_do_create(dir, dentry, data);
5232+
ret = nfs4_do_mkdir(dir, dentry, data);
52165233

52175234
nfs4_free_createdata(data);
52185235
out:
5219-
return status;
5236+
return ret;
52205237
}
52215238

5222-
static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
5223-
struct iattr *sattr)
5239+
static struct dentry *nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
5240+
struct iattr *sattr)
52245241
{
52255242
struct nfs_server *server = NFS_SERVER(dir);
52265243
struct nfs4_exception exception = {
52275244
.interruptible = true,
52285245
};
52295246
struct nfs4_label l, *label;
5247+
struct dentry *alias;
52305248
int err;
52315249

52325250
label = nfs4_label_init_security(dir, dentry, sattr, &l);
52335251

52345252
if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
52355253
sattr->ia_mode &= ~current_umask();
52365254
do {
5237-
err = _nfs4_proc_mkdir(dir, dentry, sattr, label);
5255+
alias = _nfs4_proc_mkdir(dir, dentry, sattr, label);
5256+
err = PTR_ERR_OR_ZERO(alias);
52385257
trace_nfs4_mkdir(dir, &dentry->d_name, err);
52395258
err = nfs4_handle_exception(NFS_SERVER(dir), err,
52405259
&exception);
52415260
} while (exception.retry);
52425261
nfs4_label_release_security(label);
52435262

5244-
return err;
5263+
return alias;
52455264
}
52465265

52475266
static int _nfs4_proc_readdir(struct nfs_readdir_arg *nr_arg,

fs/nfs/proc.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -446,13 +446,14 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct folio *folio,
446446
return status;
447447
}
448448

449-
static int
449+
static struct dentry *
450450
nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
451451
{
452452
struct nfs_createdata *data;
453453
struct rpc_message msg = {
454454
.rpc_proc = &nfs_procedures[NFSPROC_MKDIR],
455455
};
456+
struct dentry *alias = NULL;
456457
int status = -ENOMEM;
457458

458459
dprintk("NFS call mkdir %pd\n", dentry);
@@ -464,12 +465,15 @@ nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
464465

465466
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
466467
nfs_mark_for_revalidate(dir);
467-
if (status == 0)
468-
status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
468+
if (status == 0) {
469+
alias = nfs_add_or_obtain(dentry, data->res.fh, data->res.fattr);
470+
status = PTR_ERR_OR_ZERO(alias);
471+
} else
472+
alias = ERR_PTR(status);
469473
nfs_free_createdata(data);
470474
out:
471475
dprintk("NFS reply mkdir: %d\n", status);
472-
return status;
476+
return alias;
473477
}
474478

475479
static int

include/linux/nfs_xdr.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1802,7 +1802,7 @@ struct nfs_rpc_ops {
18021802
int (*link) (struct inode *, struct inode *, const struct qstr *);
18031803
int (*symlink) (struct inode *, struct dentry *, struct folio *,
18041804
unsigned int, struct iattr *);
1805-
int (*mkdir) (struct inode *, struct dentry *, struct iattr *);
1805+
struct dentry *(*mkdir) (struct inode *, struct dentry *, struct iattr *);
18061806
int (*rmdir) (struct inode *, const struct qstr *);
18071807
int (*readdir) (struct nfs_readdir_arg *, struct nfs_readdir_res *);
18081808
int (*mknod) (struct inode *, struct dentry *, struct iattr *,

0 commit comments

Comments
 (0)