Skip to content

Commit

Permalink
nfsd: fully unhash delegations when revoking them
Browse files Browse the repository at this point in the history
Ensure that the delegations cannot be found by the laundromat etc once
we add them to the various 'revoke' lists.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Jeff Layton <jlayton@primarydata.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
  • Loading branch information
Jeff Layton authored and J. Bruce Fields committed Jul 29, 2014
1 parent f833883 commit 4269067
Showing 1 changed file with 21 additions and 23 deletions.
44 changes: 21 additions & 23 deletions fs/nfsd/nfs4state.c
Original file line number Diff line number Diff line change
Expand Up @@ -661,13 +661,13 @@ hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
}

/* Called under the state lock. */
static void
unhash_delegation(struct nfs4_delegation *dp)
unhash_delegation_locked(struct nfs4_delegation *dp)
{
struct nfs4_file *fp = dp->dl_file;

spin_lock(&state_lock);
lockdep_assert_held(&state_lock);

dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID;
/* Ensure that deleg break won't try to requeue it */
++dp->dl_time;
Expand All @@ -678,7 +678,6 @@ unhash_delegation(struct nfs4_delegation *dp)
spin_unlock(&fp->fi_lock);
if (fp)
nfs4_put_deleg_lease(fp);
spin_unlock(&state_lock);
}

static void destroy_revoked_delegation(struct nfs4_delegation *dp)
Expand All @@ -689,7 +688,9 @@ static void destroy_revoked_delegation(struct nfs4_delegation *dp)

static void destroy_delegation(struct nfs4_delegation *dp)
{
unhash_delegation(dp);
spin_lock(&state_lock);
unhash_delegation_locked(dp);
spin_unlock(&state_lock);
nfs4_put_delegation(dp);
}

Expand All @@ -698,11 +699,10 @@ static void revoke_delegation(struct nfs4_delegation *dp)
struct nfs4_client *clp = dp->dl_stid.sc_client;

if (clp->cl_minorversion == 0)
destroy_delegation(dp);
destroy_revoked_delegation(dp);
else {
unhash_delegation(dp);
dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID;
list_add(&dp->dl_recall_lru, &clp->cl_revoked);
list_move(&dp->dl_recall_lru, &clp->cl_revoked);
}
}

Expand Down Expand Up @@ -1458,15 +1458,14 @@ destroy_client(struct nfs4_client *clp)
spin_lock(&state_lock);
while (!list_empty(&clp->cl_delegations)) {
dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
list_del_init(&dp->dl_perclnt);
/* Ensure that deleg break won't try to requeue it */
++dp->dl_time;
list_move(&dp->dl_recall_lru, &reaplist);
unhash_delegation_locked(dp);
list_add(&dp->dl_recall_lru, &reaplist);
}
spin_unlock(&state_lock);
while (!list_empty(&reaplist)) {
dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
destroy_delegation(dp);
list_del_init(&dp->dl_recall_lru);
nfs4_put_delegation(dp);
}
list_splice_init(&clp->cl_revoked, &reaplist);
while (!list_empty(&reaplist)) {
Expand Down Expand Up @@ -3662,7 +3661,7 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh,
open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
return;
out_free:
destroy_delegation(dp);
nfs4_put_delegation(dp);
out_no_deleg:
open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&
Expand Down Expand Up @@ -3900,7 +3899,8 @@ nfs4_laundromat(struct nfsd_net *nn)
new_timeo = min(new_timeo, t);
break;
}
list_move(&dp->dl_recall_lru, &reaplist);
unhash_delegation_locked(dp);
list_add(&dp->dl_recall_lru, &reaplist);
}
spin_unlock(&state_lock);
list_for_each_safe(pos, next, &reaplist) {
Expand Down Expand Up @@ -5382,12 +5382,8 @@ static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max,
if (dp->dl_time != 0)
continue;

/*
* Increment dl_time to ensure that delegation breaks
* don't monkey with it now that we are.
*/
++dp->dl_time;
list_move(&dp->dl_recall_lru, victims);
unhash_delegation_locked(dp);
list_add(&dp->dl_recall_lru, victims);
}
if (++count == max)
break;
Expand Down Expand Up @@ -5642,12 +5638,14 @@ nfs4_state_shutdown_net(struct net *net)
spin_lock(&state_lock);
list_for_each_safe(pos, next, &nn->del_recall_lru) {
dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
list_move(&dp->dl_recall_lru, &reaplist);
unhash_delegation_locked(dp);
list_add(&dp->dl_recall_lru, &reaplist);
}
spin_unlock(&state_lock);
list_for_each_safe(pos, next, &reaplist) {
dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
destroy_delegation(dp);
list_del_init(&dp->dl_recall_lru);
nfs4_put_delegation(dp);
}

nfsd4_client_tracking_exit(net);
Expand Down

0 comments on commit 4269067

Please sign in to comment.