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); |
