Re: [PATCH] nfsd: remove unsafe BUG_ON from set_change_info

From: Jeff Layton
Date: Thu Jul 20 2023 - 11:34:05 EST


On Thu, 2023-07-20 at 15:15 +0000, Chuck Lever III wrote:
>
> > On Jul 20, 2023, at 10:59 AM, Jeff Layton <jlayton@xxxxxxxxxx> wrote:
> >
> > At one time, nfsd would scrape inode information directly out of struct
> > inode in order to populate the change_info4. At that time, the BUG_ON in
> > set_change_info made some sense, since having it unset meant a coding
> > error.
> >
> > More recently, it calls vfs_getattr to get this information, which can
> > fail. If that fails, fh_pre_saved can end up not being set. While this
> > situation is unfortunate, we don't need to crash the box.
>
> I'm always happy to get rid of a BUG_ON(). But I'm not sure even
> a warning is necessary in this case. It's not likely that it's
> a software bug or something that the server administrator can
> do something about.
>
> Can you elaborate on why the vfs_getattr() might fail? Eg, how
> was it failing in 2223560 ?
>

I'm fine with dropping the WARN_ON. You are correct that there is
probably little the admin can do about it.

vfs_getattr can fail for all sorts of reasons. It really depends on the
underlying filesystem. In 2223560, I don't know for sure, but just prior
to the oops, there were these messages in the log:

[51935.482019] XFS (vda3): Filesystem has been shut down due to log error (0x2).
[51935.482020] XFS (vda3): Please unmount the filesystem and rectify the problem(s).
[51935.482550] vda3: writeback error on inode 25320400, offset 2097152, sector 58684120

My assumption was that the fs being shut down caused some VFS operations
to start returning errors (including getattr) and that is why
fh_pre_saved ultimately didn't get set.

>
> > Move set_change_info to nfs4proc.c since all of the callers are there.
> > Revise the condition for setting "atomic" to also check for
> > fh_pre_saved. Drop the BUG_ON and make it a WARN_ON, and just have it
> > zero out both change_attr4s when this occurs.
> >
> > Link: https://bugzilla.redhat.com/show_bug.cgi?id=2223560
> > Reported-by: Boyang Xue <bxue@xxxxxxxxxx>
>
> checkpatch now wants
>
> Reported-by:
> Closes:
>
> in that order.
>


Mmmmkay. So I assume the URL should go in the Closes: field then?

I'll take out the WARN_ON_ONCE and resend, once others have had a chance
to comment.

Thanks!

>
> > Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>
> > ---
> > fs/nfsd/nfs4proc.c | 30 ++++++++++++++++++++++++++++++
> > fs/nfsd/xdr4.h | 11 -----------
> > 2 files changed, 30 insertions(+), 11 deletions(-)
> >
> > diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> > index d8e7a533f9d2..e6f406f27821 100644
> > --- a/fs/nfsd/nfs4proc.c
> > +++ b/fs/nfsd/nfs4proc.c
> > @@ -380,6 +380,36 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
> > return status;
> > }
> >
> > +/**
> > + * set_change_info - set up the change_info4 for a reply
> > + * @cinfo: pointer to nfsd4_change_info to be populated
> > + * @fhp: pointer to svc_fh to use as source
> > + *
> > + * Many operations in NFSv4 require change_info4 in the reply. This function
> > + * populates that from the info that we (should!) have already collected. In
> > + * the event that we didn't get any pre-attrs, throw a warning and just
> > + * zero out both change_attr4 fields.
> > + */
> > +static void
> > +set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp)
> > +{
> > + cinfo->atomic = (u32)(fhp->fh_pre_saved && fhp->fh_post_saved && !fhp->fh_no_atomic_attr);
> > +
> > + /*
> > + * In the event that we couldn't fetch attributes from the
> > + * server for some reason, just zero out the before and after
>
> "From the server"? Is it only likely to fail if the exported
> filesystem is an NFS mount? Or did you mean "from the filesystem" ?
>
>
> > + * change values, after throwing a warning.
> > + */
> > + if (WARN_ON_ONCE(!fhp->fh_pre_saved)) {
>
> Maybe you should clear ->atomic as well in this case.
>
>
> > + cinfo->before_change = 0;
> > + cinfo->after_change = 0;
> > + return;
> > + }
> > +
> > + cinfo->before_change = fhp->fh_pre_change;
> > + cinfo->after_change = fhp->fh_post_change;
> > +}
> > +
> > static __be32
> > do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open *open, struct svc_fh **resfh)
> > {
> > diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
> > index b2931fdf53be..9e67f63c5f4d 100644
> > --- a/fs/nfsd/xdr4.h
> > +++ b/fs/nfsd/xdr4.h
> > @@ -775,17 +775,6 @@ void warn_on_nonidempotent_op(struct nfsd4_op *op);
> >
> > #define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs)
> >
> > -static inline void
> > -set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp)
> > -{
> > - BUG_ON(!fhp->fh_pre_saved);
> > - cinfo->atomic = (u32)(fhp->fh_post_saved && !fhp->fh_no_atomic_attr);
> > -
> > - cinfo->before_change = fhp->fh_pre_change;
> > - cinfo->after_change = fhp->fh_post_change;
> > -}
> > -
> > -
> > bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp);
> > bool nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
> > bool nfs4svc_encode_compoundres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
> >
> > ---
> > base-commit: 070f391ca4d48e1750ee6108eb44f751a9e9448e
> > change-id: 20230720-bz2223560-9c4690a8217b
> >
> > Best regards,
> > --
> > Jeff Layton <jlayton@xxxxxxxxxx>
> >
>
> --
> Chuck Lever
>
>

--
Jeff Layton <jlayton@xxxxxxxxxx>