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: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
parent
3ff3600e7e
commit
5ce8ba25d6
3 changed files with 32 additions and 6 deletions
|
@ -639,6 +639,10 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
|
||||||
if (!nfsd41_cb_get_slot(clp, task))
|
if (!nfsd41_cb_get_slot(clp, task))
|
||||||
return;
|
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);
|
rpc_call_start(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -681,8 +685,11 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cb->cb_done)
|
||||||
|
return;
|
||||||
switch (task->tk_status) {
|
switch (task->tk_status) {
|
||||||
case 0:
|
case 0:
|
||||||
|
cb->cb_done = true;
|
||||||
return;
|
return;
|
||||||
case -EBADHANDLE:
|
case -EBADHANDLE:
|
||||||
case -NFS4ERR_BAD_STATEID:
|
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) {
|
if (current_rpc_client != task->tk_client) {
|
||||||
/* queue a callback on the new connection: */
|
/* queue a callback on the new connection: */
|
||||||
atomic_inc(&dp->dl_count);
|
atomic_inc(&dp->dl_count);
|
||||||
nfsd4_cb_recall(dp);
|
run_nfsd4_cb(&dp->dl_recall);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -704,16 +711,23 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
|
||||||
task->tk_status = 0;
|
task->tk_status = 0;
|
||||||
rpc_restart_call_prepare(task);
|
rpc_restart_call_prepare(task);
|
||||||
return;
|
return;
|
||||||
} else
|
}
|
||||||
nfsd4_mark_cb_down(clp, task->tk_status);
|
nfsd4_mark_cb_down(clp, task->tk_status);
|
||||||
|
cb->cb_done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfsd4_cb_recall_release(void *calldata)
|
static void nfsd4_cb_recall_release(void *calldata)
|
||||||
{
|
{
|
||||||
struct nfsd4_callback *cb = 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);
|
struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
|
||||||
|
|
||||||
nfs4_put_delegation(dp);
|
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 = {
|
static const struct rpc_call_ops nfsd4_cb_recall_ops = {
|
||||||
|
@ -808,8 +822,13 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
|
||||||
spin_unlock(&clp->cl_lock);
|
spin_unlock(&clp->cl_lock);
|
||||||
|
|
||||||
err = setup_callback_client(clp, &conn, ses);
|
err = setup_callback_client(clp, &conn, ses);
|
||||||
if (err)
|
if (err) {
|
||||||
warn_no_callback_path(clp, 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)
|
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)
|
void nfsd4_cb_recall(struct nfs4_delegation *dp)
|
||||||
{
|
{
|
||||||
struct nfsd4_callback *cb = &dp->dl_recall;
|
struct nfsd4_callback *cb = &dp->dl_recall;
|
||||||
|
struct nfs4_client *clp = dp->dl_client;
|
||||||
|
|
||||||
dp->dl_retries = 1;
|
dp->dl_retries = 1;
|
||||||
cb->cb_op = dp;
|
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_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL];
|
||||||
cb->cb_msg.rpc_argp = cb;
|
cb->cb_msg.rpc_argp = cb;
|
||||||
cb->cb_msg.rpc_resp = 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;
|
cb->cb_ops = &nfsd4_cb_recall_ops;
|
||||||
dp->dl_retries = 1;
|
dp->dl_retries = 1;
|
||||||
|
|
||||||
|
cb->cb_done = true;
|
||||||
|
|
||||||
run_nfsd4_cb(&dp->dl_recall);
|
run_nfsd4_cb(&dp->dl_recall);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_openowners);
|
||||||
INIT_LIST_HEAD(&clp->cl_delegations);
|
INIT_LIST_HEAD(&clp->cl_delegations);
|
||||||
INIT_LIST_HEAD(&clp->cl_lru);
|
INIT_LIST_HEAD(&clp->cl_lru);
|
||||||
|
INIT_LIST_HEAD(&clp->cl_callbacks);
|
||||||
spin_lock_init(&clp->cl_lock);
|
spin_lock_init(&clp->cl_lock);
|
||||||
INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc);
|
INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc);
|
||||||
clp->cl_time = get_seconds();
|
clp->cl_time = get_seconds();
|
||||||
|
|
|
@ -68,10 +68,12 @@ typedef struct {
|
||||||
struct nfsd4_callback {
|
struct nfsd4_callback {
|
||||||
void *cb_op;
|
void *cb_op;
|
||||||
struct nfs4_client *cb_clp;
|
struct nfs4_client *cb_clp;
|
||||||
|
struct list_head cb_per_client;
|
||||||
u32 cb_minorversion;
|
u32 cb_minorversion;
|
||||||
struct rpc_message cb_msg;
|
struct rpc_message cb_msg;
|
||||||
const struct rpc_call_ops *cb_ops;
|
const struct rpc_call_ops *cb_ops;
|
||||||
struct work_struct cb_work;
|
struct work_struct cb_work;
|
||||||
|
bool cb_done;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nfs4_delegation {
|
struct nfs4_delegation {
|
||||||
|
@ -248,6 +250,7 @@ struct nfs4_client {
|
||||||
int cl_cb_state;
|
int cl_cb_state;
|
||||||
struct nfsd4_callback cl_cb_null;
|
struct nfsd4_callback cl_cb_null;
|
||||||
struct nfsd4_session *cl_cb_session;
|
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: */
|
/* for all client information that callback code might need: */
|
||||||
spinlock_t cl_lock;
|
spinlock_t cl_lock;
|
||||||
|
|
Loading…
Reference in a new issue