* server sessions patches
@ 2011-01-11 16:21 J. Bruce Fields
2011-01-11 16:21 ` [PATCH 01/14] nfsd4: modify session list under cl_lock J. Bruce Fields
` (13 more replies)
0 siblings, 14 replies; 15+ messages in thread
From: J. Bruce Fields @ 2011-01-11 16:21 UTC (permalink / raw)
To: linux-nfs
Some more patches implementing BIND_CONN_TO_SESSION and related stuff.
The server should be able to switch to a different backchannel now on
operations that explicitly add or remove sessions or connections, or
when the rpc layer notices a connection has gone down.
Testing from the Windows people suggests we should also switch on
callback timeouts to deal with cases where one connection is unreliable.
I'm not quite sure what to do there.
I was planning on merging this for 2.6.38. I let it get a little late.
But this seems low-risk for versions < 4.1, so I might still go ahead.
--b.
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 01/14] nfsd4: modify session list under cl_lock
2011-01-11 16:21 server sessions patches J. Bruce Fields
@ 2011-01-11 16:21 ` J. Bruce Fields
2011-01-11 16:21 ` [PATCH 02/14] nfsd4: support BIND_CONN_TO_SESSION J. Bruce Fields
` (12 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: J. Bruce Fields @ 2011-01-11 16:21 UTC (permalink / raw)
To: linux-nfs; +Cc: J. Bruce Fields
From: J. Bruce Fields <bfields@citi.umich.edu>
We want to traverse this from the callback code.
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
---
fs/nfsd/nfs4state.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index b583e4e..3cf9900 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -771,7 +771,9 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n
idx = hash_sessionid(&new->se_sessionid);
spin_lock(&client_lock);
list_add(&new->se_hash, &sessionid_hashtbl[idx]);
+ spin_lock(&clp->cl_lock);
list_add(&new->se_perclnt, &clp->cl_sessions);
+ spin_unlock(&clp->cl_lock);
spin_unlock(&client_lock);
status = nfsd4_new_conn(rqstp, new);
@@ -819,7 +821,9 @@ static void
unhash_session(struct nfsd4_session *ses)
{
list_del(&ses->se_hash);
+ spin_lock(&ses->se_client->cl_lock);
list_del(&ses->se_perclnt);
+ spin_unlock(&ses->se_client->cl_lock);
}
/* must be called under the client_lock */
@@ -925,8 +929,10 @@ unhash_client_locked(struct nfs4_client *clp)
mark_client_expired(clp);
list_del(&clp->cl_lru);
+ spin_lock(&clp->cl_lock);
list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
list_del_init(&ses->se_hash);
+ spin_unlock(&clp->cl_lock);
}
static void
--
1.7.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 02/14] nfsd4: support BIND_CONN_TO_SESSION
2011-01-11 16:21 server sessions patches J. Bruce Fields
2011-01-11 16:21 ` [PATCH 01/14] nfsd4: modify session list under cl_lock J. Bruce Fields
@ 2011-01-11 16:21 ` J. Bruce Fields
2011-01-11 16:21 ` [PATCH 03/14] nfsd4: allow backchannel recovery J. Bruce Fields
` (11 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: J. Bruce Fields @ 2011-01-11 16:21 UTC (permalink / raw)
To: linux-nfs; +Cc: J. Bruce Fields
Basic xdr and processing for BIND_CONN_TO_SESSION. This adds a
connection to the list of connections associated with a session.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
fs/nfsd/nfs4proc.c | 9 ++++++-
fs/nfsd/nfs4state.c | 59 ++++++++++++++++++++++++++++++++++++++++++++-----
fs/nfsd/nfs4xdr.c | 34 +++++++++++++++++++++++++++-
fs/nfsd/state.h | 5 ++++
fs/nfsd/xdr4.h | 2 +
include/linux/nfs4.h | 3 ++
6 files changed, 102 insertions(+), 10 deletions(-)
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index fd6694b..db52546 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1004,8 +1004,8 @@ static const char *nfsd4_op_name(unsigned opnum);
* Also note, enforced elsewhere:
* - SEQUENCE other than as first op results in
* NFS4ERR_SEQUENCE_POS. (Enforced in nfsd4_sequence().)
- * - BIND_CONN_TO_SESSION must be the only op in its compound
- * (Will be enforced in nfsd4_bind_conn_to_session().)
+ * - BIND_CONN_TO_SESSION must be the only op in its compound.
+ * (Enforced in nfsd4_bind_conn_to_session().)
* - DESTROY_SESSION must be the final operation in a compound, if
* sessionid's in SEQUENCE and DESTROY_SESSION are the same.
* (Enforced in nfsd4_destroy_session().)
@@ -1326,6 +1326,11 @@ static struct nfsd4_operation nfsd4_ops[] = {
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
.op_name = "OP_EXCHANGE_ID",
},
+ [OP_BIND_CONN_TO_SESSION] = {
+ .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session,
+ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
+ .op_name = "OP_BIND_CONN_TO_SESSION",
+ },
[OP_CREATE_SESSION] = {
.op_func = (nfsd4op_func)nfsd4_create_session,
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 3cf9900..956174f 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -679,15 +679,12 @@ static int nfsd4_register_conn(struct nfsd4_conn *conn)
return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
}
-static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses)
+static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, u32 dir)
{
struct nfsd4_conn *conn;
- u32 flags = NFS4_CDFC4_FORE;
int ret;
- if (ses->se_flags & SESSION4_BACK_CHAN)
- flags |= NFS4_CDFC4_BACK;
- conn = alloc_conn(rqstp, flags);
+ conn = alloc_conn(rqstp, dir);
if (!conn)
return nfserr_jukebox;
nfsd4_hash_conn(conn, ses);
@@ -698,6 +695,17 @@ static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses)
return nfs_ok;
}
+static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses)
+{
+ u32 dir = NFS4_CDFC4_FORE;
+
+ if (ses->se_flags & SESSION4_BACK_CHAN)
+ dir |= NFS4_CDFC4_BACK;
+
+ return nfsd4_new_conn(rqstp, ses, dir);
+}
+
+/* must be called under client_lock */
static void nfsd4_del_conns(struct nfsd4_session *s)
{
struct nfs4_client *clp = s->se_client;
@@ -776,7 +784,7 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n
spin_unlock(&clp->cl_lock);
spin_unlock(&client_lock);
- status = nfsd4_new_conn(rqstp, new);
+ status = nfsd4_new_conn_from_crses(rqstp, new);
/* whoops: benny points out, status is ignored! (err, or bogus) */
if (status) {
free_session(&new->se_ref);
@@ -1597,6 +1605,45 @@ static bool nfsd4_last_compound_op(struct svc_rqst *rqstp)
return argp->opcnt == resp->opcnt;
}
+static __be32 nfsd4_map_bcts_dir(u32 *dir)
+{
+ switch (*dir) {
+ case NFS4_CDFC4_FORE:
+ case NFS4_CDFC4_BACK:
+ return nfs_ok;
+ case NFS4_CDFC4_FORE_OR_BOTH:
+ case NFS4_CDFC4_BACK_OR_BOTH:
+ *dir = NFS4_CDFC4_BOTH;
+ return nfs_ok;
+ };
+ return nfserr_inval;
+}
+
+__be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
+ struct nfsd4_compound_state *cstate,
+ struct nfsd4_bind_conn_to_session *bcts)
+{
+ __be32 status;
+
+ if (!nfsd4_last_compound_op(rqstp))
+ return nfserr_not_only_op;
+ spin_lock(&client_lock);
+ cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid);
+ /* Sorta weird: we only need the refcnt'ing because new_conn acquires
+ * client_lock iself: */
+ if (cstate->session) {
+ nfsd4_get_session(cstate->session);
+ atomic_inc(&cstate->session->se_client->cl_refcount);
+ }
+ spin_unlock(&client_lock);
+ if (!cstate->session)
+ return nfserr_badsession;
+
+ status = nfsd4_map_bcts_dir(&bcts->dir);
+ nfsd4_new_conn(rqstp, cstate->session, bcts->dir);
+ return nfs_ok;
+}
+
static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
{
if (!session)
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index ca37869..4ff2c9e 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -421,6 +421,21 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access
DECODE_TAIL;
}
+static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts)
+{
+ DECODE_HEAD;
+ u32 dummy;
+
+ READ_BUF(NFS4_MAX_SESSIONID_LEN + 8);
+ COPYMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN);
+ READ32(bcts->dir);
+ /* XXX: Perhaps Tom Tucker could help us figure out how we
+ * should be using ctsa_use_conn_in_rdma_mode: */
+ READ32(dummy);
+
+ DECODE_TAIL;
+}
+
static __be32
nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
{
@@ -1359,7 +1374,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
/* new operations for NFSv4.1 */
[OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_notsupp,
- [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_notsupp,
+ [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session,
[OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id,
[OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session,
[OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session,
@@ -2383,6 +2398,21 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
return nfserr;
}
+static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts)
+{
+ __be32 *p;
+
+ if (!nfserr) {
+ RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 8);
+ WRITEMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN);
+ WRITE32(bcts->dir);
+ /* XXX: ? */
+ WRITE32(0);
+ ADJUST_ARGS();
+ }
+ return nfserr;
+}
+
static __be32
nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close)
{
@@ -3174,7 +3204,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
/* NFSv4.1 operations */
[OP_BACKCHANNEL_CTL] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_noop,
+ [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_bind_conn_to_session,
[OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id,
[OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session,
[OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_destroy_session,
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index cf6dc83..442f6d8 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -148,6 +148,11 @@ struct nfsd4_create_session {
u32 gid;
};
+struct nfsd4_bind_conn_to_session {
+ struct nfs4_sessionid sessionid;
+ u32 dir;
+};
+
/* The single slot clientid cache structure */
struct nfsd4_clid_slot {
u32 sl_seqid;
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 799c30c..3a7aa4d 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -427,6 +427,7 @@ struct nfsd4_op {
/* NFSv4.1 */
struct nfsd4_exchange_id exchange_id;
+ struct nfsd4_bind_conn_to_session bind_conn_to_session;
struct nfsd4_create_session create_session;
struct nfsd4_destroy_session destroy_session;
struct nfsd4_sequence sequence;
@@ -523,6 +524,7 @@ extern __be32 nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
struct nfsd4_sequence *seq);
extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp,
struct nfsd4_compound_state *, struct nfsd4_exchange_id *);
+extern __be32 nfsd4_bind_conn_to_session(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_bind_conn_to_session *);
extern __be32 nfsd4_create_session(struct svc_rqst *,
struct nfsd4_compound_state *,
struct nfsd4_create_session *);
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 26afa30..a591893 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -65,6 +65,9 @@
#define NFS4_CDFC4_FORE 0x1
#define NFS4_CDFC4_BACK 0x2
+#define NFS4_CDFC4_BOTH 0x3
+#define NFS4_CDFC4_FORE_OR_BOTH 0x3
+#define NFS4_CDFC4_BACK_OR_BOTH 0x7
#define NFS4_SET_TO_SERVER_TIME 0
#define NFS4_SET_TO_CLIENT_TIME 1
--
1.7.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 03/14] nfsd4: allow backchannel recovery
2011-01-11 16:21 server sessions patches J. Bruce Fields
2011-01-11 16:21 ` [PATCH 01/14] nfsd4: modify session list under cl_lock J. Bruce Fields
2011-01-11 16:21 ` [PATCH 02/14] nfsd4: support BIND_CONN_TO_SESSION J. Bruce Fields
@ 2011-01-11 16:21 ` J. Bruce Fields
2011-01-11 16:21 ` [PATCH 04/14] rpc: move sk_bc_xprt to svc_xprt J. Bruce Fields
` (10 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: J. Bruce Fields @ 2011-01-11 16:21 UTC (permalink / raw)
To: linux-nfs; +Cc: J. Bruce Fields
From: J. Bruce Fields <bfields@citi.umich.edu>
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>
---
fs/nfsd/nfs4callback.c | 36 +++++++++++++++++++++++++++++++++---
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 dd183af..18b740b 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -473,8 +473,7 @@ static int max_cb_time(void)
/* Reference counting, callback cleanup, etc., all look racy as heck.
* And why is cl_cb_set an atomic? */
-static int setup_callback_client(struct nfs4_client *clp,
- struct nfs4_cb_conn *conn)
+static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses)
{
struct rpc_timeout timeparms = {
.to_initval = max_cb_time(),
@@ -501,6 +500,10 @@ static int setup_callback_client(struct nfs4_client *clp,
args.protocol = XPRT_TRANSPORT_TCP;
clp->cl_cb_ident = conn->cb_ident;
} 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.prognumber = clp->cl_cb_session->se_cb_prog;
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);
}
+/* 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)
{
struct nfs4_cb_conn conn;
struct nfs4_client *clp = cb->cb_clp;
+ struct nfsd4_session *ses = NULL;
+ struct nfsd4_conn *c;
int err;
/*
@@ -770,6 +790,10 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
rpc_shutdown_client(clp->cl_cb_client);
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))
return;
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);
clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
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);
- err = setup_callback_client(clp, &conn);
+ err = setup_callback_client(clp, &conn, ses);
if (err)
warn_no_callback_path(clp, err);
}
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 956174f..290370b 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)
free_conn(c);
}
spin_unlock(&clp->cl_lock);
+ /* XXX: mark callback for update, probe callback */
}
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);
return NULL;
}
- if (!clp->cl_cb_session && (cses->flags & SESSION4_BACK_CHAN)) {
+ if (cses->flags & SESSION4_BACK_CHAN) {
struct sockaddr *sa = svc_addr(rqstp);
-
- clp->cl_cb_session = new;
- clp->cl_cb_conn.cb_xprt = rqstp->rq_xprt;
- svc_xprt_get(rqstp->rq_xprt);
+ /*
+ * This is a little silly; with sessions there's no real
+ * use for the callback address. Use the peer address
+ * 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);
clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
- nfsd4_probe_callback(clp);
}
+ nfsd4_probe_callback(clp);
return new;
}
--
1.7.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 04/14] rpc: move sk_bc_xprt to svc_xprt
2011-01-11 16:21 server sessions patches J. Bruce Fields
` (2 preceding siblings ...)
2011-01-11 16:21 ` [PATCH 03/14] nfsd4: allow backchannel recovery J. Bruce Fields
@ 2011-01-11 16:21 ` J. Bruce Fields
2011-01-11 16:21 ` [PATCH 05/14] rpc: keep backchannel xprt as long as server connection J. Bruce Fields
` (9 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: J. Bruce Fields @ 2011-01-11 16:21 UTC (permalink / raw)
To: linux-nfs; +Cc: J. Bruce Fields
This seems obviously transport-level information even if it's currently
used only by the server socket code.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
include/linux/sunrpc/svc_xprt.h | 1 +
include/linux/sunrpc/svcsock.h | 1 -
net/sunrpc/svcsock.c | 10 ++++++----
net/sunrpc/xprtsock.c | 2 +-
4 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h
index c8f81da..7ad9751 100644
--- a/include/linux/sunrpc/svc_xprt.h
+++ b/include/linux/sunrpc/svc_xprt.h
@@ -79,6 +79,7 @@ struct svc_xprt {
struct list_head xpt_users; /* callbacks on free */
struct net *xpt_net;
+ struct rpc_xprt *xpt_bc_xprt; /* NFSv4.1 backchannel */
};
static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 1b353a7..04dba23 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -28,7 +28,6 @@ struct svc_sock {
/* private TCP part */
u32 sk_reclen; /* length of record */
u32 sk_tcplen; /* current read length */
- struct rpc_xprt *sk_bc_xprt; /* NFSv4.1 backchannel xprt */
};
/*
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 52bd113..3bb400f 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -987,15 +987,17 @@ static int svc_process_calldir(struct svc_sock *svsk, struct svc_rqst *rqstp,
vec[0] = rqstp->rq_arg.head[0];
} else {
/* REPLY */
- if (svsk->sk_bc_xprt)
- req = xprt_lookup_rqst(svsk->sk_bc_xprt, xid);
+ struct rpc_xprt *bc_xprt = svsk->sk_xprt.xpt_bc_xprt;
+
+ if (bc_xprt)
+ req = xprt_lookup_rqst(bc_xprt, xid);
if (!req) {
printk(KERN_NOTICE
"%s: Got unrecognized reply: "
- "calldir 0x%x sk_bc_xprt %p xid %08x\n",
+ "calldir 0x%x xpt_bc_xprt %p xid %08x\n",
__func__, ntohl(calldir),
- svsk->sk_bc_xprt, xid);
+ bc_xprt, xid);
vec[0] = rqstp->rq_arg.head[0];
goto out;
}
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index dfcab5a..18dc42e 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2379,9 +2379,9 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
* The backchannel uses the same socket connection as the
* forechannel
*/
+ args->bc_xprt->xpt_bc_xprt = xprt;
xprt->bc_xprt = args->bc_xprt;
bc_sock = container_of(args->bc_xprt, struct svc_sock, sk_xprt);
- bc_sock->sk_bc_xprt = xprt;
transport->sock = bc_sock->sk_sock;
transport->inet = bc_sock->sk_sk;
--
1.7.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 05/14] rpc: keep backchannel xprt as long as server connection
2011-01-11 16:21 server sessions patches J. Bruce Fields
` (3 preceding siblings ...)
2011-01-11 16:21 ` [PATCH 04/14] rpc: move sk_bc_xprt to svc_xprt J. Bruce Fields
@ 2011-01-11 16:21 ` J. Bruce Fields
2011-01-11 16:21 ` [PATCH 06/14] rpc: allow xprt_class->setup to return a preexisting xprt J. Bruce Fields
` (8 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: J. Bruce Fields @ 2011-01-11 16:21 UTC (permalink / raw)
To: linux-nfs; +Cc: J. Bruce Fields
Multiple backchannels can share the same tcp connection; from rfc 5661 section
2.10.3.1:
A connection's association with a session is not exclusive. A
connection associated with the channel(s) of one session may be
simultaneously associated with the channel(s) of other sessions
including sessions associated with other client IDs.
However, multiple backchannels share a connection, they must all share
the same xid stream (hence the same rpc_xprt); the only way we have to
match replies with calls at the rpc layer is using the xid.
So, keep the rpc_xprt around as long as the connection lasts, in case
we're asked to use the connection as a backchannel again.
Requests to create new backchannel clients over a given server
connection should results in creating new clients that reuse the
existing rpc_xprt.
But to start, just reject attempts to associate multiple rpc_xprt's with
the same underlying bc_xprt.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
net/sunrpc/svc_xprt.c | 4 ++++
net/sunrpc/xprt.c | 2 +-
net/sunrpc/xprtsock.c | 34 ++++++++++++++++++++++++----------
3 files changed, 29 insertions(+), 11 deletions(-)
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index 173f3b9..ab86b79 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -13,6 +13,7 @@
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/svc_xprt.h>
#include <linux/sunrpc/svcsock.h>
+#include <linux/sunrpc/xprt.h>
#define RPCDBG_FACILITY RPCDBG_SVCXPRT
@@ -128,6 +129,9 @@ static void svc_xprt_free(struct kref *kref)
if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags))
svcauth_unix_info_release(xprt);
put_net(xprt->xpt_net);
+ /* See comment on corresponding get in xs_setup_bc_tcp(): */
+ if (xprt->xpt_bc_xprt)
+ xprt_put(xprt->xpt_bc_xprt);
xprt->xpt_ops->xpo_free(xprt);
module_put(owner);
}
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 4c8f18a..749ad15 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -965,6 +965,7 @@ struct rpc_xprt *xprt_alloc(struct net *net, int size, int max_req)
xprt = kzalloc(size, GFP_KERNEL);
if (xprt == NULL)
goto out;
+ kref_init(&xprt->kref);
xprt->max_reqs = max_req;
xprt->slot = kcalloc(max_req, sizeof(struct rpc_rqst), GFP_KERNEL);
@@ -1102,7 +1103,6 @@ found:
return xprt;
}
- kref_init(&xprt->kref);
spin_lock_init(&xprt->transport_lock);
spin_lock_init(&xprt->reserve_lock);
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 18dc42e..0ef4dd4 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2375,16 +2375,6 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
xprt->reestablish_timeout = 0;
xprt->idle_timeout = 0;
- /*
- * The backchannel uses the same socket connection as the
- * forechannel
- */
- args->bc_xprt->xpt_bc_xprt = xprt;
- xprt->bc_xprt = args->bc_xprt;
- bc_sock = container_of(args->bc_xprt, struct svc_sock, sk_xprt);
- transport->sock = bc_sock->sk_sock;
- transport->inet = bc_sock->sk_sk;
-
xprt->ops = &bc_tcp_ops;
switch (addr->sa_family) {
@@ -2407,6 +2397,29 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
xprt->address_strings[RPC_DISPLAY_PROTO]);
/*
+ * The backchannel uses the same socket connection as the
+ * forechannel
+ */
+ if (args->bc_xprt->xpt_bc_xprt) {
+ /* XXX: actually, want to catch this case... */
+ ret = ERR_PTR(-EINVAL);
+ goto out_err;
+ }
+ /*
+ * Once we've associated a backchannel xprt with a connection,
+ * we want to keep it around as long as long as the connection
+ * lasts, in case we need to start using it for a backchannel
+ * again; this reference won't be dropped until bc_xprt is
+ * destroyed.
+ */
+ xprt_get(xprt);
+ args->bc_xprt->xpt_bc_xprt = xprt;
+ xprt->bc_xprt = args->bc_xprt;
+ bc_sock = container_of(args->bc_xprt, struct svc_sock, sk_xprt);
+ transport->sock = bc_sock->sk_sock;
+ transport->inet = bc_sock->sk_sk;
+
+ /*
* Since we don't want connections for the backchannel, we set
* the xprt status to connected
*/
@@ -2415,6 +2428,7 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
if (try_module_get(THIS_MODULE))
return xprt;
+ xprt_put(xprt);
ret = ERR_PTR(-EINVAL);
out_err:
xprt_free(xprt);
--
1.7.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 06/14] rpc: allow xprt_class->setup to return a preexisting xprt
2011-01-11 16:21 server sessions patches J. Bruce Fields
` (4 preceding siblings ...)
2011-01-11 16:21 ` [PATCH 05/14] rpc: keep backchannel xprt as long as server connection J. Bruce Fields
@ 2011-01-11 16:21 ` J. Bruce Fields
2011-01-11 16:21 ` [PATCH 07/14] nfsd4: keep finer-grained callback status J. Bruce Fields
` (7 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: J. Bruce Fields @ 2011-01-11 16:21 UTC (permalink / raw)
To: linux-nfs; +Cc: J. Bruce Fields
This allows us to reuse the xprt associated with a server connection if
one has already been set up.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
include/linux/sunrpc/xprt.h | 1 +
net/sunrpc/xprt.c | 3 +++
net/sunrpc/xprtsock.c | 18 +++++++++---------
3 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index 89d10d2..bef0f53 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -321,6 +321,7 @@ void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie);
#define XPRT_CLOSING (6)
#define XPRT_CONNECTION_ABORT (7)
#define XPRT_CONNECTION_CLOSE (8)
+#define XPRT_INITIALIZED (9)
static inline void xprt_set_connected(struct rpc_xprt *xprt)
{
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 749ad15..856274d 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -1102,6 +1102,9 @@ found:
-PTR_ERR(xprt));
return xprt;
}
+ if (test_and_set_bit(XPRT_INITIALIZED, &xprt->state))
+ /* ->setup returned a pre-initialized xprt: */
+ return xprt;
spin_lock_init(&xprt->transport_lock);
spin_lock_init(&xprt->reserve_lock);
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 0ef4dd4..ee091c8 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2359,6 +2359,15 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
struct svc_sock *bc_sock;
struct rpc_xprt *ret;
+ if (args->bc_xprt->xpt_bc_xprt) {
+ /*
+ * This server connection already has a backchannel
+ * export; we can't create a new one, as we wouldn't be
+ * able to match replies based on xid any more. So,
+ * reuse the already-existing one:
+ */
+ return args->bc_xprt->xpt_bc_xprt;
+ }
xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries);
if (IS_ERR(xprt))
return xprt;
@@ -2397,15 +2406,6 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
xprt->address_strings[RPC_DISPLAY_PROTO]);
/*
- * The backchannel uses the same socket connection as the
- * forechannel
- */
- if (args->bc_xprt->xpt_bc_xprt) {
- /* XXX: actually, want to catch this case... */
- ret = ERR_PTR(-EINVAL);
- goto out_err;
- }
- /*
* Once we've associated a backchannel xprt with a connection,
* we want to keep it around as long as long as the connection
* lasts, in case we need to start using it for a backchannel
--
1.7.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 07/14] nfsd4: keep finer-grained callback status
2011-01-11 16:21 server sessions patches J. Bruce Fields
` (5 preceding siblings ...)
2011-01-11 16:21 ` [PATCH 06/14] rpc: allow xprt_class->setup to return a preexisting xprt J. Bruce Fields
@ 2011-01-11 16:21 ` J. Bruce Fields
2011-01-11 16:21 ` [PATCH 08/14] nfsd4: set sequence flag when backchannel is down J. Bruce Fields
` (6 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: J. Bruce Fields @ 2011-01-11 16:21 UTC (permalink / raw)
To: linux-nfs; +Cc: J. Bruce Fields
From: J. Bruce Fields <bfields@citi.umich.edu>
Distinguish between when the callback channel is known to be down, and
when it is not yet confirmed. This will be useful in the 4.1 case.
Also, we don't seem to be using the fact that this field is atomic.
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
---
fs/nfsd/nfs4callback.c | 26 ++++++++++++++------------
fs/nfsd/nfs4state.c | 8 ++++----
fs/nfsd/state.h | 5 ++++-
3 files changed, 22 insertions(+), 17 deletions(-)
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 18b740b..d32f49d 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -470,8 +470,6 @@ static int max_cb_time(void)
return max(nfsd4_lease/10, (time_t)1) * HZ;
}
-/* Reference counting, callback cleanup, etc., all look racy as heck.
- * And why is cl_cb_set an atomic? */
static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses)
{
@@ -526,14 +524,20 @@ static void warn_no_callback_path(struct nfs4_client *clp, int reason)
(int)clp->cl_name.len, clp->cl_name.data, reason);
}
+static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason)
+{
+ clp->cl_cb_state = NFSD4_CB_DOWN;
+ warn_no_callback_path(clp, reason);
+}
+
static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
{
struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null);
if (task->tk_status)
- warn_no_callback_path(clp, task->tk_status);
+ nfsd4_mark_cb_down(clp, task->tk_status);
else
- atomic_set(&clp->cl_cb_set, 1);
+ clp->cl_cb_state = NFSD4_CB_UP;
}
static const struct rpc_call_ops nfsd4_cb_probe_ops = {
@@ -579,14 +583,15 @@ static void do_probe_callback(struct nfs4_client *clp)
*/
void nfsd4_probe_callback(struct nfs4_client *clp)
{
+ /* XXX: atomicity? Also, should we be using cl_cb_flags? */
+ clp->cl_cb_state = NFSD4_CB_UNKNOWN;
set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
do_probe_callback(clp);
}
void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
{
- BUG_ON(atomic_read(&clp->cl_cb_set));
-
+ clp->cl_cb_state = NFSD4_CB_UNKNOWN;
spin_lock(&clp->cl_lock);
memcpy(&clp->cl_cb_conn, conn, sizeof(struct nfs4_cb_conn));
spin_unlock(&clp->cl_lock);
@@ -693,8 +698,7 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
break;
default:
/* Network partition? */
- atomic_set(&clp->cl_cb_set, 0);
- warn_no_callback_path(clp, task->tk_status);
+ nfsd4_mark_cb_down(clp, task->tk_status);
if (current_rpc_client != task->tk_client) {
/* queue a callback on the new connection: */
atomic_inc(&dp->dl_count);
@@ -707,10 +711,8 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
task->tk_status = 0;
rpc_restart_call_prepare(task);
return;
- } else {
- atomic_set(&clp->cl_cb_set, 0);
- warn_no_callback_path(clp, task->tk_status);
- }
+ } else
+ nfsd4_mark_cb_down(clp, task->tk_status);
}
static void nfsd4_cb_recall_release(void *calldata)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 290370b..919ad25 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1071,7 +1071,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
atomic_set(&clp->cl_refcount, 0);
- atomic_set(&clp->cl_cb_set, 0);
+ clp->cl_cb_state = NFSD4_CB_UNKNOWN;
INIT_LIST_HEAD(&clp->cl_idhash);
INIT_LIST_HEAD(&clp->cl_strhash);
INIT_LIST_HEAD(&clp->cl_openowners);
@@ -2003,7 +2003,6 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
if (!same_creds(&conf->cl_cred, &unconf->cl_cred))
status = nfserr_clid_inuse;
else {
- atomic_set(&conf->cl_cb_set, 0);
nfsd4_change_callback(conf, &unconf->cl_cb_conn);
nfsd4_probe_callback(conf);
expire_client(unconf);
@@ -2633,7 +2632,8 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
{
struct nfs4_delegation *dp;
struct nfs4_stateowner *sop = stp->st_stateowner;
- int cb_up = atomic_read(&sop->so_client->cl_cb_set);
+ /* XXX: or unknown and nfsv4.1: */
+ int cb_up = (sop->so_client->cl_cb_state == NFSD4_CB_UP);
struct file_lock *fl;
int status, flag = 0;
@@ -2823,7 +2823,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
renew_client(clp);
status = nfserr_cb_path_down;
if (!list_empty(&clp->cl_delegations)
- && !atomic_read(&clp->cl_cb_set))
+ && clp->cl_cb_state != NFSD4_CB_UP)
goto out;
status = nfs_ok;
out:
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 442f6d8..32ff615 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -242,7 +242,10 @@ struct nfs4_client {
unsigned long cl_cb_flags;
struct rpc_clnt *cl_cb_client;
u32 cl_cb_ident;
- atomic_t cl_cb_set;
+#define NFSD4_CB_UP 0
+#define NFSD4_CB_UNKNOWN 1
+#define NFSD4_CB_DOWN 2
+ int cl_cb_state;
struct nfsd4_callback cl_cb_null;
struct nfsd4_session *cl_cb_session;
--
1.7.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 08/14] nfsd4: set sequence flag when backchannel is down
2011-01-11 16:21 server sessions patches J. Bruce Fields
` (6 preceding siblings ...)
2011-01-11 16:21 ` [PATCH 07/14] nfsd4: keep finer-grained callback status J. Bruce Fields
@ 2011-01-11 16:21 ` J. Bruce Fields
2011-01-11 16:21 ` [PATCH 09/14] nfsd4: re-probe callback on connection loss J. Bruce Fields
` (5 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: J. Bruce Fields @ 2011-01-11 16:21 UTC (permalink / raw)
To: linux-nfs; +Cc: J. Bruce Fields
Implement the SEQ4_STATUS_CB_PATH_DOWN flag.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
fs/nfsd/nfs4state.c | 6 +++++-
fs/nfsd/nfs4xdr.c | 8 ++------
fs/nfsd/xdr4.h | 2 +-
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 919ad25..15bd1cc 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1800,8 +1800,12 @@ nfsd4_sequence(struct svc_rqst *rqstp,
out:
/* Hold a session reference until done processing the compound. */
if (cstate->session) {
+ struct nfs4_client *clp = session->se_client;
+
nfsd4_get_session(cstate->session);
- atomic_inc(&session->se_client->cl_refcount);
+ atomic_inc(&clp->cl_refcount);
+ if (clp->cl_cb_state == NFSD4_CB_DOWN)
+ seq->status_flags |= SEQ4_STATUS_CB_PATH_DOWN;
}
kfree(conn);
spin_unlock(&client_lock);
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 4ff2c9e..956629b 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3137,13 +3137,9 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
WRITE32(seq->seqid);
WRITE32(seq->slotid);
WRITE32(seq->maxslots);
- /*
- * FIXME: for now:
- * target_maxslots = maxslots
- * status_flags = 0
- */
+ /* For now: target_maxslots = maxslots */
WRITE32(seq->maxslots);
- WRITE32(0);
+ WRITE32(seq->status_flags);
ADJUST_ARGS();
resp->cstate.datap = p; /* DRC cache data pointer */
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 3a7aa4d..366401e 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -378,8 +378,8 @@ struct nfsd4_sequence {
u32 cachethis; /* request */
#if 0
u32 target_maxslots; /* response */
- u32 status_flags; /* response */
#endif /* not yet */
+ u32 status_flags; /* response */
};
struct nfsd4_destroy_session {
--
1.7.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 09/14] nfsd4: re-probe callback on connection loss
2011-01-11 16:21 server sessions patches J. Bruce Fields
` (7 preceding siblings ...)
2011-01-11 16:21 ` [PATCH 08/14] nfsd4: set sequence flag when backchannel is down J. Bruce Fields
@ 2011-01-11 16:21 ` J. Bruce Fields
2011-01-11 16:21 ` [PATCH 10/14] nfsd4: make sure sequence flags are set after destroy_session J. Bruce Fields
` (4 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: J. Bruce Fields @ 2011-01-11 16:21 UTC (permalink / raw)
To: linux-nfs; +Cc: J. Bruce Fields
This makes sure we set the sequence flag when necessary.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
fs/nfsd/nfs4state.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 15bd1cc..b24f19d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -642,7 +642,7 @@ static void nfsd4_conn_lost(struct svc_xpt_user *u)
free_conn(c);
}
spin_unlock(&clp->cl_lock);
- /* XXX: mark callback for update, probe callback */
+ nfsd4_probe_callback(clp);
}
static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags)
--
1.7.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 10/14] nfsd4: make sure sequence flags are set after destroy_session
2011-01-11 16:21 server sessions patches J. Bruce Fields
` (8 preceding siblings ...)
2011-01-11 16:21 ` [PATCH 09/14] nfsd4: re-probe callback on connection loss J. Bruce Fields
@ 2011-01-11 16:21 ` J. Bruce Fields
2011-01-11 16:21 ` [PATCH 11/14] nfsd4: add helper function to run callbacks J. Bruce Fields
` (3 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: J. Bruce Fields @ 2011-01-11 16:21 UTC (permalink / raw)
To: linux-nfs; +Cc: J. Bruce Fields
If this loses any backchannel, make sure we have a chance to notice that
and set the sequence flags.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
fs/nfsd/nfs4callback.c | 6 ++++++
fs/nfsd/nfs4state.c | 3 +--
fs/nfsd/state.h | 1 +
3 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index d32f49d..cb002dc 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -589,6 +589,12 @@ void nfsd4_probe_callback(struct nfs4_client *clp)
do_probe_callback(clp);
}
+void nfsd4_probe_callback_sync(struct nfs4_client *clp)
+{
+ nfsd4_probe_callback(clp);
+ flush_workqueue(callback_wq);
+}
+
void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
{
clp->cl_cb_state = NFSD4_CB_UNKNOWN;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index b24f19d..00a50b8 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1686,8 +1686,7 @@ nfsd4_destroy_session(struct svc_rqst *r,
spin_unlock(&client_lock);
nfs4_lock_state();
- /* wait for callbacks */
- nfsd4_shutdown_callback(ses->se_client);
+ nfsd4_probe_callback_sync(ses->se_client);
nfs4_unlock_state();
nfsd4_del_conns(ses);
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 32ff615..4e5bdfd 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -464,6 +464,7 @@ extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
extern void nfs4_free_stateowner(struct kref *kref);
extern int set_callback_cred(void);
extern void nfsd4_probe_callback(struct nfs4_client *clp);
+extern void nfsd4_probe_callback_sync(struct nfs4_client *clp);
extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *);
extern void nfsd4_do_callback_rpc(struct work_struct *);
extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
--
1.7.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 11/14] nfsd4: add helper function to run callbacks
2011-01-11 16:21 server sessions patches J. Bruce Fields
` (9 preceding siblings ...)
2011-01-11 16:21 ` [PATCH 10/14] nfsd4: make sure sequence flags are set after destroy_session J. Bruce Fields
@ 2011-01-11 16:21 ` J. Bruce Fields
2011-01-11 16:21 ` [PATCH 12/14] nfsd4: give out delegations more quickly in 4.1 case J. Bruce Fields
` (2 subsequent siblings)
13 siblings, 0 replies; 15+ messages in thread
From: J. Bruce Fields @ 2011-01-11 16:21 UTC (permalink / raw)
To: linux-nfs; +Cc: J. Bruce Fields
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
fs/nfsd/nfs4callback.c | 9 +++++++--
1 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index cb002dc..fff96dc 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -560,6 +560,11 @@ int set_callback_cred(void)
static struct workqueue_struct *callback_wq;
+static void run_nfsd4_cb(struct nfsd4_callback *cb)
+{
+ queue_work(callback_wq, &cb->cb_work);
+}
+
static void do_probe_callback(struct nfs4_client *clp)
{
struct nfsd4_callback *cb = &clp->cl_cb_null;
@@ -574,7 +579,7 @@ static void do_probe_callback(struct nfs4_client *clp)
cb->cb_ops = &nfsd4_cb_probe_ops;
- queue_work(callback_wq, &cb->cb_work);
+ run_nfsd4_cb(cb);
}
/*
@@ -859,5 +864,5 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp)
cb->cb_ops = &nfsd4_cb_recall_ops;
dp->dl_retries = 1;
- queue_work(callback_wq, &dp->dl_recall.cb_work);
+ run_nfsd4_cb(&dp->dl_recall);
}
--
1.7.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 12/14] nfsd4: give out delegations more quickly in 4.1 case
2011-01-11 16:21 server sessions patches J. Bruce Fields
` (10 preceding siblings ...)
2011-01-11 16:21 ` [PATCH 11/14] nfsd4: add helper function to run callbacks J. Bruce Fields
@ 2011-01-11 16:21 ` J. Bruce Fields
2011-01-11 16:21 ` [PATCH 13/14] nfsd4: simplify nfsd4_cb_prepare J. Bruce Fields
2011-01-11 16:21 ` [PATCH 14/14] nfsd4: allow restarting callbacks J. Bruce Fields
13 siblings, 0 replies; 15+ messages in thread
From: J. Bruce Fields @ 2011-01-11 16:21 UTC (permalink / raw)
To: linux-nfs; +Cc: J. Bruce Fields
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
fs/nfsd/nfs4state.c | 17 +++++++++++++++--
1 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 00a50b8..408957c 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2627,6 +2627,19 @@ nfs4_set_claim_prev(struct nfsd4_open *open)
open->op_stateowner->so_client->cl_firststate = 1;
}
+/* Should we give out recallable state?: */
+static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
+{
+ if (clp->cl_cb_state == NFSD4_CB_UP)
+ return true;
+ /*
+ * In the sessions case, since we don't have to establish a
+ * separate connection for callbacks, we assume it's OK
+ * until we hear otherwise:
+ */
+ return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
+}
+
/*
* Attempt to hand out a delegation.
*/
@@ -2635,11 +2648,11 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
{
struct nfs4_delegation *dp;
struct nfs4_stateowner *sop = stp->st_stateowner;
- /* XXX: or unknown and nfsv4.1: */
- int cb_up = (sop->so_client->cl_cb_state == NFSD4_CB_UP);
+ int cb_up;
struct file_lock *fl;
int status, flag = 0;
+ cb_up = nfsd4_cb_channel_good(sop->so_client);
flag = NFS4_OPEN_DELEGATE_NONE;
open->op_recall = 0;
switch (open->op_claim_type) {
--
1.7.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 13/14] nfsd4: simplify nfsd4_cb_prepare
2011-01-11 16:21 server sessions patches J. Bruce Fields
` (11 preceding siblings ...)
2011-01-11 16:21 ` [PATCH 12/14] nfsd4: give out delegations more quickly in 4.1 case J. Bruce Fields
@ 2011-01-11 16:21 ` J. Bruce Fields
2011-01-11 16:21 ` [PATCH 14/14] nfsd4: allow restarting callbacks J. Bruce Fields
13 siblings, 0 replies; 15+ messages in thread
From: J. Bruce Fields @ 2011-01-11 16:21 UTC (permalink / raw)
To: linux-nfs; +Cc: J. Bruce Fields
Remove handling for a nonexistant case (status && !-EAGAIN).
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
fs/nfsd/nfs4callback.c | 26 ++++----------------------
1 files changed, 4 insertions(+), 22 deletions(-)
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index fff96dc..69955e9 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -613,24 +613,14 @@ void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
* If the slot is available, then mark it busy. Otherwise, set the
* thread for sleeping on the callback RPC wait queue.
*/
-static int nfsd41_cb_setup_sequence(struct nfs4_client *clp,
- struct rpc_task *task)
+static bool nfsd41_cb_get_slot(struct nfs4_client *clp, struct rpc_task *task)
{
- u32 *ptr = (u32 *)clp->cl_cb_session->se_sessionid.data;
- int status = 0;
-
- dprintk("%s: %u:%u:%u:%u\n", __func__,
- ptr[0], ptr[1], ptr[2], ptr[3]);
-
if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) {
rpc_sleep_on(&clp->cl_cb_waitq, task, NULL);
dprintk("%s slot is busy\n", __func__);
- status = -EAGAIN;
- goto out;
+ return false;
}
-out:
- dprintk("%s status=%d\n", __func__, status);
- return status;
+ return true;
}
/*
@@ -643,19 +633,11 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
struct nfs4_client *clp = dp->dl_client;
u32 minorversion = clp->cl_minorversion;
- int status = 0;
cb->cb_minorversion = minorversion;
if (minorversion) {
- status = nfsd41_cb_setup_sequence(clp, task);
- if (status) {
- if (status != -EAGAIN) {
- /* terminate rpc task */
- task->tk_status = status;
- task->tk_action = NULL;
- }
+ if (!nfsd41_cb_get_slot(clp, task))
return;
- }
}
rpc_call_start(task);
}
--
1.7.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 14/14] nfsd4: allow restarting callbacks
2011-01-11 16:21 server sessions patches J. Bruce Fields
` (12 preceding siblings ...)
2011-01-11 16:21 ` [PATCH 13/14] nfsd4: simplify nfsd4_cb_prepare J. Bruce Fields
@ 2011-01-11 16:21 ` J. Bruce Fields
13 siblings, 0 replies; 15+ messages in thread
From: J. Bruce Fields @ 2011-01-11 16:21 UTC (permalink / raw)
To: linux-nfs; +Cc: J. Bruce Fields
If we lose the backchannel and then the client repairs the problem,
resend any callbacks.
We use a new cb_done flag to track whether there is still work to be
done for the callback or whether it can be destroyed with the rpc.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
---
fs/nfsd/nfs4callback.c | 34 ++++++++++++++++++++++++++++------
fs/nfsd/nfs4state.c | 1 +
fs/nfsd/state.h | 3 +++
3 files changed, 32 insertions(+), 6 deletions(-)
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 69955e9..f1d9dd4 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -639,6 +639,10 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
if (!nfsd41_cb_get_slot(clp, task))
return;
}
+ cb->cb_done = false;
+ spin_lock(&clp->cl_lock);
+ list_add(&cb->cb_per_client, &clp->cl_callbacks);
+ spin_unlock(&clp->cl_lock);
rpc_call_start(task);
}
@@ -681,8 +685,11 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
return;
}
+ if (cb->cb_done)
+ return;
switch (task->tk_status) {
case 0:
+ cb->cb_done = true;
return;
case -EBADHANDLE:
case -NFS4ERR_BAD_STATEID:
@@ -695,7 +702,7 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
if (current_rpc_client != task->tk_client) {
/* queue a callback on the new connection: */
atomic_inc(&dp->dl_count);
- nfsd4_cb_recall(dp);
+ run_nfsd4_cb(&dp->dl_recall);
return;
}
}
@@ -704,16 +711,23 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
task->tk_status = 0;
rpc_restart_call_prepare(task);
return;
- } else
- nfsd4_mark_cb_down(clp, task->tk_status);
+ }
+ nfsd4_mark_cb_down(clp, task->tk_status);
+ cb->cb_done = true;
}
static void nfsd4_cb_recall_release(void *calldata)
{
struct nfsd4_callback *cb = calldata;
+ struct nfs4_client *clp = cb->cb_clp;
struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
- nfs4_put_delegation(dp);
+ if (cb->cb_done) {
+ spin_lock(&clp->cl_lock);
+ list_del(&cb->cb_per_client);
+ spin_unlock(&clp->cl_lock);
+ nfs4_put_delegation(dp);
+ }
}
static const struct rpc_call_ops nfsd4_cb_recall_ops = {
@@ -808,8 +822,13 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
spin_unlock(&clp->cl_lock);
err = setup_callback_client(clp, &conn, ses);
- if (err)
+ if (err) {
warn_no_callback_path(clp, err);
+ return;
+ }
+ /* Yay, the callback channel's back! Restart any callbacks: */
+ list_for_each_entry(cb, &clp->cl_callbacks, cb_per_client)
+ run_nfsd4_cb(cb);
}
void nfsd4_do_callback_rpc(struct work_struct *w)
@@ -834,10 +853,11 @@ void nfsd4_do_callback_rpc(struct work_struct *w)
void nfsd4_cb_recall(struct nfs4_delegation *dp)
{
struct nfsd4_callback *cb = &dp->dl_recall;
+ struct nfs4_client *clp = dp->dl_client;
dp->dl_retries = 1;
cb->cb_op = dp;
- cb->cb_clp = dp->dl_client;
+ cb->cb_clp = clp;
cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL];
cb->cb_msg.rpc_argp = cb;
cb->cb_msg.rpc_resp = cb;
@@ -846,5 +866,7 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp)
cb->cb_ops = &nfsd4_cb_recall_ops;
dp->dl_retries = 1;
+ cb->cb_done = true;
+
run_nfsd4_cb(&dp->dl_recall);
}
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 408957c..6e1f9aa 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1077,6 +1077,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
INIT_LIST_HEAD(&clp->cl_openowners);
INIT_LIST_HEAD(&clp->cl_delegations);
INIT_LIST_HEAD(&clp->cl_lru);
+ INIT_LIST_HEAD(&clp->cl_callbacks);
spin_lock_init(&clp->cl_lock);
INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc);
clp->cl_time = get_seconds();
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 4e5bdfd..3074656 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -68,10 +68,12 @@ typedef struct {
struct nfsd4_callback {
void *cb_op;
struct nfs4_client *cb_clp;
+ struct list_head cb_per_client;
u32 cb_minorversion;
struct rpc_message cb_msg;
const struct rpc_call_ops *cb_ops;
struct work_struct cb_work;
+ bool cb_done;
};
struct nfs4_delegation {
@@ -248,6 +250,7 @@ struct nfs4_client {
int cl_cb_state;
struct nfsd4_callback cl_cb_null;
struct nfsd4_session *cl_cb_session;
+ struct list_head cl_callbacks; /* list of in-progress callbacks */
/* for all client information that callback code might need: */
spinlock_t cl_lock;
--
1.7.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
end of thread, other threads:[~2011-01-11 16:22 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-01-11 16:21 server sessions patches J. Bruce Fields
2011-01-11 16:21 ` [PATCH 01/14] nfsd4: modify session list under cl_lock J. Bruce Fields
2011-01-11 16:21 ` [PATCH 02/14] nfsd4: support BIND_CONN_TO_SESSION J. Bruce Fields
2011-01-11 16:21 ` [PATCH 03/14] nfsd4: allow backchannel recovery J. Bruce Fields
2011-01-11 16:21 ` [PATCH 04/14] rpc: move sk_bc_xprt to svc_xprt J. Bruce Fields
2011-01-11 16:21 ` [PATCH 05/14] rpc: keep backchannel xprt as long as server connection J. Bruce Fields
2011-01-11 16:21 ` [PATCH 06/14] rpc: allow xprt_class->setup to return a preexisting xprt J. Bruce Fields
2011-01-11 16:21 ` [PATCH 07/14] nfsd4: keep finer-grained callback status J. Bruce Fields
2011-01-11 16:21 ` [PATCH 08/14] nfsd4: set sequence flag when backchannel is down J. Bruce Fields
2011-01-11 16:21 ` [PATCH 09/14] nfsd4: re-probe callback on connection loss J. Bruce Fields
2011-01-11 16:21 ` [PATCH 10/14] nfsd4: make sure sequence flags are set after destroy_session J. Bruce Fields
2011-01-11 16:21 ` [PATCH 11/14] nfsd4: add helper function to run callbacks J. Bruce Fields
2011-01-11 16:21 ` [PATCH 12/14] nfsd4: give out delegations more quickly in 4.1 case J. Bruce Fields
2011-01-11 16:21 ` [PATCH 13/14] nfsd4: simplify nfsd4_cb_prepare J. Bruce Fields
2011-01-11 16:21 ` [PATCH 14/14] nfsd4: allow restarting callbacks J. Bruce Fields
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).