]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
NFS: track active delegations per-server
authorChristoph Hellwig <hch@lst.de>
Fri, 18 Jul 2025 08:14:49 +0000 (10:14 +0200)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Tue, 22 Jul 2025 12:10:41 +0000 (08:10 -0400)
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@lst.de>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Link: https://lore.kernel.org/r/20250718081509.2607553-5-hch@lst.de
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/client.c
fs/nfs/delegation.c
include/linux/nfs_fs_sb.h

index 47258dc3af70b8f677a77217395d4195492325e1..e13eb429b8b567393005c0516caac665236f66b0 100644 (file)
@@ -1005,6 +1005,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) {
index 5f85966d7709c8b079d9e4f37dfe7023c63ed8c9..ea96f77e38c21481654da600cf4cd127b1d6718e 100644 (file)
@@ -27,7 +27,6 @@
 
 #define NFS_DEFAULT_DELEGATION_WATERMARK (5000U)
 
-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 @@ add_new:
        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 @@ out:
                __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)))
@@ -1270,7 +1273,7 @@ restart:
                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);
                }
index d2d36711a1190b36c9d140ed78614a2e9d0fc181..a9b44f12623f01b4198e5c8c78407d5bf8fd59de 100644 (file)
@@ -254,6 +254,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;