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. > > > > > - 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>