aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2013-03-21 11:21:50 -0400
committerJ. Bruce Fields <bfields@redhat.com>2013-04-04 13:25:15 -0400
commit68a3396178e6688ad7367202cdf0af8ed03c8727 (patch)
tree1a05bea4199eb6637860a5242a9f8794c0fba5c6 /fs
parent8be2d2344cc192c20d7b2aa3211a5b74082e47d4 (diff)
nfsd4: shut down more of delegation earlier
Once we've unhashed the delegation, it's only hanging around for the benefit of an oustanding recall, which only needs the encoded filehandle, stateid, and dl_retries counter. No point keeping the file around any longer, or keeping it hashed. This also fixes a race: calls to idr_remove should really be serialized by the caller, but the nfs4_put_delegation call from the callback code isn't taking the state lock. (Better might be to cancel the callback before destroying the delegation, and remove any need for reference counting--but I don't see an easy way to cancel an rpc call.) Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfsd/nfs4state.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 7293e298aeed..26a03fa6840a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -417,21 +417,18 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
417 return dp; 417 return dp;
418} 418}
419 419
420static void free_stid(struct nfs4_stid *s, struct kmem_cache *slab) 420static void remove_stid(struct nfs4_stid *s)
421{ 421{
422 struct idr *stateids = &s->sc_client->cl_stateids; 422 struct idr *stateids = &s->sc_client->cl_stateids;
423 423
424 idr_remove(stateids, s->sc_stateid.si_opaque.so_id); 424 idr_remove(stateids, s->sc_stateid.si_opaque.so_id);
425 kmem_cache_free(slab, s);
426} 425}
427 426
428void 427void
429nfs4_put_delegation(struct nfs4_delegation *dp) 428nfs4_put_delegation(struct nfs4_delegation *dp)
430{ 429{
431 if (atomic_dec_and_test(&dp->dl_count)) { 430 if (atomic_dec_and_test(&dp->dl_count)) {
432 dprintk("NFSD: freeing dp %p\n",dp); 431 kmem_cache_free(deleg_slab, dp);
433 put_nfs4_file(dp->dl_file);
434 free_stid(&dp->dl_stid, deleg_slab);
435 num_delegations--; 432 num_delegations--;
436 } 433 }
437} 434}
@@ -462,6 +459,9 @@ unhash_delegation(struct nfs4_delegation *dp)
462 list_del_init(&dp->dl_recall_lru); 459 list_del_init(&dp->dl_recall_lru);
463 spin_unlock(&recall_lock); 460 spin_unlock(&recall_lock);
464 nfs4_put_deleg_lease(dp->dl_file); 461 nfs4_put_deleg_lease(dp->dl_file);
462 put_nfs4_file(dp->dl_file);
463 dp->dl_file = NULL;
464 remove_stid(&dp->dl_stid);
465 nfs4_put_delegation(dp); 465 nfs4_put_delegation(dp);
466} 466}
467 467
@@ -605,7 +605,8 @@ static void close_generic_stateid(struct nfs4_ol_stateid *stp)
605 605
606static void free_generic_stateid(struct nfs4_ol_stateid *stp) 606static void free_generic_stateid(struct nfs4_ol_stateid *stp)
607{ 607{
608 free_stid(&stp->st_stid, stateid_slab); 608 remove_stid(&stp->st_stid);
609 kmem_cache_free(stateid_slab, stp);
609} 610}
610 611
611static void release_lock_stateid(struct nfs4_ol_stateid *stp) 612static void release_lock_stateid(struct nfs4_ol_stateid *stp)