diff options
| author | NeilBrown <neil@brown.name> | 2026-07-17 19:27:59 +1000 |
|---|---|---|
| committer | Chuck Lever <cel@kernel.org> | 2026-09-13 20:36:54 -0400 |
| commit | 8b3530c951ade522cecbcbd19775dcbb30cd2f6a (patch) | |
| tree | fb1de9ecbea4165d15ad7c3621f11e3ab2535ee3 | |
| parent | 4f6843bee83c3e243d7ae72fc1c8514818b2a9fc (diff) | |
| download | linux-next-8b3530c951ade522cecbcbd19775dcbb30cd2f6a.tar.gz linux-next-8b3530c951ade522cecbcbd19775dcbb30cd2f6a.zip | |
nfsd: (almost) always open file in nfsd4_create_file()
If the file is found to already exist, open it anyway. This will
normally be needed eventually anyway, and providing a consistently valid
op_filp will simplify future changes.
To simplify this, change nfsd_check_obj_isreg() to take a dentry.
This doesn't apply in the case where the file was found in the dcache to
be mounted-on. That takes a different path and doesn't require an early
open.
Signed-off-by: NeilBrown <neil@brown.name>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260717093001.1972119-12-neilb@ownmail.net
Signed-off-by: Chuck Lever <cel@kernel.org>
| -rw-r--r-- | fs/nfsd/nfs4proc.c | 39 |
1 files changed, 35 insertions, 4 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 527602698d38..226993ca761a 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -169,9 +169,9 @@ do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs return fh_verify(rqstp, current_fh, S_IFREG, accmode); } -static __be32 nfsd_check_obj_isreg(struct svc_fh *fh, u32 minor_version) +static __be32 nfsd_check_obj_isreg(struct dentry *child, u32 minor_version) { - umode_t mode = d_inode(fh->fh_dentry)->i_mode; + umode_t mode = d_inode(child)->i_mode; if (S_ISREG(mode)) return nfs_ok; @@ -253,6 +253,8 @@ static __be32 nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct svc_fh *resfhp, struct nfsd4_open *open) { + struct nfsd4_compoundres *resp = rqstp->rq_resp; + struct nfsd4_compound_state *cstate = &resp->cstate; struct iattr *iap = &open->op_iattr; struct nfsd_attrs attrs = { .na_iattr = iap, @@ -363,7 +365,35 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, } if (d_really_is_positive(child)) { - /* No creation needed */ + /* + * open the file so that we consistently have a valid + * op_filp. + */ + struct path path = {.mnt = fhp->fh_export->ex_path.mnt, + .dentry = child, + }; + unsigned int oflags = O_LARGEFILE; + + switch (open->op_share_access & NFS4_SHARE_ACCESS_BOTH) { + case NFS4_SHARE_ACCESS_WRITE: + oflags |= O_WRONLY; + break; + case NFS4_SHARE_ACCESS_BOTH: + oflags |= O_RDWR; + break; + default: + oflags |= O_RDONLY; + } + + status = nfsd_check_obj_isreg(child, cstate->minorversion); + if (status == nfs_ok) { + open->op_filp = dentry_open(&path, oflags, + current_cred()); + if (IS_ERR(open->op_filp)) { + status = nfserrno(PTR_ERR(open->op_filp)); + open->op_filp = NULL; + } + } } else if (create_status) { status = create_status; } else { @@ -517,7 +547,8 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru } if (status) goto out; - status = nfsd_check_obj_isreg(*resfh, cstate->minorversion); + status = nfsd_check_obj_isreg((*resfh)->fh_dentry, + cstate->minorversion); if (status) goto out; |
