Linux filesystem development
 help / color / mirror / Atom feed
From: "Chuck Lever" <cel@kernel.org>
To: NeilBrown <neil@brown.name>
Cc: "Alexander Viro" <viro@zeniv.linux.org.uk>,
	"Christian Brauner" <brauner@kernel.org>,
	"Jeff Layton" <jlayton@kernel.org>,
	linux-fsdevel@vger.kernel.org, linux-nfs@vger.kernel.org
Subject: Re: [PATCH 5/7] nfsd: switch NFS4 OPEN to use vfs_lookup_open()
Date: Thu, 10 Sep 2026 11:41:31 -0400	[thread overview]
Message-ID: <e36532d5-e37f-4d71-b83a-c8d19d87811f@slotpi15m67> (raw)
In-Reply-To: <20260910002934.192979-6-neilb@ownmail.net>

>     This implementation shares more code with syscall open paths and so uses
>     some filesystem interfaces slightly more correctly.  It also takes the

Which interfaces? The concrete difference I can see is that lookup_open()
honors ->atomic_open, which do_lookup_open() never called. Naming that
would be clearer than "slightly more correctly".


>     We need to pass O_NONBLOCK so that that EWOULDBLOCK errors from

Repeated word: "that that".


>     vfs_lookup_open() always returns -EFTYPE if a non-regular-file was
>     found, and provides the dentry in parent.dentry.  We can use
>     nfsd_check_obj_is_reg() to turn this into an error.
>
>     As parent.dentry could be NULL, we enhance nfsd_check_obj_is_reg() to
>     cope with that.

The function is nfsd_check_obj_isreg(), in both places.


>     vfs_lookup_open() will return -EEXIST if required for
>     NFS_CREATE_GUARDED4 as O_EXCL is passed in.  Other checks for
>     and existing object need only test for nfsd4_create_is_exclusive().

s/and existing/an existing/, and the identifier is NFS4_CREATE_GUARDED.

The -EEXIST claim holds only on the path through the tail of
vfs_lookup_open(), where the O_EXCL test runs before the d_is_reg()
test. When lookup_open() itself returns -EFTYPE, vfs_lookup_open()
returns before either test. See below.


> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index 3a82af381a8d..0fd5a6411ed3 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c

[ ... ]

> @@ -312,7 +269,7 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
>  		.na_iattr	= iap,
>  		.na_seclabel	= &open->op_label,
>  	};
> -	int oflags = O_CREAT | O_LARGEFILE;
> +	int oflags = O_CREAT | O_LARGEFILE | O_NONBLOCK;

Nit: do_dentry_open() strips O_CREAT, O_EXCL and O_TRUNC from f_flags
and leaves O_NONBLOCK in place, so op_filp now carries O_NONBLOCK into
the filecache entry that nfsd_file_acquire_opened() builds from it.
Files opened through __nfsd_open() do not. Is that divergence
intended?


>  	struct dentry *child = ERR_PTR(-EINVAL);
>  	struct path parent = {
>  		.mnt = fhp->fh_export->ex_path.mnt,
> @@ -424,28 +381,29 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
>  		/* Might still succeed if no create is needed */
>  		oflags &= ~O_CREAT;
>  
> -	open->op_filp = do_lookup_open(&parent,
> -				       &QSTR_LEN(open->op_fname,
> -						 open->op_fnamelen),
> -				       oflags,
> -				       open->op_iattr.ia_mode);
> +	dget(parent.dentry);
> +	open->op_filp = vfs_lookup_open(&parent,
> +					&QSTR_LEN(open->op_fname,
> +						  open->op_fnamelen),
> +					oflags,
> +					open->op_iattr.ia_mode & S_IALLUGO);

Nit: after this call "parent.dentry" is the child (or NULL), while a
few lines up IS_POSIXACL(d_inode(parent.dentry)) reads the same
expression as the parent directory. The VFS patch renamed its parameter
to @path for this reason. Would renaming the local here avoid the same
trap?


>  	if (IS_ERR(open->op_filp)) {
>  		int hosterr = PTR_ERR(open->op_filp);
>  
> -		if (open->op_createmode != NFS4_CREATE_UNCHECKED) {
> -			switch (hosterr) {
> -			case -EISDIR:
> -			case -ELOOP:
> -			case -EFTYPE:
> +		if (hosterr == -EFTYPE) {
> +			if (nfsd4_create_is_exclusive(open->op_createmode))
>  				hosterr = -EEXIST;
> -			}
> +			else
> +				hosterr = nfsd_check_obj_isreg(parent.dentry);
>  		}

Does this drop the NFS4ERR_EXIST mapping for GUARDED4?

The old test covered GUARDED as well as the two EXCLUSIVE modes.
nfsd4_create_is_exclusive() covers only EXCLUSIVE4 and EXCLUSIVE4_1, so
a GUARDED open that finds a non-regular object now takes the else arm
and returns NFS4ERR_ISDIR, NFS4ERR_WRONG_TYPE, and so on. RFC 8881
section 18.16.3 says a GUARDED4 duplicate is NFS4ERR_EXIST.

Keeping "open->op_createmode != NFS4_CREATE_UNCHECKED" here would
restore the old mapping without depending on the ordering of checks
inside each filesystem's ->atomic_open.

Separately, can this arm return nfs_ok? nfsd_check_obj_isreg() returns
0 for a regular file, and vfs_lookup_open() can leave a regular file in
parent.dentry when the d_lookup() it does after an -EFTYPE races with a
rename (the VFS marks that case with a WARN_ON_ONCE rather than
excluding it). nfserrno(0) is nfs_ok, op_filp is then set to NULL, and
nfsd4_create_file() returns success with resfhp never composed. It only
fails safely today because do_open_lookup() then calls
nfsd_check_obj_isreg() on the NULL fh_dentry. Something like

		if (!hosterr)
			hosterr = -EFTYPE;

would address that.


>  		status = nfserrno(hosterr);
>  		open->op_filp = NULL;
>  		if (status == nfserr_noent && create_status)
>  			status = create_status;
> +		dput(parent.dentry);
>  		goto out;
>  	}
> +	dput(parent.dentry);
>  
>  	child = open->op_filp->f_path.dentry;
>  	open->op_created = open->op_filp->f_mode & FMODE_CREATED;
> @@ -462,7 +420,9 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
>  		open->op_created = true;
>  
>  	if (!open->op_created) {
> -		if (open->op_createmode == NFS4_CREATE_UNCHECKED) {
> +		if (nfsd4_create_is_exclusive(open->op_createmode)) {
> +			status = nfserr_exist;
> +		} else {

Same question here. GUARDED used to get nfserr_exist from this branch
and now gets the "no change happened" arm. It is unreachable for GUARDED
today only because vfs_lookup_open() returns -EEXIST whenever O_EXCL is
set and nothing was created. Should this also stay as
"!= NFS4_CREATE_UNCHECKED" so the protocol rule is enforced here rather
than relying on that ordering?


-- 
Chuck Lever (Come to NFS bake-a-thon! https://nfsv4bat.org)

  reply	other threads:[~2026-09-10 15:41 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-10  0:20 [PATCH 0/7 RFC] fixes for vfs_lookup_open, and integration with nfsd NeilBrown
2026-09-10  0:20 ` [PATCH 1/7] vfs: add some allowed open flags to vfs_lookup_open() NeilBrown
2026-09-10  0:20 ` [PATCH 2/7] vfs: O_NONBLOCK|O_CREAT open shouldn't wait for directory delegation NeilBrown
2026-09-10  0:20 ` [PATCH 3/7] vfs: vfs_lookup_open() should only return -EFTYPE for non-regular files NeilBrown
2026-09-10  0:20 ` [PATCH 4/7] vfs: change vfs_lookup_open() to return found dentry in path.dentry NeilBrown
2026-09-10  0:39   ` NeilBrown
2026-09-10 15:13   ` Chuck Lever
2026-09-10  0:20 ` [PATCH 5/7] nfsd: switch NFS4 OPEN to use vfs_lookup_open() NeilBrown
2026-09-10 15:41   ` Chuck Lever [this message]
2026-09-10  0:20 ` [PATCH 6/7] nfsd: nfsd_check_obj_isreg() to use nfs error codes NeilBrown
2026-09-10  0:20 ` [PATCH 7/7] nfsd: use vfs_lookup_open() for non-creating open requests too NeilBrown
2026-09-10 15:47   ` 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=e36532d5-e37f-4d71-b83a-c8d19d87811f@slotpi15m67 \
    --to=cel@kernel.org \
    --cc=brauner@kernel.org \
    --cc=jlayton@kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=neil@brown.name \
    --cc=viro@zeniv.linux.org.uk \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox