Skip to content

Commit 2d4a532

Browse files
Jeff LaytonJ. Bruce Fields
Jeff Layton
authored and
J. Bruce Fields
committed
nfsd: ensure that clp->cl_revoked list is protected by clp->cl_lock
Currently, both destroy_revoked_delegation and revoke_delegation manipulate the cl_revoked list without any locking aside from the client_mutex. Ensure that the clp->cl_lock is held when manipulating it, except for the list walking in destroy_client. At that point, the client should no longer be in use, and so it should be safe to walk the list without any locking. That also means that we don't need to do the list_splice_init there either. Also, the fact that revoke_delegation deletes dl_recall_lru list_head without any locking makes it difficult to know whether it's doing so safely in all cases. Move the list_del_init calls into the callers, and add a WARN_ON in the event that t's passed a delegation that has a non-empty list_head. Signed-off-by: Jeff Layton <jlayton@primarydata.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
1 parent 4269067 commit 2d4a532

File tree

1 file changed

+20
-15
lines changed

1 file changed

+20
-15
lines changed

fs/nfsd/nfs4state.c

+20-15
Original file line numberDiff line numberDiff line change
@@ -680,12 +680,6 @@ unhash_delegation_locked(struct nfs4_delegation *dp)
680680
nfs4_put_deleg_lease(fp);
681681
}
682682

683-
static void destroy_revoked_delegation(struct nfs4_delegation *dp)
684-
{
685-
list_del_init(&dp->dl_recall_lru);
686-
nfs4_put_delegation(dp);
687-
}
688-
689683
static void destroy_delegation(struct nfs4_delegation *dp)
690684
{
691685
spin_lock(&state_lock);
@@ -698,11 +692,15 @@ static void revoke_delegation(struct nfs4_delegation *dp)
698692
{
699693
struct nfs4_client *clp = dp->dl_stid.sc_client;
700694

695+
WARN_ON(!list_empty(&dp->dl_recall_lru));
696+
701697
if (clp->cl_minorversion == 0)
702-
destroy_revoked_delegation(dp);
698+
nfs4_put_delegation(dp);
703699
else {
704700
dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID;
705-
list_move(&dp->dl_recall_lru, &clp->cl_revoked);
701+
spin_lock(&clp->cl_lock);
702+
list_add(&dp->dl_recall_lru, &clp->cl_revoked);
703+
spin_unlock(&clp->cl_lock);
706704
}
707705
}
708706

@@ -1467,10 +1465,10 @@ destroy_client(struct nfs4_client *clp)
14671465
list_del_init(&dp->dl_recall_lru);
14681466
nfs4_put_delegation(dp);
14691467
}
1470-
list_splice_init(&clp->cl_revoked, &reaplist);
1471-
while (!list_empty(&reaplist)) {
1468+
while (!list_empty(&clp->cl_revoked)) {
14721469
dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
1473-
destroy_revoked_delegation(dp);
1470+
list_del_init(&dp->dl_recall_lru);
1471+
nfs4_put_delegation(dp);
14741472
}
14751473
while (!list_empty(&clp->cl_openowners)) {
14761474
oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
@@ -3903,8 +3901,10 @@ nfs4_laundromat(struct nfsd_net *nn)
39033901
list_add(&dp->dl_recall_lru, &reaplist);
39043902
}
39053903
spin_unlock(&state_lock);
3906-
list_for_each_safe(pos, next, &reaplist) {
3907-
dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
3904+
while (!list_empty(&reaplist)) {
3905+
dp = list_first_entry(&reaplist, struct nfs4_delegation,
3906+
dl_recall_lru);
3907+
list_del_init(&dp->dl_recall_lru);
39083908
revoke_delegation(dp);
39093909
}
39103910
list_for_each_safe(pos, next, &nn->close_lru) {
@@ -4248,7 +4248,10 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
42484248
break;
42494249
case NFS4_REVOKED_DELEG_STID:
42504250
dp = delegstateid(s);
4251-
destroy_revoked_delegation(dp);
4251+
spin_lock(&cl->cl_lock);
4252+
list_del_init(&dp->dl_recall_lru);
4253+
spin_unlock(&cl->cl_lock);
4254+
nfs4_put_delegation(dp);
42524255
ret = nfs_ok;
42534256
break;
42544257
default:
@@ -5401,8 +5404,10 @@ u64 nfsd_forget_client_delegations(struct nfs4_client *clp, u64 max)
54015404
count = nfsd_find_all_delegations(clp, max, &victims);
54025405
spin_unlock(&state_lock);
54035406

5404-
list_for_each_entry_safe(dp, next, &victims, dl_recall_lru)
5407+
list_for_each_entry_safe(dp, next, &victims, dl_recall_lru) {
5408+
list_del_init(&dp->dl_recall_lru);
54055409
revoke_delegation(dp);
5410+
}
54065411

54075412
return count;
54085413
}

0 commit comments

Comments
 (0)