[PATCH v4 2/8] NFSD: Count the delegations held by each client
Chuck Lever <[email protected]>
| Newsgroups | gmane.linux.nfs |
|---|---|
| Message-ID | <[email protected]> |
struct nfs4_client records the delegations it holds on cl_delegations but keeps no count of them. deleg_reaper() walks nn->client_lru under nn->client_lock, but cl_delegations is serialized by nn->deleg_lock, which nests outside nn->client_lock. A caller there cannot take nn->deleg_lock to count the list. The cost tells against the walk as well: an O(n) count per client, on a pass that already visits every client. Add cl_deleg_count, maintained at the two sites that mutate cl_delegations. Both hold nn->deleg_lock, so the counter is already serialized against itself and needs no atomic of its own. The decrement sits below the delegation_hashed() test, next to the list_del_init it pairs with, so it runs only when the delegation really leaves the list. A reader that holds only nn->client_lock is not synchronized against either update site, so it can see a count that does not match the list. Such a reader marks the access with data_race() and may not depend on the value for correctness. No functional change. Signed-off-by: Chuck Lever <[email protected]> Reviewed-by: Jeff Layton <[email protected]> --- fs/nfsd/nfs4state.c | 2 ++ fs/nfsd/state.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 9a3574b853ad..fbe073ee5225 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1527,6 +1527,7 @@ hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) dp->dl_stid.sc_type = SC_TYPE_DELEG; list_add(&dp->dl_perfile, &fp->fi_delegations); list_add(&dp->dl_perclnt, &clp->cl_delegations); + clp->cl_deleg_count++; return 0; } @@ -1558,6 +1559,7 @@ unhash_delegation_locked(struct nfs4_delegation *dp, unsigned short statusmask) ++dp->dl_time; spin_lock(&fp->fi_lock); list_del_init(&dp->dl_perclnt); + dp->dl_stid.sc_client->cl_deleg_count--; list_del_init(&dp->dl_recall_lru); list_del_init(&dp->dl_perfile); spin_unlock(&fp->fi_lock); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index c65b604e29f1..cd9294f024bb 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -633,6 +633,8 @@ struct nfs4_client { unsigned int cl_state; atomic_t cl_delegs_in_recall; + /* Length of cl_delegations, updated under nn->deleg_lock */ + unsigned int cl_deleg_count; struct nfsd4_cb_recall_any *cl_ra; time64_t cl_ra_time; -- 2.54.0