Skip to content

Commit dcbeaa6

Browse files
J. Bruce FieldsJ. Bruce Fields
authored andcommitted
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 <[email protected]>
1 parent 1d1bc8f commit dcbeaa6

File tree

2 files changed

+43
-9
lines changed

2 files changed

+43
-9
lines changed

fs/nfsd/nfs4callback.c

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -473,8 +473,7 @@ static int max_cb_time(void)
473473
/* Reference counting, callback cleanup, etc., all look racy as heck.
474474
* And why is cl_cb_set an atomic? */
475475

476-
static int setup_callback_client(struct nfs4_client *clp,
477-
struct nfs4_cb_conn *conn)
476+
static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses)
478477
{
479478
struct rpc_timeout timeparms = {
480479
.to_initval = max_cb_time(),
@@ -501,6 +500,10 @@ static int setup_callback_client(struct nfs4_client *clp,
501500
args.protocol = XPRT_TRANSPORT_TCP;
502501
clp->cl_cb_ident = conn->cb_ident;
503502
} 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;
504507
args.bc_xprt = conn->cb_xprt;
505508
args.prognumber = clp->cl_cb_session->se_cb_prog;
506509
args.protocol = XPRT_TRANSPORT_BC_TCP;
@@ -756,10 +759,27 @@ static void nfsd4_release_cb(struct nfsd4_callback *cb)
756759
cb->cb_ops->rpc_release(cb);
757760
}
758761

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+
759777
static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
760778
{
761779
struct nfs4_cb_conn conn;
762780
struct nfs4_client *clp = cb->cb_clp;
781+
struct nfsd4_session *ses = NULL;
782+
struct nfsd4_conn *c;
763783
int err;
764784

765785
/*
@@ -770,6 +790,10 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
770790
rpc_shutdown_client(clp->cl_cb_client);
771791
clp->cl_cb_client = NULL;
772792
}
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+
}
773797
if (test_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags))
774798
return;
775799
spin_lock(&clp->cl_lock);
@@ -780,9 +804,15 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
780804
BUG_ON(!clp->cl_cb_flags);
781805
clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
782806
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+
}
783813
spin_unlock(&clp->cl_lock);
784814

785-
err = setup_callback_client(clp, &conn);
815+
err = setup_callback_client(clp, &conn, ses);
786816
if (err)
787817
warn_no_callback_path(clp, err);
788818
}

fs/nfsd/nfs4state.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,7 @@ static void nfsd4_conn_lost(struct svc_xpt_user *u)
642642
free_conn(c);
643643
}
644644
spin_unlock(&clp->cl_lock);
645+
/* XXX: mark callback for update, probe callback */
645646
}
646647

647648
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
790791
free_session(&new->se_ref);
791792
return NULL;
792793
}
793-
if (!clp->cl_cb_session && (cses->flags & SESSION4_BACK_CHAN)) {
794+
if (cses->flags & SESSION4_BACK_CHAN) {
794795
struct sockaddr *sa = svc_addr(rqstp);
795-
796-
clp->cl_cb_session = new;
797-
clp->cl_cb_conn.cb_xprt = rqstp->rq_xprt;
798-
svc_xprt_get(rqstp->rq_xprt);
796+
/*
797+
* This is a little silly; with sessions there's no real
798+
* use for the callback address. Use the peer address
799+
* as a reasonable default for now, but consider fixing
800+
* the rpc client not to require an address in the
801+
* future:
802+
*/
799803
rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
800804
clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
801-
nfsd4_probe_callback(clp);
802805
}
806+
nfsd4_probe_callback(clp);
803807
return new;
804808
}
805809

0 commit comments

Comments
 (0)