diff options
author | J. Bruce Fields <bfields@citi.umich.edu> | 2010-06-15 17:25:45 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2011-01-11 15:04:10 -0500 |
commit | dcbeaa68dbbdacbbb330a86c7fc95a28473fc209 (patch) | |
tree | 5ef2b2c1e65d22275a867700551e4a663c4a98ad /fs | |
parent | 1d1bc8f2074f0b728dfca2a3c16f2f5a3f298ffc (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')
-rw-r--r-- | fs/nfsd/nfs4callback.c | 36 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 16 |
2 files changed, 43 insertions, 9 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 | ||
476 | static int setup_callback_client(struct nfs4_client *clp, | 476 | static 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: */ | ||
763 | static 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 | |||
759 | static void nfsd4_process_cb_update(struct nfsd4_callback *cb) | 777 | static 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 | } |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 956174f488a7..290370bc9ae7 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -642,6 +642,7 @@ static void nfsd4_conn_lost(struct svc_xpt_user *u) | |||
642 | free_conn(c); | 642 | free_conn(c); |
643 | } | 643 | } |
644 | spin_unlock(&clp->cl_lock); | 644 | spin_unlock(&clp->cl_lock); |
645 | /* XXX: mark callback for update, probe callback */ | ||
645 | } | 646 | } |
646 | 647 | ||
647 | static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) | 648 | static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) |
@@ -790,16 +791,19 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n | |||
790 | free_session(&new->se_ref); | 791 | free_session(&new->se_ref); |
791 | return NULL; | 792 | return NULL; |
792 | } | 793 | } |
793 | if (!clp->cl_cb_session && (cses->flags & SESSION4_BACK_CHAN)) { | 794 | if (cses->flags & SESSION4_BACK_CHAN) { |
794 | struct sockaddr *sa = svc_addr(rqstp); | 795 | struct sockaddr *sa = svc_addr(rqstp); |
795 | 796 | /* | |
796 | clp->cl_cb_session = new; | 797 | * This is a little silly; with sessions there's no real |
797 | clp->cl_cb_conn.cb_xprt = rqstp->rq_xprt; | 798 | * use for the callback address. Use the peer address |
798 | svc_xprt_get(rqstp->rq_xprt); | 799 | * as a reasonable default for now, but consider fixing |
800 | * the rpc client not to require an address in the | ||
801 | * future: | ||
802 | */ | ||
799 | rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); | 803 | rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); |
800 | clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); | 804 | clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); |
801 | nfsd4_probe_callback(clp); | ||
802 | } | 805 | } |
806 | nfsd4_probe_callback(clp); | ||
803 | return new; | 807 | return new; |
804 | } | 808 | } |
805 | 809 | ||