aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRicardo Labiaga <Ricardo.Labiaga@netapp.com>2009-09-10 05:26:38 -0400
committerJ. Bruce Fields <bfields@citi.umich.edu>2009-09-15 20:49:56 -0400
commit2a1d1b593803d7c18a369bf148f3b48c5a3260fc (patch)
tree40cd8e5498ad680eec740923d512c0bf5fe114b3
parent199ff35e1c8724871e157c2e48556c2794946e82 (diff)
nfsd41: Backchannel: Setup sequence information
Follows the model used by the NFS client. Setup the RPC prepare and done function pointers so that we can populate the sequence information if minorversion == 1. rpc_run_task() is then invoked directly just like existing NFS client operations do. nfsd4_cb_prepare() determines if the sequence information needs to be setup. If the slot is in use, it adds itself to the wait queue. nfsd4_cb_done() wakes anyone sleeping on the callback channel wait queue after our RPC reply has been received. It also sets the task message result pointer to NULL to clearly indicate we're done using it. Signed-off-by: Ricardo Labiaga <Ricardo.Labiaga@netapp.com> [define and initialize cl_cb_seq_nr here] [pulled out unused defintion of nfsd4_cb_done] Signed-off-by: Benny Halevy <bhalevy@panasas.com> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
-rw-r--r--fs/nfsd/nfs4callback.c62
-rw-r--r--fs/nfsd/nfs4state.c1
-rw-r--r--include/linux/nfsd/state.h1
3 files changed, 64 insertions, 0 deletions
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index f31175717c1a..25a09069e458 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -501,6 +501,67 @@ nfsd4_probe_callback(struct nfs4_client *clp)
501 do_probe_callback(clp); 501 do_probe_callback(clp);
502} 502}
503 503
504/*
505 * There's currently a single callback channel slot.
506 * If the slot is available, then mark it busy. Otherwise, set the
507 * thread for sleeping on the callback RPC wait queue.
508 */
509static int nfsd41_cb_setup_sequence(struct nfs4_client *clp,
510 struct rpc_task *task)
511{
512 struct nfs4_rpc_args *args = task->tk_msg.rpc_argp;
513 u32 *ptr = (u32 *)clp->cl_sessionid.data;
514 int status = 0;
515
516 dprintk("%s: %u:%u:%u:%u\n", __func__,
517 ptr[0], ptr[1], ptr[2], ptr[3]);
518
519 if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) {
520 rpc_sleep_on(&clp->cl_cb_waitq, task, NULL);
521 dprintk("%s slot is busy\n", __func__);
522 status = -EAGAIN;
523 goto out;
524 }
525
526 /*
527 * We'll need the clp during XDR encoding and decoding,
528 * and the sequence during decoding to verify the reply
529 */
530 args->args_seq.cbs_clp = clp;
531 task->tk_msg.rpc_resp = &args->args_seq;
532
533out:
534 dprintk("%s status=%d\n", __func__, status);
535 return status;
536}
537
538/*
539 * TODO: cb_sequence should support referring call lists, cachethis, multiple
540 * slots, and mark callback channel down on communication errors.
541 */
542static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
543{
544 struct nfs4_delegation *dp = calldata;
545 struct nfs4_client *clp = dp->dl_client;
546 struct nfs4_rpc_args *args = task->tk_msg.rpc_argp;
547 u32 minorversion = clp->cl_cb_conn.cb_minorversion;
548 int status = 0;
549
550 args->args_seq.cbs_minorversion = minorversion;
551 if (minorversion) {
552 status = nfsd41_cb_setup_sequence(clp, task);
553 if (status) {
554 if (status != -EAGAIN) {
555 /* terminate rpc task */
556 task->tk_status = status;
557 task->tk_action = NULL;
558 }
559 return;
560 }
561 }
562 rpc_call_start(task);
563}
564
504static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) 565static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
505{ 566{
506 struct nfs4_delegation *dp = calldata; 567 struct nfs4_delegation *dp = calldata;
@@ -540,6 +601,7 @@ static void nfsd4_cb_recall_release(void *calldata)
540} 601}
541 602
542static const struct rpc_call_ops nfsd4_cb_recall_ops = { 603static const struct rpc_call_ops nfsd4_cb_recall_ops = {
604 .rpc_call_prepare = nfsd4_cb_prepare,
543 .rpc_call_done = nfsd4_cb_recall_done, 605 .rpc_call_done = nfsd4_cb_recall_done,
544 .rpc_release = nfsd4_cb_recall_release, 606 .rpc_release = nfsd4_cb_recall_release,
545}; 607};
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index f4cebd9016bc..76b7bcbb3f20 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1331,6 +1331,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
1331 unconf->cl_cb_conn.cb_minorversion = 1331 unconf->cl_cb_conn.cb_minorversion =
1332 cstate->minorversion; 1332 cstate->minorversion;
1333 unconf->cl_cb_conn.cb_prog = cr_ses->callback_prog; 1333 unconf->cl_cb_conn.cb_prog = cr_ses->callback_prog;
1334 unconf->cl_cb_seq_nr = 1;
1334 nfsd4_probe_callback(unconf); 1335 nfsd4_probe_callback(unconf);
1335 } 1336 }
1336 conf = unconf; 1337 conf = unconf;
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index 9cc40a137c34..b38d11324189 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -221,6 +221,7 @@ struct nfs4_client {
221 /* for nfs41 callbacks */ 221 /* for nfs41 callbacks */
222 /* We currently support a single back channel with a single slot */ 222 /* We currently support a single back channel with a single slot */
223 unsigned long cl_cb_slot_busy; 223 unsigned long cl_cb_slot_busy;
224 u32 cl_cb_seq_nr;
224 struct svc_xprt *cl_cb_xprt; /* 4.1 callback transport */ 225 struct svc_xprt *cl_cb_xprt; /* 4.1 callback transport */
225 struct rpc_wait_queue cl_cb_waitq; /* backchannel callers may */ 226 struct rpc_wait_queue cl_cb_waitq; /* backchannel callers may */
226 /* wait here for slots */ 227 /* wait here for slots */