* [PATCH 0/4] Fixes for looping in the NFSv4 manager thread
@ 2025-03-03 17:35 trondmy
2025-03-03 17:35 ` [PATCH 1/4] NFSv4: Don't trigger uneccessary scans for return-on-close delegations trondmy
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: trondmy @ 2025-03-03 17:35 UTC (permalink / raw)
To: linux-nfs
From: Trond Myklebust <trond.myklebust@hammerspace.com>
The following set of patches address an issue where the NFSv4 manager
thread can end up doing a lot of looping in order to do asynchronous
returns of old delegations. When the list of cached delegations gets
large enough, this can sometimes lead to soft lockups being declared.
Trond Myklebust (4):
NFSv4: Don't trigger uneccessary scans for return-on-close delegations
NFSv4: Avoid unnecessary scans of filesystems for returning
delegations
NFSv4: Avoid unnecessary scans of filesystems for expired delegations
NFSv4: Avoid unnecessary scans of filesystems for delayed delegations
fs/nfs/delegation.c | 63 ++++++++++++++++++++++++++-------------
include/linux/nfs_fs_sb.h | 4 +++
2 files changed, 46 insertions(+), 21 deletions(-)
--
2.48.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/4] NFSv4: Don't trigger uneccessary scans for return-on-close delegations
2025-03-03 17:35 [PATCH 0/4] Fixes for looping in the NFSv4 manager thread trondmy
@ 2025-03-03 17:35 ` trondmy
2025-03-03 17:35 ` [PATCH 2/4] NFSv4: Avoid unnecessary scans of filesystems for returning delegations trondmy
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: trondmy @ 2025-03-03 17:35 UTC (permalink / raw)
To: linux-nfs
From: Trond Myklebust <trond.myklebust@hammerspace.com>
The amount of looping through the list of delegations is occasionally
leading to soft lockups. Avoid at least some loops by not requiring the
NFSv4 state manager to scan for delegations that are marked for
return-on-close. Instead, either mark them for immediate return (if
possible) or else leave it up to nfs4_inode_return_delegation_on_close()
to return them once the file is closed by the application.
Fixes: b757144fd77c ("NFSv4: Be less aggressive about returning delegations for open files")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
---
fs/nfs/delegation.c | 33 ++++++++++++++++++---------------
1 file changed, 18 insertions(+), 15 deletions(-)
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 4db912f56230..df77d68d9ff9 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -590,17 +590,6 @@ static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
ret = true;
- else if (test_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags)) {
- struct inode *inode;
-
- spin_lock(&delegation->lock);
- inode = delegation->inode;
- if (inode && list_empty(&NFS_I(inode)->open_files))
- ret = true;
- spin_unlock(&delegation->lock);
- }
- if (ret)
- clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags);
if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags) ||
test_bit(NFS_DELEGATION_RETURN_DELAYED, &delegation->flags) ||
test_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
@@ -878,11 +867,25 @@ int nfs4_inode_make_writeable(struct inode *inode)
return nfs4_inode_return_delegation(inode);
}
-static void nfs_mark_return_if_closed_delegation(struct nfs_server *server,
- struct nfs_delegation *delegation)
+static void
+nfs_mark_return_if_closed_delegation(struct nfs_server *server,
+ struct nfs_delegation *delegation)
{
- set_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags);
- set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
+ struct inode *inode;
+
+ if (test_bit(NFS_DELEGATION_RETURN, &delegation->flags) ||
+ test_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags))
+ return;
+ spin_lock(&delegation->lock);
+ inode = delegation->inode;
+ if (!inode)
+ goto out;
+ if (list_empty(&NFS_I(inode)->open_files))
+ nfs_mark_return_delegation(server, delegation);
+ else
+ set_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags);
+out:
+ spin_unlock(&delegation->lock);
}
static bool nfs_server_mark_return_all_delegations(struct nfs_server *server)
--
2.48.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/4] NFSv4: Avoid unnecessary scans of filesystems for returning delegations
2025-03-03 17:35 [PATCH 0/4] Fixes for looping in the NFSv4 manager thread trondmy
2025-03-03 17:35 ` [PATCH 1/4] NFSv4: Don't trigger uneccessary scans for return-on-close delegations trondmy
@ 2025-03-03 17:35 ` trondmy
2025-03-03 17:35 ` [PATCH 3/4] NFSv4: Avoid unnecessary scans of filesystems for expired delegations trondmy
2025-03-03 17:35 ` [PATCH 4/4] NFSv4: Avoid unnecessary scans of filesystems for delayed delegations trondmy
3 siblings, 0 replies; 5+ messages in thread
From: trondmy @ 2025-03-03 17:35 UTC (permalink / raw)
To: linux-nfs
From: Trond Myklebust <trond.myklebust@hammerspace.com>
The amount of looping through the list of delegations is occasionally
leading to soft lockups. If the state manager was asked to return
delegations asynchronously, it should only scan those filesystems that
hold delegations that need to be returned.
Fixes: af3b61bf6131 ("NFSv4: Clean up nfs_client_return_marked_delegations()")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
---
fs/nfs/delegation.c | 5 +++++
include/linux/nfs_fs_sb.h | 2 ++
2 files changed, 7 insertions(+)
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index df77d68d9ff9..d1f5e497729c 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -79,6 +79,7 @@ static void nfs_mark_return_delegation(struct nfs_server *server,
struct nfs_delegation *delegation)
{
set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
+ set_bit(NFS4SERV_DELEGRETURN, &server->delegation_flags);
set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
}
@@ -608,6 +609,9 @@ static int nfs_server_return_marked_delegations(struct nfs_server *server,
struct nfs_delegation *place_holder_deleg = NULL;
int err = 0;
+ if (!test_and_clear_bit(NFS4SERV_DELEGRETURN,
+ &server->delegation_flags))
+ return 0;
restart:
/*
* To avoid quadratic looping we hold a reference
@@ -659,6 +663,7 @@ static int nfs_server_return_marked_delegations(struct nfs_server *server,
cond_resched();
if (!err)
goto restart;
+ set_bit(NFS4SERV_DELEGRETURN, &server->delegation_flags);
set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
goto out;
}
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index f00bfcee7120..4e9ad6f6e907 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -250,6 +250,8 @@ struct nfs_server {
struct list_head ss_copies;
struct list_head ss_src_copies;
+ unsigned long delegation_flags;
+#define NFS4SERV_DELEGRETURN (1)
unsigned long delegation_gen;
unsigned long mig_gen;
unsigned long mig_status;
--
2.48.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/4] NFSv4: Avoid unnecessary scans of filesystems for expired delegations
2025-03-03 17:35 [PATCH 0/4] Fixes for looping in the NFSv4 manager thread trondmy
2025-03-03 17:35 ` [PATCH 1/4] NFSv4: Don't trigger uneccessary scans for return-on-close delegations trondmy
2025-03-03 17:35 ` [PATCH 2/4] NFSv4: Avoid unnecessary scans of filesystems for returning delegations trondmy
@ 2025-03-03 17:35 ` trondmy
2025-03-03 17:35 ` [PATCH 4/4] NFSv4: Avoid unnecessary scans of filesystems for delayed delegations trondmy
3 siblings, 0 replies; 5+ messages in thread
From: trondmy @ 2025-03-03 17:35 UTC (permalink / raw)
To: linux-nfs
From: Trond Myklebust <trond.myklebust@hammerspace.com>
The amount of looping through the list of delegations is occasionally
leading to soft lockups. If the state manager was asked to reap the
expired delegations, it should scan only those filesystems that hold
delegations that need to be reaped.
Fixes: 7f156ef0bf45 ("NFSv4: Clean up nfs_delegation_reap_expired()")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
---
fs/nfs/delegation.c | 7 +++++++
include/linux/nfs_fs_sb.h | 1 +
2 files changed, 8 insertions(+)
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index d1f5e497729c..abd952cc47e4 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -1284,6 +1284,7 @@ static void nfs_mark_test_expired_delegation(struct nfs_server *server,
return;
clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
set_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags);
+ set_bit(NFS4SERV_DELEGATION_EXPIRED, &server->delegation_flags);
set_bit(NFS4CLNT_DELEGATION_EXPIRED, &server->nfs_client->cl_state);
}
@@ -1362,6 +1363,9 @@ static int nfs_server_reap_expired_delegations(struct nfs_server *server,
nfs4_stateid stateid;
unsigned long gen = ++server->delegation_gen;
+ if (!test_and_clear_bit(NFS4SERV_DELEGATION_EXPIRED,
+ &server->delegation_flags))
+ return 0;
restart:
rcu_read_lock();
list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
@@ -1391,6 +1395,9 @@ static int nfs_server_reap_expired_delegations(struct nfs_server *server,
goto restart;
}
nfs_inode_mark_test_expired_delegation(server,inode);
+ set_bit(NFS4SERV_DELEGATION_EXPIRED, &server->delegation_flags);
+ set_bit(NFS4CLNT_DELEGATION_EXPIRED,
+ &server->nfs_client->cl_state);
iput(inode);
return -EAGAIN;
}
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 4e9ad6f6e907..7d6f164036fa 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -252,6 +252,7 @@ struct nfs_server {
unsigned long delegation_flags;
#define NFS4SERV_DELEGRETURN (1)
+#define NFS4SERV_DELEGATION_EXPIRED (2)
unsigned long delegation_gen;
unsigned long mig_gen;
unsigned long mig_status;
--
2.48.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 4/4] NFSv4: Avoid unnecessary scans of filesystems for delayed delegations
2025-03-03 17:35 [PATCH 0/4] Fixes for looping in the NFSv4 manager thread trondmy
` (2 preceding siblings ...)
2025-03-03 17:35 ` [PATCH 3/4] NFSv4: Avoid unnecessary scans of filesystems for expired delegations trondmy
@ 2025-03-03 17:35 ` trondmy
3 siblings, 0 replies; 5+ messages in thread
From: trondmy @ 2025-03-03 17:35 UTC (permalink / raw)
To: linux-nfs
From: Trond Myklebust <trond.myklebust@hammerspace.com>
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>
---
fs/nfs/delegation.c | 18 ++++++++++++------
include/linux/nfs_fs_sb.h | 1 +
2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index abd952cc47e4..325ba0663a6d 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -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 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
*/
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;
}
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 7d6f164036fa..108862d81b57 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -253,6 +253,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;
--
2.48.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-03-03 17:35 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-03 17:35 [PATCH 0/4] Fixes for looping in the NFSv4 manager thread trondmy
2025-03-03 17:35 ` [PATCH 1/4] NFSv4: Don't trigger uneccessary scans for return-on-close delegations trondmy
2025-03-03 17:35 ` [PATCH 2/4] NFSv4: Avoid unnecessary scans of filesystems for returning delegations trondmy
2025-03-03 17:35 ` [PATCH 3/4] NFSv4: Avoid unnecessary scans of filesystems for expired delegations trondmy
2025-03-03 17:35 ` [PATCH 4/4] NFSv4: Avoid unnecessary scans of filesystems for delayed delegations trondmy
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox