aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4callback.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfs4callback.c')
-rw-r--r--fs/nfsd/nfs4callback.c62
1 files changed, 62 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};