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>
This commit is contained in:
Родитель
1d1bc8f207
Коммит
dcbeaa68db
|
@ -473,8 +473,7 @@ static int max_cb_time(void)
|
||||||
/* Reference counting, callback cleanup, etc., all look racy as heck.
|
/* Reference counting, callback cleanup, etc., all look racy as heck.
|
||||||
* And why is cl_cb_set an atomic? */
|
* And why is cl_cb_set an atomic? */
|
||||||
|
|
||||||
static int setup_callback_client(struct nfs4_client *clp,
|
static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses)
|
||||||
struct nfs4_cb_conn *conn)
|
|
||||||
{
|
{
|
||||||
struct rpc_timeout timeparms = {
|
struct rpc_timeout timeparms = {
|
||||||
.to_initval = max_cb_time(),
|
.to_initval = max_cb_time(),
|
||||||
|
@ -501,6 +500,10 @@ static int setup_callback_client(struct nfs4_client *clp,
|
||||||
args.protocol = XPRT_TRANSPORT_TCP;
|
args.protocol = XPRT_TRANSPORT_TCP;
|
||||||
clp->cl_cb_ident = conn->cb_ident;
|
clp->cl_cb_ident = conn->cb_ident;
|
||||||
} else {
|
} else {
|
||||||
|
if (!conn->cb_xprt)
|
||||||
|
return -EINVAL;
|
||||||
|
clp->cl_cb_conn.cb_xprt = conn->cb_xprt;
|
||||||
|
clp->cl_cb_session = ses;
|
||||||
args.bc_xprt = conn->cb_xprt;
|
args.bc_xprt = conn->cb_xprt;
|
||||||
args.prognumber = clp->cl_cb_session->se_cb_prog;
|
args.prognumber = clp->cl_cb_session->se_cb_prog;
|
||||||
args.protocol = XPRT_TRANSPORT_BC_TCP;
|
args.protocol = XPRT_TRANSPORT_BC_TCP;
|
||||||
|
@ -756,10 +759,27 @@ static void nfsd4_release_cb(struct nfsd4_callback *cb)
|
||||||
cb->cb_ops->rpc_release(cb);
|
cb->cb_ops->rpc_release(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* requires cl_lock: */
|
||||||
|
static struct nfsd4_conn * __nfsd4_find_backchannel(struct nfs4_client *clp)
|
||||||
|
{
|
||||||
|
struct nfsd4_session *s;
|
||||||
|
struct nfsd4_conn *c;
|
||||||
|
|
||||||
|
list_for_each_entry(s, &clp->cl_sessions, se_perclnt) {
|
||||||
|
list_for_each_entry(c, &s->se_conns, cn_persession) {
|
||||||
|
if (c->cn_flags & NFS4_CDFC4_BACK)
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
|
static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
|
||||||
{
|
{
|
||||||
struct nfs4_cb_conn conn;
|
struct nfs4_cb_conn conn;
|
||||||
struct nfs4_client *clp = cb->cb_clp;
|
struct nfs4_client *clp = cb->cb_clp;
|
||||||
|
struct nfsd4_session *ses = NULL;
|
||||||
|
struct nfsd4_conn *c;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -770,6 +790,10 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
|
||||||
rpc_shutdown_client(clp->cl_cb_client);
|
rpc_shutdown_client(clp->cl_cb_client);
|
||||||
clp->cl_cb_client = NULL;
|
clp->cl_cb_client = NULL;
|
||||||
}
|
}
|
||||||
|
if (clp->cl_cb_conn.cb_xprt) {
|
||||||
|
svc_xprt_put(clp->cl_cb_conn.cb_xprt);
|
||||||
|
clp->cl_cb_conn.cb_xprt = NULL;
|
||||||
|
}
|
||||||
if (test_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags))
|
if (test_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags))
|
||||||
return;
|
return;
|
||||||
spin_lock(&clp->cl_lock);
|
spin_lock(&clp->cl_lock);
|
||||||
|
@ -780,9 +804,15 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
|
||||||
BUG_ON(!clp->cl_cb_flags);
|
BUG_ON(!clp->cl_cb_flags);
|
||||||
clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
|
clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
|
||||||
memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn));
|
memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn));
|
||||||
|
c = __nfsd4_find_backchannel(clp);
|
||||||
|
if (c) {
|
||||||
|
svc_xprt_get(c->cn_xprt);
|
||||||
|
conn.cb_xprt = c->cn_xprt;
|
||||||
|
ses = c->cn_session;
|
||||||
|
}
|
||||||
spin_unlock(&clp->cl_lock);
|
spin_unlock(&clp->cl_lock);
|
||||||
|
|
||||||
err = setup_callback_client(clp, &conn);
|
err = setup_callback_client(clp, &conn, ses);
|
||||||
if (err)
|
if (err)
|
||||||
warn_no_callback_path(clp, err);
|
warn_no_callback_path(clp, err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -642,6 +642,7 @@ static void nfsd4_conn_lost(struct svc_xpt_user *u)
|
||||||
free_conn(c);
|
free_conn(c);
|
||||||
}
|
}
|
||||||
spin_unlock(&clp->cl_lock);
|
spin_unlock(&clp->cl_lock);
|
||||||
|
/* XXX: mark callback for update, probe callback */
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags)
|
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
|
||||||
free_session(&new->se_ref);
|
free_session(&new->se_ref);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!clp->cl_cb_session && (cses->flags & SESSION4_BACK_CHAN)) {
|
if (cses->flags & SESSION4_BACK_CHAN) {
|
||||||
struct sockaddr *sa = svc_addr(rqstp);
|
struct sockaddr *sa = svc_addr(rqstp);
|
||||||
|
/*
|
||||||
clp->cl_cb_session = new;
|
* This is a little silly; with sessions there's no real
|
||||||
clp->cl_cb_conn.cb_xprt = rqstp->rq_xprt;
|
* use for the callback address. Use the peer address
|
||||||
svc_xprt_get(rqstp->rq_xprt);
|
* as a reasonable default for now, but consider fixing
|
||||||
|
* the rpc client not to require an address in the
|
||||||
|
* future:
|
||||||
|
*/
|
||||||
rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
|
rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
|
||||||
clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
|
clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
|
||||||
nfsd4_probe_callback(clp);
|
|
||||||
}
|
}
|
||||||
|
nfsd4_probe_callback(clp);
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче