diff options
-rw-r--r-- | fs/nfsd/nfs4callback.c | 62 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 1 | ||||
-rw-r--r-- | include/linux/nfsd/state.h | 1 |
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 | */ | ||
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 | }; |
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 */ |