On Mon, 2025-07-14 at 13:16 +0200, Christoph Hellwig wrote: > The active delegation watermark was added to avoid overloading servers. > Track the active delegation per-server instead of globally so that clients > talking to multiple servers aren't limited by the global limit. > > Signed-off-by: Christoph Hellwig <hch@xxxxxx> > --- > fs/nfs/client.c | 1 + > fs/nfs/delegation.c | 35 +++++++++++++++++++---------------- > include/linux/nfs_fs_sb.h | 1 + > 3 files changed, 21 insertions(+), 16 deletions(-) > > diff --git a/fs/nfs/client.c b/fs/nfs/client.c > index 1a55debab6e5..f55188928f67 100644 > --- a/fs/nfs/client.c > +++ b/fs/nfs/client.c > @@ -1017,6 +1017,7 @@ struct nfs_server *nfs_alloc_server(void) > INIT_LIST_HEAD(&server->ss_src_copies); > > atomic_set(&server->active, 0); > + atomic_long_set(&server->nr_active_delegations, 0); > > server->io_stats = nfs_alloc_iostats(); > if (!server->io_stats) { > diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c > index d036796dbe69..621b635d1c56 100644 > --- a/fs/nfs/delegation.c > +++ b/fs/nfs/delegation.c > @@ -27,7 +27,6 @@ > > #define NFS_DEFAULT_DELEGATION_WATERMARK (15000U) > > -static atomic_long_t nfs_active_delegations; > static unsigned nfs_delegation_watermark = NFS_DEFAULT_DELEGATION_WATERMARK; > module_param_named(delegation_watermark, nfs_delegation_watermark, uint, 0644); > > @@ -38,11 +37,12 @@ static void __nfs_free_delegation(struct nfs_delegation *delegation) > kfree_rcu(delegation, rcu); > } > > -static void nfs_mark_delegation_revoked(struct nfs_delegation *delegation) > +static void nfs_mark_delegation_revoked(struct nfs_server *server, > + struct nfs_delegation *delegation) > { > if (!test_and_set_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) { > delegation->stateid.type = NFS4_INVALID_STATEID_TYPE; > - atomic_long_dec(&nfs_active_delegations); > + atomic_long_dec(&server->nr_active_delegations); > if (!test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) > nfs_clear_verifier_delegated(delegation->inode); > } > @@ -60,9 +60,10 @@ static void nfs_put_delegation(struct nfs_delegation *delegation) > __nfs_free_delegation(delegation); > } > > -static void nfs_free_delegation(struct nfs_delegation *delegation) > +static void nfs_free_delegation(struct nfs_server *server, > + struct nfs_delegation *delegation) > { > - nfs_mark_delegation_revoked(delegation); > + nfs_mark_delegation_revoked(server, delegation); > nfs_put_delegation(delegation); > } > > @@ -261,7 +262,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, const struct cred *cred, > } > clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags); > if (test_and_clear_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) > - atomic_long_inc(&nfs_active_delegations); > + atomic_long_inc(&NFS_SERVER(inode)->nr_active_delegations); > spin_unlock(&delegation->lock); > rcu_read_unlock(); > put_cred(oldcred); > @@ -413,7 +414,8 @@ nfs_update_delegation_cred(struct nfs_delegation *delegation, > } > > static void > -nfs_update_inplace_delegation(struct nfs_delegation *delegation, > +nfs_update_inplace_delegation(struct nfs_server *server, > + struct nfs_delegation *delegation, > const struct nfs_delegation *update) > { > if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid)) { > @@ -426,7 +428,7 @@ nfs_update_inplace_delegation(struct nfs_delegation *delegation, > nfs_update_delegation_cred(delegation, update->cred); > /* smp_mb__before_atomic() is implicit due to xchg() */ > clear_bit(NFS_DELEGATION_REVOKED, &delegation->flags); > - atomic_long_inc(&nfs_active_delegations); > + atomic_long_inc(&server->nr_active_delegations); > } > } > } > @@ -481,7 +483,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred, > if (nfs4_stateid_match_other(&old_delegation->stateid, > &delegation->stateid)) { > spin_lock(&old_delegation->lock); > - nfs_update_inplace_delegation(old_delegation, > + nfs_update_inplace_delegation(server, old_delegation, > delegation); > spin_unlock(&old_delegation->lock); > goto out; > @@ -530,7 +532,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred, > rcu_assign_pointer(nfsi->delegation, delegation); > delegation = NULL; > > - atomic_long_inc(&nfs_active_delegations); > + atomic_long_inc(&server->nr_active_delegations); > > trace_nfs4_set_delegation(inode, type); > > @@ -544,7 +546,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred, > __nfs_free_delegation(delegation); > if (freeme != NULL) { > nfs_do_return_delegation(inode, freeme, 0); > - nfs_free_delegation(freeme); > + nfs_free_delegation(server, freeme); > } > return status; > } > @@ -756,7 +758,7 @@ void nfs_inode_evict_delegation(struct inode *inode) > set_bit(NFS_DELEGATION_RETURNING, &delegation->flags); > set_bit(NFS_DELEGATION_INODE_FREEING, &delegation->flags); > nfs_do_return_delegation(inode, delegation, 1); > - nfs_free_delegation(delegation); > + nfs_free_delegation(NFS_SERVER(inode), delegation); > } > } > > @@ -842,7 +844,8 @@ void nfs4_inode_return_delegation_on_close(struct inode *inode) > if (!delegation) > goto out; > if (test_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) || > - atomic_long_read(&nfs_active_delegations) >= nfs_delegation_watermark) { > + atomic_long_read(&NFS_SERVER(inode)->nr_active_delegations) >= > + nfs_delegation_watermark) { > spin_lock(&delegation->lock); > if (delegation->inode && > list_empty(&NFS_I(inode)->open_files) && > @@ -1018,7 +1021,7 @@ static void nfs_revoke_delegation(struct inode *inode, > } > spin_unlock(&delegation->lock); > } > - nfs_mark_delegation_revoked(delegation); > + nfs_mark_delegation_revoked(NFS_SERVER(inode), delegation); > ret = true; > out: > rcu_read_unlock(); > @@ -1050,7 +1053,7 @@ void nfs_delegation_mark_returned(struct inode *inode, > delegation->stateid.seqid = stateid->seqid; > } > > - nfs_mark_delegation_revoked(delegation); > + nfs_mark_delegation_revoked(NFS_SERVER(inode), delegation); > clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags); > spin_unlock(&delegation->lock); > if (nfs_detach_delegation(NFS_I(inode), delegation, NFS_SERVER(inode))) > @@ -1272,7 +1275,7 @@ static int nfs_server_reap_unclaimed_delegations(struct nfs_server *server, > if (delegation != NULL) { > if (nfs_detach_delegation(NFS_I(inode), delegation, > server) != NULL) > - nfs_free_delegation(delegation); > + nfs_free_delegation(server, delegation); > /* Match nfs_start_delegation_return_locked */ > nfs_put_delegation(delegation); > } > diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h > index 73bed04529a7..fe930d685780 100644 > --- a/include/linux/nfs_fs_sb.h > +++ b/include/linux/nfs_fs_sb.h > @@ -255,6 +255,7 @@ struct nfs_server { > struct list_head state_owners_lru; > struct list_head layouts; > struct list_head delegations; > + atomic_long_t nr_active_delegations; > struct list_head ss_copies; > struct list_head ss_src_copies; > Good idea. I like this. Reviewed-by: Jeff Layton <jlayton@xxxxxxxxxx>