aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4callback.c
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@citi.umich.edu>2010-06-15 17:25:45 -0400
committerJ. Bruce Fields <bfields@redhat.com>2011-01-11 15:04:10 -0500
commitdcbeaa68dbbdacbbb330a86c7fc95a28473fc209 (patch)
tree5ef2b2c1e65d22275a867700551e4a663c4a98ad /fs/nfsd/nfs4callback.c
parent1d1bc8f2074f0b728dfca2a3c16f2f5a3f298ffc (diff)
nfsd4: allow backchannel recovery
Now that we have a list of connections to choose from, we can teach the callback code to just pick a suitable connection and use that, instead of insisting on forever using the connection that the first create_session was sent with. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'fs/nfsd/nfs4callback.c')
-rw-r--r--fs/nfsd/nfs4callback.c36
1 files changed, 33 insertions, 3 deletions
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index dd183af24fe6..18b740bd29ac 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -473,8 +473,7 @@ static int max_cb_time(void)
473/* Reference counting, callback cleanup, etc., all look racy as heck. 473/* Reference counting, callback cleanup, etc., all look racy as heck.
474 * And why is cl_cb_set an atomic? */ 474 * And why is cl_cb_set an atomic? */
475 475
476static int setup_callback_client(struct nfs4_client *clp, 476static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses)
477 struct nfs4_cb_conn *conn)
478{ 477{
479 struct rpc_timeout timeparms = { 478 struct rpc_timeout timeparms = {
480 .to_initval = max_cb_time(), 479 .to_initval = max_cb_time(),
@@ -501,6 +500,10 @@ static int setup_callback_client(struct nfs4_client *clp,
501 args.protocol = XPRT_TRANSPORT_TCP; 500 args.protocol = XPRT_TRANSPORT_TCP;
502 clp->cl_cb_ident = conn->cb_ident; 501 clp->cl_cb_ident = conn->cb_ident;
503 } else { 502 } else {
503 if (!conn->cb_xprt)
504 return -EINVAL;
505 clp->cl_cb_conn.cb_xprt = conn->cb_xprt;
506 clp->cl_cb_session = ses;
504 args.bc_xprt = conn->cb_xprt; 507 args.bc_xprt = conn->cb_xprt;
505 args.prognumber = clp->cl_cb_session->se_cb_prog; 508 args.prognumber = clp->cl_cb_session->se_cb_prog;
506 args.protocol = XPRT_TRANSPORT_BC_TCP; 509 args.protocol = XPRT_TRANSPORT_BC_TCP;
@@ -756,10 +759,27 @@ static void nfsd4_release_cb(struct nfsd4_callback *cb)
756 cb->cb_ops->rpc_release(cb); 759 cb->cb_ops->rpc_release(cb);
757} 760}
758 761
762/* requires cl_lock: */
763static struct nfsd4_conn * __nfsd4_find_backchannel(struct nfs4_client *clp)
764{
765 struct nfsd4_session *s;
766 struct nfsd4_conn *c;
767
768 list_for_each_entry(s, &clp->cl_sessions, se_perclnt) {
769 list_for_each_entry(c, &s->se_conns, cn_persession) {
770 if (c->cn_flags & NFS4_CDFC4_BACK)
771 return c;
772 }
773 }
774 return NULL;
775}
776
759static void nfsd4_process_cb_update(struct nfsd4_callback *cb) 777static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
760{ 778{
761 struct nfs4_cb_conn conn; 779 struct nfs4_cb_conn conn;
762 struct nfs4_client *clp = cb->cb_clp; 780 struct nfs4_client *clp = cb->cb_clp;
781 struct nfsd4_session *ses = NULL;
782 struct nfsd4_conn *c;
763 int err; 783 int err;
764 784
765 /* 785 /*
@@ -770,6 +790,10 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
770 rpc_shutdown_client(clp->cl_cb_client); 790 rpc_shutdown_client(clp->cl_cb_client);
771 clp->cl_cb_client = NULL; 791 clp->cl_cb_client = NULL;
772 } 792 }
793 if (clp->cl_cb_conn.cb_xprt) {
794 svc_xprt_put(clp->cl_cb_conn.cb_xprt);
795 clp->cl_cb_conn.cb_xprt = NULL;
796 }
773 if (test_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags)) 797 if (test_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags))
774 return; 798 return;
775 spin_lock(&clp->cl_lock); 799 spin_lock(&clp->cl_lock);
@@ -780,9 +804,15 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
780 BUG_ON(!clp->cl_cb_flags); 804 BUG_ON(!clp->cl_cb_flags);
781 clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags); 805 clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
782 memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn)); 806 memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn));
807 c = __nfsd4_find_backchannel(clp);
808 if (c) {
809 svc_xprt_get(c->cn_xprt);
810 conn.cb_xprt = c->cn_xprt;
811 ses = c->cn_session;
812 }
783 spin_unlock(&clp->cl_lock); 813 spin_unlock(&clp->cl_lock);
784 814
785 err = setup_callback_client(clp, &conn); 815 err = setup_callback_client(clp, &conn, ses);
786 if (err) 816 if (err)
787 warn_no_callback_path(clp, err); 817 warn_no_callback_path(clp, err);
788} 818}