diff options
author | J. Bruce Fields <bfields@citi.umich.edu> | 2007-09-12 08:43:59 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2007-10-09 18:31:57 -0400 |
commit | 1b1a9b3163a83f52ea2ac333846d4dfd2c4edd90 (patch) | |
tree | bfaaa512b4efa08bed800330f654ba9637dd2f58 /fs | |
parent | 0272e1fd9f4fa8a43357c168e081744f99e67195 (diff) |
knfsd: don't shutdown callbacks until nfsv4 client is freed
If a callback still holds a reference on the client, then it may be
about to perform an rpc call, so it isn't safe to call rpc_shutdown().
(Though rpc_shutdown() does wait for any outstanding rpc's, it can't
know if a new rpc is about to be issued with that client.)
So, wait to shutdown the rpc_client until the reference count on the
client has gone to zero.
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfsd/nfs4state.c | 27 |
1 files changed, 13 insertions, 14 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 48fbdac33c7c..e706c6961691 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -358,9 +358,22 @@ alloc_client(struct xdr_netobj name) | |||
358 | return clp; | 358 | return clp; |
359 | } | 359 | } |
360 | 360 | ||
361 | static void | ||
362 | shutdown_callback_client(struct nfs4_client *clp) | ||
363 | { | ||
364 | struct rpc_clnt *clnt = clp->cl_callback.cb_client; | ||
365 | |||
366 | /* shutdown rpc client, ending any outstanding recall rpcs */ | ||
367 | if (clnt) { | ||
368 | clp->cl_callback.cb_client = NULL; | ||
369 | rpc_shutdown_client(clnt); | ||
370 | } | ||
371 | } | ||
372 | |||
361 | static inline void | 373 | static inline void |
362 | free_client(struct nfs4_client *clp) | 374 | free_client(struct nfs4_client *clp) |
363 | { | 375 | { |
376 | shutdown_callback_client(clp); | ||
364 | if (clp->cl_cred.cr_group_info) | 377 | if (clp->cl_cred.cr_group_info) |
365 | put_group_info(clp->cl_cred.cr_group_info); | 378 | put_group_info(clp->cl_cred.cr_group_info); |
366 | kfree(clp->cl_name.data); | 379 | kfree(clp->cl_name.data); |
@@ -375,18 +388,6 @@ put_nfs4_client(struct nfs4_client *clp) | |||
375 | } | 388 | } |
376 | 389 | ||
377 | static void | 390 | static void |
378 | shutdown_callback_client(struct nfs4_client *clp) | ||
379 | { | ||
380 | struct rpc_clnt *clnt = clp->cl_callback.cb_client; | ||
381 | |||
382 | /* shutdown rpc client, ending any outstanding recall rpcs */ | ||
383 | if (clnt) { | ||
384 | clp->cl_callback.cb_client = NULL; | ||
385 | rpc_shutdown_client(clnt); | ||
386 | } | ||
387 | } | ||
388 | |||
389 | static void | ||
390 | expire_client(struct nfs4_client *clp) | 391 | expire_client(struct nfs4_client *clp) |
391 | { | 392 | { |
392 | struct nfs4_stateowner *sop; | 393 | struct nfs4_stateowner *sop; |
@@ -396,8 +397,6 @@ expire_client(struct nfs4_client *clp) | |||
396 | dprintk("NFSD: expire_client cl_count %d\n", | 397 | dprintk("NFSD: expire_client cl_count %d\n", |
397 | atomic_read(&clp->cl_count)); | 398 | atomic_read(&clp->cl_count)); |
398 | 399 | ||
399 | shutdown_callback_client(clp); | ||
400 | |||
401 | INIT_LIST_HEAD(&reaplist); | 400 | INIT_LIST_HEAD(&reaplist); |
402 | spin_lock(&recall_lock); | 401 | spin_lock(&recall_lock); |
403 | while (!list_empty(&clp->cl_delegations)) { | 402 | while (!list_empty(&clp->cl_delegations)) { |