Skip to content

Commit a9b8d90

Browse files
bcodding-rhTrond Myklebust
authored andcommitted
NFSv4: fairly test all delegations on a SEQ4_ revocation
When the client is required to use TEST_STATEID to discover which delegation(s) have been revoked, it may continually test delegations at the head of the list if the server continues to be unsatisfied and send SEQ4_STATUS_RECALLABLE_STATE_REVOKED. For a large number of delegations this behavior is prone to live-lock because the client may never be able to test and free revoked state at the end of the list since the SEQ4_STATUS_RECALLABLE_STATE_REVOKED will cause us to flag delegations at the head of the list to be tested. This problem is further exacerbated by the state manager's willingness to be scheduled out on a busy system while testing the list of delegations. Keep a generation counter for each attempt to test all delegations, and skip delegations that have already been tested in the current pass. Signed-off-by: Benjamin Coddington <bcodding@redhat.com> Tested-by: Torkil Svensgaard <torkil@drcmr.dk> Tested-by: Ruben Vestergaard <rubenv@drcmr.dk> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
1 parent 59464b2 commit a9b8d90

File tree

3 files changed

+8
-1
lines changed

3 files changed

+8
-1
lines changed

fs/nfs/delegation.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
448448
delegation->cred = get_cred(cred);
449449
delegation->inode = inode;
450450
delegation->flags = 1<<NFS_DELEGATION_REFERENCED;
451+
delegation->test_gen = 0;
451452
spin_lock_init(&delegation->lock);
452453

453454
spin_lock(&clp->cl_lock);
@@ -1294,6 +1295,8 @@ static int nfs_server_reap_expired_delegations(struct nfs_server *server,
12941295
struct inode *inode;
12951296
const struct cred *cred;
12961297
nfs4_stateid stateid;
1298+
unsigned long gen = ++server->delegation_gen;
1299+
12971300
restart:
12981301
rcu_read_lock();
12991302
restart_locked:
@@ -1303,7 +1306,8 @@ static int nfs_server_reap_expired_delegations(struct nfs_server *server,
13031306
test_bit(NFS_DELEGATION_RETURNING,
13041307
&delegation->flags) ||
13051308
test_bit(NFS_DELEGATION_TEST_EXPIRED,
1306-
&delegation->flags) == 0)
1309+
&delegation->flags) == 0 ||
1310+
delegation->test_gen == gen)
13071311
continue;
13081312
inode = nfs_delegation_grab_inode(delegation);
13091313
if (inode == NULL)
@@ -1312,6 +1316,7 @@ static int nfs_server_reap_expired_delegations(struct nfs_server *server,
13121316
cred = get_cred_rcu(delegation->cred);
13131317
nfs4_stateid_copy(&stateid, &delegation->stateid);
13141318
spin_unlock(&delegation->lock);
1319+
delegation->test_gen = gen;
13151320
clear_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags);
13161321
rcu_read_unlock();
13171322
nfs_delegation_test_free_expired(inode, &stateid, cred);

fs/nfs/delegation.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ struct nfs_delegation {
2121
fmode_t type;
2222
unsigned long pagemod_limit;
2323
__u64 change_attr;
24+
unsigned long test_gen;
2425
unsigned long flags;
2526
refcount_t refcount;
2627
spinlock_t lock;

include/linux/nfs_fs_sb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ struct nfs_server {
239239
struct list_head delegations;
240240
struct list_head ss_copies;
241241

242+
unsigned long delegation_gen;
242243
unsigned long mig_gen;
243244
unsigned long mig_status;
244245
#define NFS_MIG_IN_TRANSITION (1)

0 commit comments

Comments
 (0)