Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5ce8ba25 authored by J. Bruce Fields's avatar J. Bruce Fields
Browse files

nfsd4: allow restarting callbacks



If we lose the backchannel and then the client repairs the problem,
resend any callbacks.

We use a new cb_done flag to track whether there is still work to be
done for the callback or whether it can be destroyed with the rpc.

Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 3ff3600e
Loading
Loading
Loading
Loading
+28 −6
Original line number Diff line number Diff line
@@ -639,6 +639,10 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
		if (!nfsd41_cb_get_slot(clp, task))
			return;
	}
	cb->cb_done = false;
	spin_lock(&clp->cl_lock);
	list_add(&cb->cb_per_client, &clp->cl_callbacks);
	spin_unlock(&clp->cl_lock);
	rpc_call_start(task);
}

@@ -681,8 +685,11 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
		return;
	}

	if (cb->cb_done)
		return;
	switch (task->tk_status) {
	case 0:
		cb->cb_done = true;
		return;
	case -EBADHANDLE:
	case -NFS4ERR_BAD_STATEID:
@@ -695,7 +702,7 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
		if (current_rpc_client != task->tk_client) {
			/* queue a callback on the new connection: */
			atomic_inc(&dp->dl_count);
			nfsd4_cb_recall(dp);
			run_nfsd4_cb(&dp->dl_recall);
			return;
		}
	}
@@ -704,17 +711,24 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
		task->tk_status = 0;
		rpc_restart_call_prepare(task);
		return;
	} else
	}
	nfsd4_mark_cb_down(clp, task->tk_status);
	cb->cb_done = true;
}

static void nfsd4_cb_recall_release(void *calldata)
{
	struct nfsd4_callback *cb = calldata;
	struct nfs4_client *clp = cb->cb_clp;
	struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);

	if (cb->cb_done) {
		spin_lock(&clp->cl_lock);
		list_del(&cb->cb_per_client);
		spin_unlock(&clp->cl_lock);
		nfs4_put_delegation(dp);
	}
}

static const struct rpc_call_ops nfsd4_cb_recall_ops = {
	.rpc_call_prepare = nfsd4_cb_prepare,
@@ -808,8 +822,13 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
	spin_unlock(&clp->cl_lock);

	err = setup_callback_client(clp, &conn, ses);
	if (err)
	if (err) {
		warn_no_callback_path(clp, err);
		return;
	}
	/* Yay, the callback channel's back! Restart any callbacks: */
	list_for_each_entry(cb, &clp->cl_callbacks, cb_per_client)
		run_nfsd4_cb(cb);
}

void nfsd4_do_callback_rpc(struct work_struct *w)
@@ -834,10 +853,11 @@ void nfsd4_do_callback_rpc(struct work_struct *w)
void nfsd4_cb_recall(struct nfs4_delegation *dp)
{
	struct nfsd4_callback *cb = &dp->dl_recall;
	struct nfs4_client *clp = dp->dl_client;

	dp->dl_retries = 1;
	cb->cb_op = dp;
	cb->cb_clp = dp->dl_client;
	cb->cb_clp = clp;
	cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL];
	cb->cb_msg.rpc_argp = cb;
	cb->cb_msg.rpc_resp = cb;
@@ -846,5 +866,7 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp)
	cb->cb_ops = &nfsd4_cb_recall_ops;
	dp->dl_retries = 1;

	cb->cb_done = true;

	run_nfsd4_cb(&dp->dl_recall);
}
+1 −0
Original line number Diff line number Diff line
@@ -1077,6 +1077,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
	INIT_LIST_HEAD(&clp->cl_openowners);
	INIT_LIST_HEAD(&clp->cl_delegations);
	INIT_LIST_HEAD(&clp->cl_lru);
	INIT_LIST_HEAD(&clp->cl_callbacks);
	spin_lock_init(&clp->cl_lock);
	INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc);
	clp->cl_time = get_seconds();
+3 −0
Original line number Diff line number Diff line
@@ -68,10 +68,12 @@ typedef struct {
struct nfsd4_callback {
	void *cb_op;
	struct nfs4_client *cb_clp;
	struct list_head cb_per_client;
	u32 cb_minorversion;
	struct rpc_message cb_msg;
	const struct rpc_call_ops *cb_ops;
	struct work_struct cb_work;
	bool cb_done;
};

struct nfs4_delegation {
@@ -248,6 +250,7 @@ struct nfs4_client {
	int			cl_cb_state;
	struct nfsd4_callback	cl_cb_null;
	struct nfsd4_session	*cl_cb_session;
	struct list_head	cl_callbacks; /* list of in-progress callbacks */

	/* for all client information that callback code might need: */
	spinlock_t		cl_lock;