diff options
Diffstat (limited to 'fs/nfsd/nfs4callback.c')
-rw-r--r-- | fs/nfsd/nfs4callback.c | 62 |
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 | */ | ||
509 | static 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 | |||
533 | out: | ||
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 | */ | ||
542 | static 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 | |||
504 | static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) | 565 | static 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 | ||
542 | static const struct rpc_call_ops nfsd4_cb_recall_ops = { | 603 | static 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 | }; |