From: Jeff Layton <jlayton@kernel.org>
To: NeilBrown <neilb@suse.de>, Chuck Lever <chuck.lever@oracle.com>
Cc: linux-nfs@vger.kernel.org, Olga Kornievskaia <kolga@netapp.com>,
Dai Ngo <Dai.Ngo@oracle.com>, Tom Talpey <tom@talpey.com>
Subject: Re: [PATCH 3/3] nfsd: move error choice for incorrect object types to version-specific code.
Date: Thu, 08 Aug 2024 06:37:13 -0400 [thread overview]
Message-ID: <aab4166ae13a4453ea18644da6cc260e41f1b49f.camel@kernel.org> (raw)
In-Reply-To: <20240729014940.23053-4-neilb@suse.de>
[-- Attachment #1: Type: text/plain, Size: 7036 bytes --]
On Mon, 2024-07-29 at 11:47 +1000, NeilBrown wrote:
> If an NFS operation expect a particular sort of object (file, dir, link,
> etc) but gets a file handle for a different sort of object, it must
> return an error. The actual error varies among version in no-trivial
> ways.
>
> For v2 and v3 there are ISDIR and NOTDIR errors, and for any else, only
> INVAL is suitable.
>
> For v4.0 there is also NFS4ERR_SYMLINK which should be used if a SYMLINK
> was found when not expected. This take precedence over NOTDIR.
>
> For v4.1+ there is also NFS4ERR_WRONG_TYPE which should be used in
> preference to EINVAL when none of the specific error codes apply.
>
> When nfsd_mode_check() finds a symlink where it expect a directory it
> needs to return an error code that can be converted to NOTDIR for v2 or
> v3 but will be SYMLINK for v4. It must be different from the error
> code returns when it finds a symlink but expects a regular file - that
> must be converted to EINVAL or SYMLINK.
>
> So we introduce an internal error code nfserr_symlink_not_dir which each
> version converts as appropriate.
>
> We also allow nfserr_wrong_type to be returned by
> nfsd_check_obj_is_reg() in nfsv4 code) and nfsd_mode_check(). This a
> behavioural change as nfsd_check_obj_is_reg() would previously return
> nfserr_symiink for non-directory objects that aren't regular files. Now
> it will return nfserr_wrong_type for objects that aren't regular,
> directory, symlink (so char-special, block-special, sockets), which is
> mapped to nfserr_inval for NFSv4.0. This should not be a problem as the
> behaviour is supported by RFCs.
>
> As a result of these changes, nfsd_mode_check() doesn't need an rqstp
> arg any more.
>
> Signed-off-by: NeilBrown <neilb@suse.de>
> ---
> fs/nfsd/nfs3proc.c | 8 ++++++++
> fs/nfsd/nfs4proc.c | 24 ++++++++++++++++--------
> fs/nfsd/nfsd.h | 5 +++++
> fs/nfsd/nfsfh.c | 16 +++++++---------
> fs/nfsd/nfsproc.c | 7 +++++++
> 5 files changed, 43 insertions(+), 17 deletions(-)
>
> diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
> index 31bd9bcf8687..ac7ee24415a3 100644
> --- a/fs/nfsd/nfs3proc.c
> +++ b/fs/nfsd/nfs3proc.c
> @@ -38,6 +38,14 @@ static __be32 map_status(__be32 status)
> case nfserr_file_open:
> status = nfserr_acces;
> break;
> +
> + case nfserr_symlink_not_dir:
> + status = nfserr_notdir;
> + break;
> + case nfserr_symlink:
> + case nfserr_wrong_type:
> + status = nfserr_inval;
> + break;
> }
> return status;
> }
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index 46bd20fe5c0f..cc715438e77a 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -166,14 +166,9 @@ static __be32 nfsd_check_obj_isreg(struct svc_fh *fh)
> return nfs_ok;
> if (S_ISDIR(mode))
> return nfserr_isdir;
> - /*
> - * Using err_symlink as our catch-all case may look odd; but
> - * there's no other obvious error for this case in 4.0, and we
> - * happen to know that it will cause the linux v4 client to do
> - * the right thing on attempts to open something other than a
> - * regular file.
> - */
> - return nfserr_symlink;
> + if (S_ISLNK(mode))
> + return nfserr_symlink;
> + return nfserr_wrong_type;
> }
>
> static void nfsd4_set_open_owner_reply_cache(struct nfsd4_compound_state *cstate, struct nfsd4_open *open, struct svc_fh *resfh)
> @@ -184,6 +179,17 @@ static void nfsd4_set_open_owner_reply_cache(struct nfsd4_compound_state *cstate
> &resfh->fh_handle);
> }
>
> +static __be32 map_status(__be32 status, int minor)
> +{
> + if (status == nfserr_wrong_type &&
> + minor == 0)
> + /* RFC5661 - 15.1.2.9 */
> + status = nfserr_inval;
> +
> + if (status == nfserr_symlink_not_dir)
> + status = nfserr_symlink;
> + return status;
> +}
> static inline bool nfsd4_create_is_exclusive(int createmode)
> {
> return createmode == NFS4_CREATE_EXCLUSIVE ||
> @@ -2798,6 +2804,8 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
> nfsd4_encode_replay(resp->xdr, op);
> status = op->status = op->replay->rp_status;
> } else {
> + op->status = map_status(op->status,
> + cstate->minorversion);
> nfsd4_encode_operation(resp, op);
> status = op->status;
> }
> diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
> index 593c34fd325a..3c8c8da063b0 100644
> --- a/fs/nfsd/nfsd.h
> +++ b/fs/nfsd/nfsd.h
> @@ -349,6 +349,11 @@ enum {
> NFSERR_REPLAY_CACHE,
> #define nfserr_replay_cache cpu_to_be32(NFSERR_REPLAY_CACHE)
>
> +/* symlink found where dir expected - handled differently to
> + * other symlink found errors by NFSv3.
> + */
> + NFSERR_SYMLINK_NOT_DIR,
> +#define nfserr_symlink_not_dir cpu_to_be32(NFSERR_SYMLINK_NOT_DIR)
> };
>
> /* Check for dir entries '.' and '..' */
> diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
> index 0130103833e5..8cd70f93827c 100644
> --- a/fs/nfsd/nfsfh.c
> +++ b/fs/nfsd/nfsfh.c
> @@ -62,8 +62,7 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry)
> * the write call).
> */
> static inline __be32
> -nfsd_mode_check(struct svc_rqst *rqstp, struct dentry *dentry,
> - umode_t requested)
> +nfsd_mode_check(struct dentry *dentry, umode_t requested)
> {
> umode_t mode = d_inode(dentry)->i_mode & S_IFMT;
>
> @@ -76,17 +75,16 @@ nfsd_mode_check(struct svc_rqst *rqstp, struct dentry *dentry,
> }
> return nfs_ok;
> }
> - /*
> - * v4 has an error more specific than err_notdir which we should
> - * return in preference to err_notdir:
> - */
> - if (rqstp->rq_vers == 4 && mode == S_IFLNK)
> + if (mode == S_IFLNK) {
> + if (requested == S_IFDIR)
> + return nfserr_symlink_not_dir;
> return nfserr_symlink;
> + }
> if (requested == S_IFDIR)
> return nfserr_notdir;
> if (mode == S_IFDIR)
> return nfserr_isdir;
> - return nfserr_inval;
> + return nfserr_wrong_type;
> }
>
> static bool nfsd_originating_port_ok(struct svc_rqst *rqstp, int flags)
> @@ -362,7 +360,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
> if (error)
> goto out;
>
> - error = nfsd_mode_check(rqstp, dentry, type);
> + error = nfsd_mode_check(dentry, type);
> if (error)
> goto out;
>
> diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
> index cb7099c6dc78..3d65ab558091 100644
> --- a/fs/nfsd/nfsproc.c
> +++ b/fs/nfsd/nfsproc.c
> @@ -25,6 +25,13 @@ static __be32 map_status(__be32 status)
> case nfserr_file_open:
> status = nfserr_acces;
> break;
> + case nfserr_symlink_not_dir:
> + status = nfserr_notdir;
> + break;
> + case nfserr_symlink:
> + case nfserr_wrong_type:
> + status = nfserr_inval;
> + break;
> }
> return status;
> }
Hi Neil,
I'm seeing a set of failures in pynfs with this patch (json results
attached). I haven't looked in detail yet, but we should probably drop
this one for now.
--
Jeff Layton <jlayton@kernel.org>
[-- Attachment #2: 6.11.0-rc2-g1c134bcd2ef0-v4.0.json --]
[-- Type: application/json, Size: 122987 bytes --]
next prev parent reply other threads:[~2024-08-08 10:37 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-07-29 1:47 [PATCH 0/3] nfsd: move error code mapping to per-version code NeilBrown
2024-07-29 1:47 ` [PATCH 1/3] nfsd: Move error code mapping to per-version proc code NeilBrown
2024-07-29 15:04 ` Christoph Hellwig
2024-07-29 1:47 ` [PATCH 2/3] nfsd: be more systematic about selecting error codes for internal use NeilBrown
2024-07-29 15:05 ` Christoph Hellwig
2024-07-29 1:47 ` [PATCH 3/3] nfsd: move error choice for incorrect object types to version-specific code NeilBrown
2024-07-29 15:06 ` Christoph Hellwig
2024-08-08 10:37 ` Jeff Layton [this message]
2024-08-08 11:40 ` NeilBrown
2024-08-08 12:01 ` Jeff Layton
2024-08-08 22:00 ` NeilBrown
2024-08-09 12:34 ` Jeff Layton
2024-07-29 12:36 ` [PATCH 0/3] nfsd: move error code mapping to per-version code Jeff Layton
2024-07-29 15:16 ` 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=aab4166ae13a4453ea18644da6cc260e41f1b49f.camel@kernel.org \
--to=jlayton@kernel.org \
--cc=Dai.Ngo@oracle.com \
--cc=chuck.lever@oracle.com \
--cc=kolga@netapp.com \
--cc=linux-nfs@vger.kernel.org \
--cc=neilb@suse.de \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox