Re: [PATCH v2 04/10] nfsd: Distinguish between required and optional NFSv3 post-op attributes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> On Dec 20, 2021, at 1:38 PM, Trond Myklebust <trondmy@xxxxxxxxxxxxxxx> wrote:
> 
> On Mon, 2021-12-20 at 16:02 +0000, Chuck Lever III wrote:
>> 
>> 
>>> On Dec 19, 2021, at 4:09 PM, Trond Myklebust
>>> <trondmy@xxxxxxxxxxxxxxx> wrote:
>>> 
>>> On Sun, 2021-12-19 at 20:10 +0000, Chuck Lever III wrote:
>>>> 
>>>> 
>>>>> On Dec 18, 2021, at 8:37 PM, trondmy@xxxxxxxxxx wrote:
>>>>> 
>>>>> From: Trond Myklebust <trond.myklebust@xxxxxxxxxxxxxxx>
>>>>> 
>>>>> The fhp->fh_no_wcc flag is automatically set in
>>>>> nfsd_set_fh_dentry()
>>>>> when the EXPORT_OP_NOWCC flag is set. In
>>>>> svcxdr_encode_post_op_attr(),
>>>>> this then causes nfsd to skip returning the post-op attributes.
>>>>> 
>>>>> The problem is that some of these post-op attributes are not
>>>>> really
>>>>> optional. In particular, we do want LOOKUP to always return
>>>>> post-op
>>>>> attributes for the file that is being looked up.
>>>>> 
>>>>> The solution is therefore to explicitly label the attributes
>>>>> that
>>>>> we can
>>>>> safely opt out from, and only apply the 'fhp->fh_no_wcc' test
>>>>> in
>>>>> that
>>>>> case.
>>>>> 
>>>>> Signed-off-by: Trond Myklebust
>>>>> <trond.myklebust@xxxxxxxxxxxxxxx>
>>>>> Signed-off-by: Lance Shelton <lance.shelton@xxxxxxxxxxxxxxx>
>>>>> Signed-off-by: Trond Myklebust
>>>>> <trond.myklebust@xxxxxxxxxxxxxxx>
>>>>> ---
>>>>> fs/nfsd/nfs3xdr.c | 77 +++++++++++++++++++++++++++++++---------
>>>>> ----
>>>>> ---
>>>>> 1 file changed, 51 insertions(+), 26 deletions(-)
>>>>> 
>>>>> diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
>>>>> index c3ac1b6aa3aa..6adfc40722fa 100644
>>>>> --- a/fs/nfsd/nfs3xdr.c
>>>>> +++ b/fs/nfsd/nfs3xdr.c
>>>>> @@ -415,19 +415,9 @@ svcxdr_encode_pre_op_attr(struct
>>>>> xdr_stream
>>>>> *xdr, const struct svc_fh *fhp)
>>>>>         return svcxdr_encode_wcc_attr(xdr, fhp);
>>>>> }
>>>>> 
>>>>> -/**
>>>>> - * svcxdr_encode_post_op_attr - Encode NFSv3 post-op
>>>>> attributes
>>>>> - * @rqstp: Context of a completed RPC transaction
>>>>> - * @xdr: XDR stream
>>>>> - * @fhp: File handle to encode
>>>>> - *
>>>>> - * Return values:
>>>>> - *   %false: Send buffer space was exhausted
>>>>> - *   %true: Success
>>>>> - */
>>>>> -bool
>>>>> -svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct
>>>>> xdr_stream *xdr,
>>>>> -                          const struct svc_fh *fhp)
>>>>> +static bool
>>>>> +__svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct
>>>>> xdr_stream *xdr,
>>>>> +                            const struct svc_fh *fhp, bool
>>>>> force)
>>>>> {
>>>>>         struct dentry *dentry = fhp->fh_dentry;
>>>>>         struct kstat stat;
>>>>> @@ -437,7 +427,7 @@ svcxdr_encode_post_op_attr(struct svc_rqst
>>>>> *rqstp, struct xdr_stream *xdr,
>>>>>          * stale file handle. In this case, no attributes are
>>>>>          * returned.
>>>>>          */
>>>>> -       if (fhp->fh_no_wcc || !dentry ||
>>>>> !d_really_is_positive(dentry))
>>>>> +       if (!force || !dentry || !d_really_is_positive(dentry))
>>>>>                 goto no_post_op_attrs;
>>>>>         if (fh_getattr(fhp, &stat) != nfs_ok)
>>>>>                 goto no_post_op_attrs;
>>>>> @@ -454,6 +444,31 @@ svcxdr_encode_post_op_attr(struct svc_rqst
>>>>> *rqstp, struct xdr_stream *xdr,
>>>>>         return xdr_stream_encode_item_absent(xdr) > 0;
>>>>> }
>>>>> 
>>>>> +/**
>>>>> + * svcxdr_encode_post_op_attr - Encode NFSv3 post-op
>>>>> attributes
>>>>> + * @rqstp: Context of a completed RPC transaction
>>>>> + * @xdr: XDR stream
>>>>> + * @fhp: File handle to encode
>>>>> + *
>>>>> + * Return values:
>>>>> + *   %false: Send buffer space was exhausted
>>>>> + *   %true: Success
>>>>> + */
>>>>> +bool
>>>>> +svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct
>>>>> xdr_stream *xdr,
>>>>> +                          const struct svc_fh *fhp)
>>>>> +{
>>>>> +       return __svcxdr_encode_post_op_attr(rqstp, xdr, fhp,
>>>>> true);
>>>>> +}
>>>>> +
>>>>> +static bool
>>>>> +svcxdr_encode_post_op_attr_opportunistic(struct svc_rqst
>>>>> *rqstp,
>>>>> +                                        struct xdr_stream
>>>>> *xdr,
>>>>> +                                        const struct svc_fh
>>>>> *fhp)
>>>>> +{
>>>>> +       return __svcxdr_encode_post_op_attr(rqstp, xdr, fhp,
>>>>> !fhp-
>>>>>> fh_no_wcc);
>>>>> +}
>>>>> +
>>>> 
>>>> Thanks for splitting this out: the "why" is much clearer.
>>>> 
>>>> Wouldn't it be simpler to explicitly set fh_no_wcc to false
>>>> in each of the cases where you want to ensure the server
>>>> emits WCC? And perhaps that should be done in nfs3proc.c
>>>> instead of in nfs3xdr.c.
>>>> 
>>> 
>>> It can't be done in nfs3proc.c, and toggling the value of fh_no_wcc
>>> is
>>> a lot more cumbersome than this approach.
>>> 
>>> The current code is broken for NFSv3 exports because it is unable
>>> to
>>> distinguish between what is and isn't mandatory to return for in
>>> the
>>> same NFS operation. That's the problem this patch fixes.
>> 
>> That suggests that a Fixes: tag is appropriate. Can you recommend
>> one?
>> 
>> 
>>> LOOKUP has to return the attributes for the object being looked up
>>> in
>>> order to be useful. If the attributes are not up to date then we
>>> should
>>> ask the NFS client that is being re-exported to go to the server to
>>> revalidate its attributes.
>>> The same is not true of the directory post-op attributes. LOOKUP
>>> does
>>> not even change the contents of the directory, and so while it is
>>> beneficial to have the NFS client return those attributes if they
>>> are
>>> up to date, forcing it to go to the server to retrieve them is less
>>> than optimal for system performance.
>> 
>> I get all that, but I don't see how this is cumbersome at all:
>> 
>>  82 static __be32
>>  83 nfsd3_proc_lookup(struct svc_rqst *rqstp)
>>  84 {
>> ...
>>  96         resp->status = nfsd_lookup(rqstp, &resp->dirfh,
>>  97                                    argp->name, argp->len,
>>  98                                    &resp->fh);
>>     +       resp->fh.fh_no_wcc = false;
>>  99         return rpc_success;
>> 100 }
>> 
>> Then in 5/10, pass !fhp->fh_no_wcc to nfsd_getattr().
> 
> That's not equivalent. That will force the NFS client to retrieve the
> lookup object attributes AND the directory attributes.

Does it? Your patch does this:

 418 static bool
 419 __svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 420                              const struct svc_fh *fhp, bool force)
 421 {
...
 436         if (nfsd_getattr(&path, &stat, force) != nfs_ok)
 437                 goto no_post_op_attrs;

...

 461 bool
 462 svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 463                            const struct svc_fh *fhp)
 464 {
 465         return __svcxdr_encode_post_op_attr(rqstp, xdr, fhp, true);
 466 }
 467 
 468 static bool
 469 svcxdr_encode_post_op_attr_opportunistic(struct svc_rqst *rqstp,
 470                                          struct xdr_stream *xdr,
 471                                          const struct svc_fh *fhp)
 472 {
 473         return __svcxdr_encode_post_op_attr(rqstp, xdr, fhp, !fhp->fh_no_wcc);
 474 }

...

 863 bool
 864 nfs3svc_encode_lookupres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 865 {
...
 871         case nfs_ok:
 872                 if (!svcxdr_encode_nfs_fh3(xdr, &resp->fh))
 873                         return false;
 874                 if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
 875                         return false;
 876                 if (!svcxdr_encode_post_op_attr_opportunistic(rqstp, xdr,
 877                                                               &resp->dirfh))
 878                         return false;
 879                 break;

So for resp->fh, this is equivalent to resp->fh.fh_no_wcc = false
and for resp->dirfh, this is equivalent to passing in
resp->dirfh.fh_no_wcc unchanged.

I don't see how that's different from what my suggestion does --
it forces WCC for the looked-up object, and leaves WCC for the
parent directory optional.


--
Chuck Lever







[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux