aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfsd/nfs4callback.c54
-rw-r--r--fs/nfsd/nfs4state.c34
-rw-r--r--fs/nfsd/state.h5
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
696static struct workqueue_struct *callback_wq;
697
698int 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
706void nfsd4_destroy_callback_queue(void)
707{
708 destroy_workqueue(callback_wq);
709}
710
711void 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 */
698void 730static void _nfsd4_cb_recall(struct nfs4_delegation *dp)
699nfsd4_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
755void 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
766void 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
682static void
683shutdown_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
697static inline void 683static inline void
698free_client(struct nfs4_client *clp) 684free_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;
1398out: 1384out:
@@ -4004,16 +3990,27 @@ set_max_delegations(void)
4004static int 3990static 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;
4011out_free_laundry:
4012 destroy_workqueue(laundry_wq);
4013 return ret;
4017} 4014}
4018 4015
4019int 4016int
@@ -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
78struct nfsd4_callback { 78struct 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
82struct nfs4_delegation { 83struct nfs4_delegation {
@@ -391,7 +392,11 @@ extern void put_nfs4_client(struct nfs4_client *clp);
391extern void nfs4_free_stateowner(struct kref *kref); 392extern void nfs4_free_stateowner(struct kref *kref);
392extern int set_callback_cred(void); 393extern int set_callback_cred(void);
393extern void nfsd4_probe_callback(struct nfs4_client *clp); 394extern void nfsd4_probe_callback(struct nfs4_client *clp);
395extern void nfsd4_do_callback_rpc(struct work_struct *);
394extern void nfsd4_cb_recall(struct nfs4_delegation *dp); 396extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
397extern int nfsd4_create_callback_queue(void);
398extern void nfsd4_destroy_callback_queue(void);
399extern void nfsd4_set_callback_client(struct nfs4_client *, struct rpc_clnt *);
395extern void nfs4_put_delegation(struct nfs4_delegation *dp); 400extern void nfs4_put_delegation(struct nfs4_delegation *dp);
396extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); 401extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
397extern void nfsd4_init_recdir(char *recdir_name); 402extern void nfsd4_init_recdir(char *recdir_name);