|
@@ -501,6 +501,67 @@ nfsd4_probe_callback(struct nfs4_client *clp)
|
|
|
do_probe_callback(clp);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * There's currently a single callback channel slot.
|
|
|
+ * 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)
|
|
|
+{
|
|
|
+ struct nfs4_rpc_args *args = task->tk_msg.rpc_argp;
|
|
|
+ u32 *ptr = (u32 *)clp->cl_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;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We'll need the clp during XDR encoding and decoding,
|
|
|
+ * and the sequence during decoding to verify the reply
|
|
|
+ */
|
|
|
+ args->args_seq.cbs_clp = clp;
|
|
|
+ task->tk_msg.rpc_resp = &args->args_seq;
|
|
|
+
|
|
|
+out:
|
|
|
+ dprintk("%s status=%d\n", __func__, status);
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * TODO: cb_sequence should support referring call lists, cachethis, multiple
|
|
|
+ * slots, and mark callback channel down on communication errors.
|
|
|
+ */
|
|
|
+static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
|
|
|
+{
|
|
|
+ struct nfs4_delegation *dp = calldata;
|
|
|
+ struct nfs4_client *clp = dp->dl_client;
|
|
|
+ struct nfs4_rpc_args *args = task->tk_msg.rpc_argp;
|
|
|
+ u32 minorversion = clp->cl_cb_conn.cb_minorversion;
|
|
|
+ int status = 0;
|
|
|
+
|
|
|
+ args->args_seq.cbs_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;
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ rpc_call_start(task);
|
|
|
+}
|
|
|
+
|
|
|
static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
|
|
|
{
|
|
|
struct nfs4_delegation *dp = calldata;
|
|
@@ -540,6 +601,7 @@ static void nfsd4_cb_recall_release(void *calldata)
|
|
|
}
|
|
|
|
|
|
static const struct rpc_call_ops nfsd4_cb_recall_ops = {
|
|
|
+ .rpc_call_prepare = nfsd4_cb_prepare,
|
|
|
.rpc_call_done = nfsd4_cb_recall_done,
|
|
|
.rpc_release = nfsd4_cb_recall_release,
|
|
|
};
|