Re: [PATCH 1/6] nfsd: don't take nfsd4_copy ref for OP_OFFLOAD_STATUS

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

 



On Wed, Jan 18, 2023 at 1:53 PM Chuck Lever III <chuck.lever@xxxxxxxxxx> wrote:
>
>
>
> > On Jan 18, 2023, at 1:08 PM, Olga Kornievskaia <aglo@xxxxxxxxx> wrote:
> >
> > On Wed, Jan 18, 2023 at 12:49 PM Jeff Layton <jlayton@xxxxxxxxxx> wrote:
> >>
> >> On Wed, 2023-01-18 at 12:43 -0500, Olga Kornievskaia wrote:
> >>> On Wed, Jan 18, 2023 at 12:35 PM Jeff Layton <jlayton@xxxxxxxxxx> wrote:
> >>>>
> >>>> We're not doing any blocking operations for OP_OFFLOAD_STATUS, so taking
> >>>> and putting a reference is a waste of effort. Take the client lock,
> >>>> search for the copy and fetch the wr_bytes_written field and return.
> >>>>
> >>>> Also, make find_async_copy a static function.
> >>>>
> >>>> Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>
> >>>> ---
> >>>> fs/nfsd/nfs4proc.c | 35 ++++++++++++++++++++++++-----------
> >>>> fs/nfsd/state.h    |  2 --
> >>>> 2 files changed, 24 insertions(+), 13 deletions(-)
> >>>>
> >>>> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> >>>> index 62b9d6c1b18b..731c2b22f163 100644
> >>>> --- a/fs/nfsd/nfs4proc.c
> >>>> +++ b/fs/nfsd/nfs4proc.c
> >>>> @@ -1823,23 +1823,34 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> >>>>        goto out;
> >>>> }
> >>>>
> >>>> -struct nfsd4_copy *
> >>>> -find_async_copy(struct nfs4_client *clp, stateid_t *stateid)
> >>>> +static struct nfsd4_copy *
> >>>> +find_async_copy_locked(struct nfs4_client *clp, stateid_t *stateid)
> >>>> {
> >>>>        struct nfsd4_copy *copy;
> >>>>
> >>>> -       spin_lock(&clp->async_lock);
> >>>> +       lockdep_assert_held(&clp->async_lock);
> >>>> +
> >>>>        list_for_each_entry(copy, &clp->async_copies, copies) {
> >>>>                if (memcmp(&copy->cp_stateid.cs_stid, stateid, NFS4_STATEID_SIZE))
> >>>>                        continue;
> >>>> -               refcount_inc(&copy->refcount);
> >>>
> >>> If we don't take a refcount on the copy, this copy could be removed
> >>> between the time we found it in the list of copies and when we then
> >>> look inside to check the amount written so far. This would lead to a
> >>> null (or bad) pointer dereference?
> >>>
> >>
> >> No. The existing code finds this object, takes a reference to it,
> >> fetches a single integer out of it and then puts the reference. This
> >> patch just has it avoid the reference altogether and fetch the value
> >> while we still hold the spinlock. This should be completely safe
> >> (assuming the locking around the existing list handling is correct,
> >> which it does seem to be).
> >
> > Thank you for the explanation. I see it now.
>
> May I add Reviewed-by: Olga Kornievskaia <kolga@xxxxxxxxxx> ?

Of course.

> >>>> -               spin_unlock(&clp->async_lock);
> >>>>                return copy;
> >>>>        }
> >>>> -       spin_unlock(&clp->async_lock);
> >>>>        return NULL;
> >>>> }
> >>>>
> >>>> +static struct nfsd4_copy *
> >>>> +find_async_copy(struct nfs4_client *clp, stateid_t *stateid)
> >>>> +{
> >>>> +       struct nfsd4_copy *copy;
> >>>> +
> >>>> +       spin_lock(&clp->async_lock);
> >>>> +       copy = find_async_copy_locked(clp, stateid);
> >>>> +       if (copy)
> >>>> +               refcount_inc(&copy->refcount);
> >>>> +       spin_unlock(&clp->async_lock);
> >>>> +       return copy;
> >>>> +}
> >>>> +
> >>>> static __be32
> >>>> nfsd4_offload_cancel(struct svc_rqst *rqstp,
> >>>>                     struct nfsd4_compound_state *cstate,
> >>>> @@ -1924,22 +1935,24 @@ nfsd4_fallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> >>>>        nfsd_file_put(nf);
> >>>>        return status;
> >>>> }
> >>>> +
> >>>> static __be32
> >>>> nfsd4_offload_status(struct svc_rqst *rqstp,
> >>>>                     struct nfsd4_compound_state *cstate,
> >>>>                     union nfsd4_op_u *u)
> >>>> {
> >>>>        struct nfsd4_offload_status *os = &u->offload_status;
> >>>> -       __be32 status = 0;
> >>>> +       __be32 status = nfs_ok;
> >>>>        struct nfsd4_copy *copy;
> >>>>        struct nfs4_client *clp = cstate->clp;
> >>>>
> >>>> -       copy = find_async_copy(clp, &os->stateid);
> >>>> -       if (copy) {
> >>>> +       spin_lock(&clp->async_lock);
> >>>> +       copy = find_async_copy_locked(clp, &os->stateid);
> >>>> +       if (copy)
> >>>>                os->count = copy->cp_res.wr_bytes_written;
> >>>> -               nfs4_put_copy(copy);
> >>>> -       } else
> >>>> +       else
> >>>>                status = nfserr_bad_stateid;
> >>>> +       spin_unlock(&clp->async_lock);
> >>>>
> >>>>        return status;
> >>>> }
> >>>> diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
> >>>> index e94634d30591..d49d3060ed4f 100644
> >>>> --- a/fs/nfsd/state.h
> >>>> +++ b/fs/nfsd/state.h
> >>>> @@ -705,8 +705,6 @@ extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name
> >>>> extern bool nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn);
> >>>>
> >>>> void put_nfs4_file(struct nfs4_file *fi);
> >>>> -extern struct nfsd4_copy *
> >>>> -find_async_copy(struct nfs4_client *clp, stateid_t *staetid);
> >>>> extern void nfs4_put_cpntf_state(struct nfsd_net *nn,
> >>>>                                 struct nfs4_cpntf_state *cps);
> >>>> extern __be32 manage_cpntf_state(struct nfsd_net *nn, stateid_t *st,
> >>>> --
> >>>> 2.39.0
> >>>>
> >>
> >> --
> >> Jeff Layton <jlayton@xxxxxxxxxx>
>
> --
> 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