diff options
author | J. Bruce Fields <bfields@citi.umich.edu> | 2010-03-03 14:52:55 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2010-04-22 11:34:01 -0400 |
commit | b5a1a81e5c25fb6bb3fdc1812ba69ff6ab638fcf (patch) | |
tree | c524a75d111f4060eb985161478362ac18c17169 /fs/nfsd/nfs4state.c | |
parent | 3c4ab2aaa90826060b1e8d4036f9bb8325f8759e (diff) |
nfsd4: don't sleep in lease-break callback
The NFSv4 server's fl_break callback can sleep (dropping the BKL), in
order to allocate a new rpc task to send a recall to the client.
As far as I can tell this doesn't cause any races in the current code,
but the analysis is difficult. Also, the sleep here may complicate the
move away from the BKL.
So, just schedule some work to do the job for us instead. The work will
later also prove useful for restarting a call after the callback
information is changed.
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 34 |
1 files changed, 16 insertions, 18 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 5051ade30dfb..adc51d10d435 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -198,6 +198,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
198 | atomic_set(&dp->dl_count, 1); | 198 | atomic_set(&dp->dl_count, 1); |
199 | list_add(&dp->dl_perfile, &fp->fi_delegations); | 199 | list_add(&dp->dl_perfile, &fp->fi_delegations); |
200 | list_add(&dp->dl_perclnt, &clp->cl_delegations); | 200 | list_add(&dp->dl_perclnt, &clp->cl_delegations); |
201 | INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc); | ||
201 | return dp; | 202 | return dp; |
202 | } | 203 | } |
203 | 204 | ||
@@ -679,21 +680,6 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) | |||
679 | return clp; | 680 | return clp; |
680 | } | 681 | } |
681 | 682 | ||
682 | static void | ||
683 | shutdown_callback_client(struct nfs4_client *clp) | ||
684 | { | ||
685 | struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client; | ||
686 | |||
687 | if (clnt) { | ||
688 | /* | ||
689 | * Callback threads take a reference on the client, so there | ||
690 | * should be no outstanding callbacks at this point. | ||
691 | */ | ||
692 | clp->cl_cb_conn.cb_client = NULL; | ||
693 | rpc_shutdown_client(clnt); | ||
694 | } | ||
695 | } | ||
696 | |||
697 | static inline void | 683 | static inline void |
698 | free_client(struct nfs4_client *clp) | 684 | free_client(struct nfs4_client *clp) |
699 | { | 685 | { |
@@ -746,7 +732,7 @@ expire_client(struct nfs4_client *clp) | |||
746 | se_perclnt); | 732 | se_perclnt); |
747 | release_session(ses); | 733 | release_session(ses); |
748 | } | 734 | } |
749 | shutdown_callback_client(clp); | 735 | nfsd4_set_callback_client(clp, NULL); |
750 | if (clp->cl_cb_xprt) | 736 | if (clp->cl_cb_xprt) |
751 | svc_xprt_put(clp->cl_cb_xprt); | 737 | svc_xprt_put(clp->cl_cb_xprt); |
752 | put_nfs4_client(clp); | 738 | put_nfs4_client(clp); |
@@ -1392,7 +1378,7 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
1392 | spin_unlock(&sessionid_lock); | 1378 | spin_unlock(&sessionid_lock); |
1393 | 1379 | ||
1394 | /* wait for callbacks */ | 1380 | /* wait for callbacks */ |
1395 | shutdown_callback_client(ses->se_client); | 1381 | nfsd4_set_callback_client(ses->se_client, NULL); |
1396 | nfsd4_put_session(ses); | 1382 | nfsd4_put_session(ses); |
1397 | status = nfs_ok; | 1383 | status = nfs_ok; |
1398 | out: | 1384 | out: |
@@ -4004,16 +3990,27 @@ set_max_delegations(void) | |||
4004 | static int | 3990 | static int |
4005 | __nfs4_state_start(void) | 3991 | __nfs4_state_start(void) |
4006 | { | 3992 | { |
3993 | int ret; | ||
3994 | |||
4007 | boot_time = get_seconds(); | 3995 | boot_time = get_seconds(); |
4008 | locks_start_grace(&nfsd4_manager); | 3996 | locks_start_grace(&nfsd4_manager); |
4009 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", | 3997 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", |
4010 | nfsd4_grace); | 3998 | nfsd4_grace); |
3999 | ret = set_callback_cred(); | ||
4000 | if (ret) | ||
4001 | return -ENOMEM; | ||
4011 | laundry_wq = create_singlethread_workqueue("nfsd4"); | 4002 | laundry_wq = create_singlethread_workqueue("nfsd4"); |
4012 | if (laundry_wq == NULL) | 4003 | if (laundry_wq == NULL) |
4013 | return -ENOMEM; | 4004 | return -ENOMEM; |
4005 | ret = nfsd4_create_callback_queue(); | ||
4006 | if (ret) | ||
4007 | goto out_free_laundry; | ||
4014 | queue_delayed_work(laundry_wq, &laundromat_work, nfsd4_grace * HZ); | 4008 | queue_delayed_work(laundry_wq, &laundromat_work, nfsd4_grace * HZ); |
4015 | set_max_delegations(); | 4009 | set_max_delegations(); |
4016 | return set_callback_cred(); | 4010 | return 0; |
4011 | out_free_laundry: | ||
4012 | destroy_workqueue(laundry_wq); | ||
4013 | return ret; | ||
4017 | } | 4014 | } |
4018 | 4015 | ||
4019 | int | 4016 | int |
@@ -4075,6 +4072,7 @@ nfs4_state_shutdown(void) | |||
4075 | nfs4_lock_state(); | 4072 | nfs4_lock_state(); |
4076 | nfs4_release_reclaim(); | 4073 | nfs4_release_reclaim(); |
4077 | __nfs4_state_shutdown(); | 4074 | __nfs4_state_shutdown(); |
4075 | nfsd4_destroy_callback_queue(); | ||
4078 | nfs4_unlock_state(); | 4076 | nfs4_unlock_state(); |
4079 | } | 4077 | } |
4080 | 4078 | ||