]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
NFSv4: Avoid unnecessary scans of filesystems for delayed delegations
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Tue, 18 Feb 2025 23:37:51 +0000 (18:37 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 10 Apr 2025 12:39:24 +0000 (14:39 +0200)
[ Upstream commit e767b59e29b8327d25edde65efc743f479f30d0a ]

The amount of looping through the list of delegations is occasionally
leading to soft lockups. If the state manager was asked to manage the
delayed return of delegations, then only scan those filesystems
containing delegations that were marked as being delayed.

Fixes: be20037725d1 ("NFSv4: Fix delegation return in cases where we have to retry")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/nfs/delegation.c
include/linux/nfs_fs_sb.h

index abd952cc47e4be7806e2ee6cb76731ec70b0f084..325ba0663a6de24fe9d6e53196c3154f053431ee 100644 (file)
@@ -331,14 +331,16 @@ nfs_start_delegation_return(struct nfs_inode *nfsi)
 }
 
 static void nfs_abort_delegation_return(struct nfs_delegation *delegation,
-                                       struct nfs_client *clp, int err)
+                                       struct nfs_server *server, int err)
 {
-
        spin_lock(&delegation->lock);
        clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
        if (err == -EAGAIN) {
                set_bit(NFS_DELEGATION_RETURN_DELAYED, &delegation->flags);
-               set_bit(NFS4CLNT_DELEGRETURN_DELAYED, &clp->cl_state);
+               set_bit(NFS4SERV_DELEGRETURN_DELAYED,
+                       &server->delegation_flags);
+               set_bit(NFS4CLNT_DELEGRETURN_DELAYED,
+                       &server->nfs_client->cl_state);
        }
        spin_unlock(&delegation->lock);
 }
@@ -548,7 +550,7 @@ out:
  */
 static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation *delegation, int issync)
 {
-       struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
+       struct nfs_server *server = NFS_SERVER(inode);
        unsigned int mode = O_WRONLY | O_RDWR;
        int err = 0;
 
@@ -570,11 +572,11 @@ static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation
                /*
                 * Guard against state recovery
                 */
-               err = nfs4_wait_clnt_recover(clp);
+               err = nfs4_wait_clnt_recover(server->nfs_client);
        }
 
        if (err) {
-               nfs_abort_delegation_return(delegation, clp, err);
+               nfs_abort_delegation_return(delegation, server, err);
                goto out;
        }
 
@@ -678,6 +680,9 @@ static bool nfs_server_clear_delayed_delegations(struct nfs_server *server)
        struct nfs_delegation *d;
        bool ret = false;
 
+       if (!test_and_clear_bit(NFS4SERV_DELEGRETURN_DELAYED,
+                               &server->delegation_flags))
+               goto out;
        list_for_each_entry_rcu (d, &server->delegations, super_list) {
                if (!test_bit(NFS_DELEGATION_RETURN_DELAYED, &d->flags))
                        continue;
@@ -685,6 +690,7 @@ static bool nfs_server_clear_delayed_delegations(struct nfs_server *server)
                clear_bit(NFS_DELEGATION_RETURN_DELAYED, &d->flags);
                ret = true;
        }
+out:
        return ret;
 }
 
index f4cb1f4850a0cb111d11e218b56550a7fcdf1a32..81ab18658d72dcb519d0f9cc5cc1a9df2f2dd655 100644 (file)
@@ -254,6 +254,7 @@ struct nfs_server {
        unsigned long           delegation_flags;
 #define NFS4SERV_DELEGRETURN           (1)
 #define NFS4SERV_DELEGATION_EXPIRED    (2)
+#define NFS4SERV_DELEGRETURN_DELAYED   (3)
        unsigned long           delegation_gen;
        unsigned long           mig_gen;
        unsigned long           mig_status;