[PATCH v3 5/8] NFSD: Count delegations per network namespace
Chuck Lever <[email protected]>
| Newsgroups | gmane.linux.nfs |
|---|---|
| Message-ID | <[email protected]> |
The state shrinker is allocated per network namespace, but nfsd4_state_shrinker_count() reports num_delegations, which counts the delegations held by the whole host. Every namespace therefore reports every delegation on the server. Reclaim sees the population multiplied by the number of namespaces running NFSD. A namespace holding no delegations of its own still reports a nonzero count and queues its reaper, which then finds nothing to recall. Count the delegations in each namespace and report that instead. num_delegations stays for the admission check in __alloc_init_deleg() and the ceiling check in nfs4_laundromat(). Both compare against max_delegations, which is sized from host memory and so remains a host-wide limit. Signed-off-by: Chuck Lever <[email protected]> --- fs/nfsd/netns.h | 2 ++ fs/nfsd/nfs4state.c | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h index 71eebfea020d..bb62d19430bc 100644 --- a/fs/nfsd/netns.h +++ b/fs/nfsd/netns.h @@ -238,6 +238,8 @@ struct nfsd_net { int nfs4_max_clients; atomic_t nfsd_courtesy_clients; + /* per-namespace; num_delegations in nfs4state.c is host-wide */ + atomic_long_t nfsd_delegations; struct shrinker *nfsd_client_shrinker; struct work_struct nfsd_shrinker_work; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 7d8d7df9953b..f818e8a60099 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1161,6 +1161,7 @@ static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) */ static void nfs4_free_deleg(struct nfs4_stid *stid) { + struct nfsd_net *nn = net_generic(stid->sc_client->net, nfsd_net_id); struct nfs4_delegation *dp = delegstateid(stid); WARN_ON_ONCE(!list_empty(&stid->sc_cp_list)); @@ -1171,6 +1172,7 @@ static void nfs4_free_deleg(struct nfs4_stid *stid) nfsd41_cb_destroy_referring_call_list(&dp->dl_recall); kmem_cache_free(deleg_slab, stid); atomic_long_dec(&num_delegations); + atomic_long_dec(&nn->nfsd_delegations); } /* @@ -1255,6 +1257,7 @@ __alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate, u32 dl_type, void (*sc_free)(struct nfs4_stid *)) { + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); struct nfs4_delegation *dp; struct nfs4_stid *stid; long n; @@ -1263,6 +1266,7 @@ __alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, return NULL; n = atomic_long_inc_return(&num_delegations); + atomic_long_inc(&nn->nfsd_delegations); if (n < 0 || n > max_delegations) goto out_dec; @@ -1295,6 +1299,7 @@ __alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, return dp; out_dec: atomic_long_dec(&num_delegations); + atomic_long_dec(&nn->nfsd_delegations); return NULL; } @@ -5566,7 +5571,7 @@ nfsd4_state_shrinker_count(struct shrinker *shrink, struct shrink_control *sc) count = atomic_read(&nn->nfsd_courtesy_clients); if (!count) - count = atomic_long_read(&num_delegations); + count = atomic_long_read(&nn->nfsd_delegations); if (count) queue_work(laundry_wq, &nn->nfsd_shrinker_work); return (unsigned long)count; -- 2.54.0