diff options
-rw-r--r-- | fs/nfsd/nfs4callback.c | 54 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 34 | ||||
-rw-r--r-- | fs/nfsd/state.h | 5 |
3 files changed, 73 insertions, 20 deletions
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 91eb2ea9ef0a..e078c747f49d 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -32,6 +32,7 @@ | |||
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <linux/sunrpc/clnt.h> | 34 | #include <linux/sunrpc/clnt.h> |
35 | #include <linux/sunrpc/svc_xprt.h> | ||
35 | #include "nfsd.h" | 36 | #include "nfsd.h" |
36 | #include "state.h" | 37 | #include "state.h" |
37 | 38 | ||
@@ -692,11 +693,41 @@ static const struct rpc_call_ops nfsd4_cb_recall_ops = { | |||
692 | .rpc_release = nfsd4_cb_recall_release, | 693 | .rpc_release = nfsd4_cb_recall_release, |
693 | }; | 694 | }; |
694 | 695 | ||
696 | static struct workqueue_struct *callback_wq; | ||
697 | |||
698 | int nfsd4_create_callback_queue(void) | ||
699 | { | ||
700 | callback_wq = create_singlethread_workqueue("nfsd4_callbacks"); | ||
701 | if (!callback_wq) | ||
702 | return -ENOMEM; | ||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | void nfsd4_destroy_callback_queue(void) | ||
707 | { | ||
708 | destroy_workqueue(callback_wq); | ||
709 | } | ||
710 | |||
711 | void nfsd4_set_callback_client(struct nfs4_client *clp, struct rpc_clnt | ||
712 | *new) | ||
713 | { | ||
714 | struct rpc_clnt *old = clp->cl_cb_conn.cb_client; | ||
715 | |||
716 | clp->cl_cb_conn.cb_client = new; | ||
717 | /* | ||
718 | * After this, any work that saw the old value of cb_client will | ||
719 | * be gone: | ||
720 | */ | ||
721 | flush_workqueue(callback_wq); | ||
722 | /* So we can safely shut it down: */ | ||
723 | if (old) | ||
724 | rpc_shutdown_client(old); | ||
725 | } | ||
726 | |||
695 | /* | 727 | /* |
696 | * called with dp->dl_count inc'ed. | 728 | * called with dp->dl_count inc'ed. |
697 | */ | 729 | */ |
698 | void | 730 | static void _nfsd4_cb_recall(struct nfs4_delegation *dp) |
699 | nfsd4_cb_recall(struct nfs4_delegation *dp) | ||
700 | { | 731 | { |
701 | struct nfs4_client *clp = dp->dl_client; | 732 | struct nfs4_client *clp = dp->dl_client; |
702 | struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client; | 733 | struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client; |
@@ -707,6 +738,9 @@ nfsd4_cb_recall(struct nfs4_delegation *dp) | |||
707 | }; | 738 | }; |
708 | int status; | 739 | int status; |
709 | 740 | ||
741 | if (clnt == NULL) | ||
742 | return; /* Client is shutting down; give up. */ | ||
743 | |||
710 | args->args_op = dp; | 744 | args->args_op = dp; |
711 | msg.rpc_argp = args; | 745 | msg.rpc_argp = args; |
712 | dp->dl_retries = 1; | 746 | dp->dl_retries = 1; |
@@ -717,3 +751,19 @@ nfsd4_cb_recall(struct nfs4_delegation *dp) | |||
717 | nfs4_put_delegation(dp); | 751 | nfs4_put_delegation(dp); |
718 | } | 752 | } |
719 | } | 753 | } |
754 | |||
755 | void nfsd4_do_callback_rpc(struct work_struct *w) | ||
756 | { | ||
757 | /* XXX: for now, just send off delegation recall. */ | ||
758 | /* In future, generalize to handle any sort of callback. */ | ||
759 | struct nfsd4_callback *c = container_of(w, struct nfsd4_callback, cb_work); | ||
760 | struct nfs4_delegation *dp = container_of(c, struct nfs4_delegation, dl_recall); | ||
761 | |||
762 | _nfsd4_cb_recall(dp); | ||
763 | } | ||
764 | |||
765 | |||
766 | void nfsd4_cb_recall(struct nfs4_delegation *dp) | ||
767 | { | ||
768 | queue_work(callback_wq, &dp->dl_recall.cb_work); | ||
769 | } | ||
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 | ||
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index b85437982a8d..c4c92aea8f39 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -77,6 +77,7 @@ struct nfs4_rpc_args { | |||
77 | 77 | ||
78 | struct nfsd4_callback { | 78 | struct nfsd4_callback { |
79 | struct nfs4_rpc_args cb_args; | 79 | struct nfs4_rpc_args cb_args; |
80 | struct work_struct cb_work; | ||
80 | }; | 81 | }; |
81 | 82 | ||
82 | struct nfs4_delegation { | 83 | struct nfs4_delegation { |
@@ -391,7 +392,11 @@ extern void put_nfs4_client(struct nfs4_client *clp); | |||
391 | extern void nfs4_free_stateowner(struct kref *kref); | 392 | extern void nfs4_free_stateowner(struct kref *kref); |
392 | extern int set_callback_cred(void); | 393 | extern int set_callback_cred(void); |
393 | extern void nfsd4_probe_callback(struct nfs4_client *clp); | 394 | extern void nfsd4_probe_callback(struct nfs4_client *clp); |
395 | extern void nfsd4_do_callback_rpc(struct work_struct *); | ||
394 | extern void nfsd4_cb_recall(struct nfs4_delegation *dp); | 396 | extern void nfsd4_cb_recall(struct nfs4_delegation *dp); |
397 | extern int nfsd4_create_callback_queue(void); | ||
398 | extern void nfsd4_destroy_callback_queue(void); | ||
399 | extern void nfsd4_set_callback_client(struct nfs4_client *, struct rpc_clnt *); | ||
395 | extern void nfs4_put_delegation(struct nfs4_delegation *dp); | 400 | extern void nfs4_put_delegation(struct nfs4_delegation *dp); |
396 | extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); | 401 | extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); |
397 | extern void nfsd4_init_recdir(char *recdir_name); | 402 | extern void nfsd4_init_recdir(char *recdir_name); |