aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@hammerspace.com>2019-02-21 14:51:25 -0500
committerTrond Myklebust <trond.myklebust@hammerspace.com>2019-02-21 14:51:25 -0500
commit6f9449be53f3ce383caed797708b332ede8d952c (patch)
treeb1cf6c89dc67f5310fbe52767c073d6eb744b2b8
parent3453d5708b33efe76f40eca1c0ed60923094b971 (diff)
NFS: Fix a soft lockup in the delegation recovery code
Fix a soft lockup when NFS client delegation recovery is attempted but the inode is in the process of being freed. When the igrab(inode) call fails, and we have to restart the recovery process, we need to ensure that we won't attempt to recover the same delegation again. Fixes: 45870d6909d5a ("NFSv4.1: Test delegation stateids when server...") Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
-rw-r--r--fs/nfs/delegation.c20
-rw-r--r--fs/nfs/delegation.h1
2 files changed, 13 insertions, 8 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 70e5931f3c60..2f6b447cdd82 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -229,6 +229,8 @@ static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation
229 spin_lock(&delegation->lock); 229 spin_lock(&delegation->lock);
230 if (delegation->inode != NULL) 230 if (delegation->inode != NULL)
231 inode = igrab(delegation->inode); 231 inode = igrab(delegation->inode);
232 if (!inode)
233 set_bit(NFS_DELEGATION_INODE_FREEING, &delegation->flags);
232 spin_unlock(&delegation->lock); 234 spin_unlock(&delegation->lock);
233 return inode; 235 return inode;
234} 236}
@@ -944,10 +946,11 @@ restart:
944 list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { 946 list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
945 list_for_each_entry_rcu(delegation, &server->delegations, 947 list_for_each_entry_rcu(delegation, &server->delegations,
946 super_list) { 948 super_list) {
947 if (test_bit(NFS_DELEGATION_RETURNING, 949 if (test_bit(NFS_DELEGATION_INODE_FREEING,
948 &delegation->flags)) 950 &delegation->flags) ||
949 continue; 951 test_bit(NFS_DELEGATION_RETURNING,
950 if (test_bit(NFS_DELEGATION_NEED_RECLAIM, 952 &delegation->flags) ||
953 test_bit(NFS_DELEGATION_NEED_RECLAIM,
951 &delegation->flags) == 0) 954 &delegation->flags) == 0)
952 continue; 955 continue;
953 if (!nfs_sb_active(server->super)) 956 if (!nfs_sb_active(server->super))
@@ -1053,10 +1056,11 @@ restart:
1053 list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { 1056 list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
1054 list_for_each_entry_rcu(delegation, &server->delegations, 1057 list_for_each_entry_rcu(delegation, &server->delegations,
1055 super_list) { 1058 super_list) {
1056 if (test_bit(NFS_DELEGATION_RETURNING, 1059 if (test_bit(NFS_DELEGATION_INODE_FREEING,
1057 &delegation->flags)) 1060 &delegation->flags) ||
1058 continue; 1061 test_bit(NFS_DELEGATION_RETURNING,
1059 if (test_bit(NFS_DELEGATION_TEST_EXPIRED, 1062 &delegation->flags) ||
1063 test_bit(NFS_DELEGATION_TEST_EXPIRED,
1060 &delegation->flags) == 0) 1064 &delegation->flags) == 0)
1061 continue; 1065 continue;
1062 if (!nfs_sb_active(server->super)) 1066 if (!nfs_sb_active(server->super))
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h
index dcbf3394ba0e..35b4b02c1ae0 100644
--- a/fs/nfs/delegation.h
+++ b/fs/nfs/delegation.h
@@ -34,6 +34,7 @@ enum {
34 NFS_DELEGATION_RETURNING, 34 NFS_DELEGATION_RETURNING,
35 NFS_DELEGATION_REVOKED, 35 NFS_DELEGATION_REVOKED,
36 NFS_DELEGATION_TEST_EXPIRED, 36 NFS_DELEGATION_TEST_EXPIRED,
37 NFS_DELEGATION_INODE_FREEING,
37}; 38};
38 39
39int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred, 40int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,