Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6f9449be authored by Trond Myklebust's avatar Trond Myklebust
Browse files

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: 45870d69 ("NFSv4.1: Test delegation stateids when server...")
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent 3453d570
Loading
Loading
Loading
Loading
+12 −8
Original line number Diff line number Diff line
@@ -229,6 +229,8 @@ static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation
	spin_lock(&delegation->lock);
	if (delegation->inode != NULL)
		inode = igrab(delegation->inode);
	if (!inode)
		set_bit(NFS_DELEGATION_INODE_FREEING, &delegation->flags);
	spin_unlock(&delegation->lock);
	return inode;
}
@@ -944,10 +946,11 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
		list_for_each_entry_rcu(delegation, &server->delegations,
								super_list) {
			if (test_bit(NFS_DELEGATION_RETURNING,
						&delegation->flags))
				continue;
			if (test_bit(NFS_DELEGATION_NEED_RECLAIM,
			if (test_bit(NFS_DELEGATION_INODE_FREEING,
						&delegation->flags) ||
			    test_bit(NFS_DELEGATION_RETURNING,
						&delegation->flags) ||
			    test_bit(NFS_DELEGATION_NEED_RECLAIM,
						&delegation->flags) == 0)
				continue;
			if (!nfs_sb_active(server->super))
@@ -1053,10 +1056,11 @@ void nfs_reap_expired_delegations(struct nfs_client *clp)
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
		list_for_each_entry_rcu(delegation, &server->delegations,
								super_list) {
			if (test_bit(NFS_DELEGATION_RETURNING,
						&delegation->flags))
				continue;
			if (test_bit(NFS_DELEGATION_TEST_EXPIRED,
			if (test_bit(NFS_DELEGATION_INODE_FREEING,
						&delegation->flags) ||
			    test_bit(NFS_DELEGATION_RETURNING,
						&delegation->flags) ||
			    test_bit(NFS_DELEGATION_TEST_EXPIRED,
						&delegation->flags) == 0)
				continue;
			if (!nfs_sb_active(server->super))
+1 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ enum {
	NFS_DELEGATION_RETURNING,
	NFS_DELEGATION_REVOKED,
	NFS_DELEGATION_TEST_EXPIRED,
	NFS_DELEGATION_INODE_FREEING,
};

int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,