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(©->cp_stateid.cs_stid, stateid, NFS4_STATEID_SIZE)) > >>>> continue; > >>>> - refcount_inc(©->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(©->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 > > >