From: Jeff Layton <jlayton@kernel.org>
To: NeilBrown <neil@brown.name>, Chuck Lever <chuck.lever@oracle.com>
Cc: Olga Kornievskaia <okorniev@redhat.com>,
Dai Ngo <Dai.Ngo@oracle.com>, Tom Talpey <tom@talpey.com>,
linux-nfs@vger.kernel.org
Subject: Re: [PATCH v5 18/18] nfsd: use do_lookup_open() for non-creating open requests too.
Date: Wed, 12 Aug 2026 13:12:46 -0400 [thread overview]
Message-ID: <bb2eb0ef5172cbfc4452f7a8a2afc866f629557f.camel@kernel.org> (raw)
In-Reply-To: <20260717093001.1972119-19-neilb@ownmail.net>
On Fri, 2026-07-17 at 19:28 +1000, NeilBrown wrote:
> From: NeilBrown <neil@brown.name>
>
> Now that we have do_lookup_open() for creating open requests, we can use
> it for non-creating too as do_lookup_open() is already able to do that.
>
> This prepares for switching to vfs_lookup_open() once the VFS provides
> that. This will ensure consistent code and fs-interaction with VFS open().
>
> The resulting simplification allows fh_fill_pre_attrs_unlocked() to be
> moved into nfsd4_open_file() (renamed from nfsd4_create_file()) so it is
> closer to fh_full_post_attrs and fh_fill_post_noop calls.
>
> As ->op_create_mode isn't defined when op_create is zero, we need a
> local create_mode which is -1 (illegal value) when op_create is zero.
>
> The non-create path now doesn't use nfsd_lookup(). As mount-point
> crossing including nfsd_check_access() is already included for existing
> names, this does not lose us anything.
>
> We now only call mnt_want_write() is there is a flag which indicates we
> might want write access - previously O_CREAT was always set.
>
> Signed-off-by: NeilBrown <neil@brown.name>
> ---
> fs/nfsd/nfs4proc.c | 113 ++++++++++++++++++++++-----------------------
> 1 file changed, 56 insertions(+), 57 deletions(-)
>
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index b7fdc75c4b81..11d0411dec08 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -204,9 +204,10 @@ static struct file *do_lookup_open(struct path *parent,
> struct file *filp = NULL;
> struct path path;
> struct dentry *child;
> - int want_write_err = 0;
> + int want_write_err = -ENOENT;
>
> - want_write_err = mnt_want_write(parent->mnt);
> + if (oflags & (O_CREAT|O_RDONLY|O_RDWR|O_TRUNC))
> + want_write_err = mnt_want_write(parent->mnt);
>
> child = start_creating(&nop_mnt_idmap, parent->dentry, name);
> if (IS_ERR(child)) {
> @@ -242,29 +243,30 @@ static struct file *do_lookup_open(struct path *parent,
> }
>
> /*
> - * Implement NFSv4's unchecked, guarded, and exclusive create
> - * semantics for regular files. Open state for this new file is
> - * subsequently fabricated in nfsd4_process_open2().
> - *
> + * Implement NFSv4's open semantics for regular files.
> + * Both create (unchecked, guarded, and exclusive) and non-create.
> + * Open state for this new file is subsequently fabricated in
> + * nfsd4_process_open2().
> * Upon return, caller must release @fhp and @resfhp.
> */
> static __be32
> -nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
> - struct svc_fh *resfhp, struct nfsd4_open *open)
> +nfsd4_open_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
> + struct svc_fh *resfhp, struct nfsd4_open *open)
> {
> struct iattr *iap = &open->op_iattr;
> struct nfsd_attrs attrs = {
> .na_iattr = iap,
> .na_seclabel = &open->op_label,
> };
> - int oflags = O_CREAT | O_LARGEFILE;
> + int oflags = O_LARGEFILE;
> struct dentry *child = ERR_PTR(-EINVAL);
> struct path parent = {
> .mnt = fhp->fh_export->ex_path.mnt,
> .dentry = fhp->fh_dentry,
> };
> __u32 v_mtime, v_atime;
> - __be32 status, create_status;
> + int createmode = -1;
> + __be32 status, create_status = 0;
> int want_write_err;
>
> if (name_is_dot_dotdot(open->op_fname, open->op_fnamelen))
> @@ -276,6 +278,10 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
> if (status != nfs_ok)
> return status;
>
> + status = fh_fill_pre_attrs_unlocked(fhp);
> + if (status)
> + return status;
> +
> if (open->op_createmode == NFS4_CREATE_UNCHECKED) {
> /*
> * If name is already in dcache we need to check for mountpoints
> @@ -305,11 +311,15 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
> if (!IS_POSIXACL(d_inode(parent.dentry)))
> iap->ia_mode &= ~current_umask();
>
> + if (open->op_create) {
> + createmode = open->op_createmode;
> + oflags |= O_CREAT;
> + }
> /*
> * For the EXCLUSIVE modes we do our own uniqueness tests
> * so don't want O_EXCL.
> */
> - if (open->op_createmode == NFS4_CREATE_GUARDED)
> + if (createmode == NFS4_CREATE_GUARDED)
> oflags |= O_EXCL;
>
> switch (open->op_share_access & NFS4_SHARE_ACCESS_BOTH) {
> @@ -344,7 +354,7 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
>
> v_mtime = 0;
> v_atime = 0;
> - if (nfsd4_create_is_exclusive(open->op_createmode)) {
> + if (nfsd4_create_is_exclusive(createmode)) {
> u32 *verifier = (u32 *)open->op_verf.data;
>
> /*
> @@ -366,11 +376,11 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
> iap->ia_atime.tv_nsec = 0;
> }
>
> - create_status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
> - if (create_status)
> - /* Might still succeed if no create is needed */
> - oflags &= ~O_CREAT;
> -
> + if (oflags & O_CREAT) {
> + create_status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
> + if (create_status)
> + oflags &= ~O_CREAT;
> + }
> open->op_filp = do_lookup_open(&parent,
> &QSTR_LEN(open->op_fname,
> open->op_fnamelen),
> @@ -392,14 +402,15 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
> goto out;
>
> if (!open->op_created &&
> - nfsd4_create_is_exclusive(open->op_createmode) &&
> + nfsd4_create_is_exclusive(createmode) &&
> inode_get_mtime_sec(d_inode(child)) == v_mtime &&
> inode_get_atime_sec(d_inode(child)) == v_atime &&
> d_inode(child)->i_size == 0)
> open->op_created = true;
>
> if (!open->op_created) {
> - if (open->op_createmode == NFS4_CREATE_UNCHECKED) {
> + if (open->op_create == NFS4_OPEN_NOCREATE ||
> + createmode == NFS4_CREATE_UNCHECKED) {
> /* NFSv4 protocol requires change attributes
> * even though no change happened.
> */
> @@ -494,46 +505,34 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
> fh_init(*resfh, NFS4_FHSIZE);
> open->op_truncate = false;
>
> - status = fh_fill_pre_attrs_unlocked(current_fh);
> - if (status)
> - goto out;
> - if (open->op_create) {
> - /* FIXME: check session persistence and pnfs flags.
> - * The nfsv4.1 spec requires the following semantics:
> - *
> - * Persistent | pNFS | Server REQUIRED | Client Allowed
> - * Reply Cache | server | |
> - * -------------+--------+-----------------+--------------------
> - * no | no | EXCLUSIVE4_1 | EXCLUSIVE4_1
> - * | | | (SHOULD)
> - * | | and EXCLUSIVE4 | or EXCLUSIVE4
> - * | | | (SHOULD NOT)
> - * no | yes | EXCLUSIVE4_1 | EXCLUSIVE4_1
> - * yes | no | GUARDED4 | GUARDED4
> - * yes | yes | GUARDED4 | GUARDED4
> - */
> + /* FIXME: check session persistence and pnfs flags.
> + * The nfsv4.1 spec requires the following semantics:
> + *
> + * Persistent | pNFS | Server REQUIRED | Client Allowed
> + * Reply Cache | server | |
> + * -------------+--------+-----------------+--------------------
> + * no | no | EXCLUSIVE4_1 | EXCLUSIVE4_1
> + * | | | (SHOULD)
> + * | | and EXCLUSIVE4 | or EXCLUSIVE4
> + * | | | (SHOULD NOT)
> + * no | yes | EXCLUSIVE4_1 | EXCLUSIVE4_1
> + * yes | no | GUARDED4 | GUARDED4
> + * yes | yes | GUARDED4 | GUARDED4
> + */
>
> - current->fs->umask = open->op_umask;
> - status = nfsd4_create_file(rqstp, current_fh, *resfh, open);
> - current->fs->umask = 0;
> + current->fs->umask = open->op_umask;
> + status = nfsd4_open_file(rqstp, current_fh, *resfh, open);
> + current->fs->umask = 0;
>
> - /*
> - * Following rfc 3530 14.2.16, and rfc 5661 18.16.4
> - * use the returned bitmask to indicate which attributes
> - * we used to store the verifier:
> - */
> - if (nfsd4_create_is_exclusive(open->op_createmode) && status == 0)
> - open->op_bmval[1] |= (FATTR4_WORD1_TIME_ACCESS |
> - FATTR4_WORD1_TIME_MODIFY);
> - } else {
> - status = nfsd_lookup(rqstp, current_fh,
> - open->op_fname, open->op_fnamelen, *resfh);
> - /*
> - * NFSv4 protocol requires change attributes even though
> - * no change happened.
> - */
> - fh_fill_post_noop(current_fh);
> - }
> + /*
> + * Following rfc 3530 14.2.16, and rfc 5661 18.16.4
> + * use the returned bitmask to indicate which attributes
> + * we used to store the verifier:
> + */
> + if (open->op_create &&
> + nfsd4_create_is_exclusive(open->op_createmode) && status == 0)
> + open->op_bmval[1] |= (FATTR4_WORD1_TIME_ACCESS |
> + FATTR4_WORD1_TIME_MODIFY);
> if (status)
> goto out;
> status = nfserrno(nfsd_check_obj_isreg((*resfh)->fh_dentry));
This patch is making the pynfs DELEG8 test fail. It seems like this
patch breaks the behavior where the server sends back NFS4ERR_DELAY on
an OPEN while waiting for a DELEGRETURN. The server just doesn't send a
reply until the delegation times out with it.
--
Jeff Layton <jlayton@kernel.org>
next prev parent reply other threads:[~2026-08-12 17:12 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-17 9:27 [PATCH v5 00/18] nfsd: refactor nfs4_create_file() NeilBrown
2026-07-17 9:27 ` [PATCH v5 01/18] nfsd: honour client-provided attributes for NFS4_CREATE_EXCLUSIVE4_1 NeilBrown
2026-07-17 9:27 ` [PATCH v5 02/18] nfsd: move check_nfsd_access() call into nfsd_cross_mnt() NeilBrown
2026-07-17 9:27 ` [PATCH v5 03/18] nfsd: correctly handle CREATE of mounted-on files NeilBrown
2026-07-17 9:27 ` [PATCH v5 04/18] nfsd: replace fh_fill_both_attrs() with fh_fill_post_noop() NeilBrown
2026-07-17 9:27 ` [PATCH v5 05/18] nfsd: move fh_want_write() after preamble in nfsd4_create_file() NeilBrown
2026-07-17 9:27 ` [PATCH v5 06/18] nfsd: move more nfs-specific code into preamble of nfsd4_create_file() NeilBrown
2026-07-17 9:27 ` [PATCH v5 07/18] nfsd: remove subtlety from nfsd4_create_file() NeilBrown
2026-07-17 9:27 ` [PATCH v5 08/18] nfsd: in nfsd4_create_file() let VFS report if file was created NeilBrown
2026-07-17 9:27 ` [PATCH v5 09/18] nfsd: nfsd4_create_file(): Move NFSD_MAY_CREATE check earlier NeilBrown
2026-07-17 9:27 ` [PATCH v5 10/18] nfsd: fh_want_write) failure need not be immediately fatal for nfsd4_create_file() NeilBrown
2026-07-17 9:27 ` [PATCH v5 11/18] nfsd: (almost) always open file in nfsd4_create_file() NeilBrown
2026-07-17 9:28 ` [PATCH v5 12/18] nfsd: reduce range of directory lock " NeilBrown
2026-07-17 9:28 ` [PATCH v5 13/18] nfsd: open-code nfsd4_vfs_create() into nfsd4_create_file() NeilBrown
2026-07-17 9:28 ` [PATCH v5 14/18] nfsd: move some code out of the d_really_is_negative() branch in nfsd4_create_file() NeilBrown
2026-07-17 9:28 ` [PATCH v5 15/18] nfsd: reduce want-write range " NeilBrown
2026-07-17 9:28 ` [PATCH v5 16/18] nfsd: move v0 checking out of nfsd_check_obj_isreg() NeilBrown
2026-07-17 9:28 ` [PATCH v5 17/18] nfsd: separate out VFS-specific code from nfsd4_create_file() NeilBrown
2026-07-17 9:28 ` [PATCH v5 18/18] nfsd: use do_lookup_open() for non-creating open requests too NeilBrown
2026-08-12 17:12 ` Jeff Layton [this message]
2026-07-17 11:29 ` [PATCH v5 00/18] nfsd: refactor nfs4_create_file() Jeff Layton
2026-07-17 13:30 ` Chuck Lever
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=bb2eb0ef5172cbfc4452f7a8a2afc866f629557f.camel@kernel.org \
--to=jlayton@kernel.org \
--cc=Dai.Ngo@oracle.com \
--cc=chuck.lever@oracle.com \
--cc=linux-nfs@vger.kernel.org \
--cc=neil@brown.name \
--cc=okorniev@redhat.com \
--cc=tom@talpey.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.