nfs41: RECLAIM_COMPLETE functionality
Implements RECLAIM_COMPLETE as an asynchronous RPC. NFS4ERR_DELAY is retried, NFS4ERR_DEADSESSION invokes the error handling but does not result in a retry, since we don't want to have a lingering RECLAIM_COMPLETE call sent in the middle of a possible new state recovery cycle. If a session reset occurs, a new wave of reclaim operations will follow, containing their own RECLAIM_COMPLETE call. We don't want a retry to get on the way of recovery by incorrectly indicating to the server that we're done reclaiming state. A subsequent patch invokes the functionality. Signed-off-by: Ricardo Labiaga <Ricardo.Labiaga@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
180197536b
commit
fce5c838e1
@ -181,6 +181,7 @@ struct nfs4_state_recovery_ops {
|
|||||||
int (*recover_lock)(struct nfs4_state *, struct file_lock *);
|
int (*recover_lock)(struct nfs4_state *, struct file_lock *);
|
||||||
int (*establish_clid)(struct nfs_client *, struct rpc_cred *);
|
int (*establish_clid)(struct nfs_client *, struct rpc_cred *);
|
||||||
struct rpc_cred * (*get_clid_cred)(struct nfs_client *);
|
struct rpc_cred * (*get_clid_cred)(struct nfs_client *);
|
||||||
|
int (*reclaim_complete)(struct nfs_client *);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nfs4_state_maintenance_ops {
|
struct nfs4_state_maintenance_ops {
|
||||||
|
@ -4971,6 +4971,110 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp,
|
|||||||
&nfs41_sequence_ops, (void *)clp);
|
&nfs41_sequence_ops, (void *)clp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct nfs4_reclaim_complete_data {
|
||||||
|
struct nfs_client *clp;
|
||||||
|
struct nfs41_reclaim_complete_args arg;
|
||||||
|
struct nfs41_reclaim_complete_res res;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data)
|
||||||
|
{
|
||||||
|
struct nfs4_reclaim_complete_data *calldata = data;
|
||||||
|
|
||||||
|
if (nfs4_setup_sequence(calldata->clp, &calldata->arg.seq_args,
|
||||||
|
&calldata->res.seq_res, 0, task))
|
||||||
|
return;
|
||||||
|
|
||||||
|
rpc_call_start(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data)
|
||||||
|
{
|
||||||
|
struct nfs4_reclaim_complete_data *calldata = data;
|
||||||
|
struct nfs_client *clp = calldata->clp;
|
||||||
|
struct nfs4_sequence_res *res = &calldata->res.seq_res;
|
||||||
|
|
||||||
|
dprintk("--> %s\n", __func__);
|
||||||
|
nfs41_sequence_done(clp, res, task->tk_status);
|
||||||
|
switch (task->tk_status) {
|
||||||
|
case 0:
|
||||||
|
case -NFS4ERR_COMPLETE_ALREADY:
|
||||||
|
break;
|
||||||
|
case -NFS4ERR_BADSESSION:
|
||||||
|
case -NFS4ERR_DEADSESSION:
|
||||||
|
/*
|
||||||
|
* Handle the session error, but do not retry the operation, as
|
||||||
|
* we have no way of telling whether the clientid had to be
|
||||||
|
* reset before we got our reply. If reset, a new wave of
|
||||||
|
* reclaim operations will follow, containing their own reclaim
|
||||||
|
* complete. We don't want our retry to get on the way of
|
||||||
|
* recovery by incorrectly indicating to the server that we're
|
||||||
|
* done reclaiming state since the process had to be restarted.
|
||||||
|
*/
|
||||||
|
_nfs4_async_handle_error(task, NULL, clp, NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (_nfs4_async_handle_error(
|
||||||
|
task, NULL, clp, NULL) == -EAGAIN) {
|
||||||
|
rpc_restart_call_prepare(task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nfs41_sequence_free_slot(clp, res);
|
||||||
|
|
||||||
|
dprintk("<-- %s\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfs4_free_reclaim_complete_data(void *data)
|
||||||
|
{
|
||||||
|
struct nfs4_reclaim_complete_data *calldata = data;
|
||||||
|
|
||||||
|
kfree(calldata);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct rpc_call_ops nfs4_reclaim_complete_call_ops = {
|
||||||
|
.rpc_call_prepare = nfs4_reclaim_complete_prepare,
|
||||||
|
.rpc_call_done = nfs4_reclaim_complete_done,
|
||||||
|
.rpc_release = nfs4_free_reclaim_complete_data,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Issue a global reclaim complete.
|
||||||
|
*/
|
||||||
|
static int nfs41_proc_reclaim_complete(struct nfs_client *clp)
|
||||||
|
{
|
||||||
|
struct nfs4_reclaim_complete_data *calldata;
|
||||||
|
struct rpc_task *task;
|
||||||
|
struct rpc_message msg = {
|
||||||
|
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RECLAIM_COMPLETE],
|
||||||
|
};
|
||||||
|
struct rpc_task_setup task_setup_data = {
|
||||||
|
.rpc_client = clp->cl_rpcclient,
|
||||||
|
.rpc_message = &msg,
|
||||||
|
.callback_ops = &nfs4_reclaim_complete_call_ops,
|
||||||
|
.flags = RPC_TASK_ASYNC,
|
||||||
|
};
|
||||||
|
int status = -ENOMEM;
|
||||||
|
|
||||||
|
dprintk("--> %s\n", __func__);
|
||||||
|
calldata = kzalloc(sizeof(*calldata), GFP_KERNEL);
|
||||||
|
if (calldata == NULL)
|
||||||
|
goto out;
|
||||||
|
calldata->clp = clp;
|
||||||
|
calldata->arg.one_fs = 0;
|
||||||
|
calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
|
||||||
|
|
||||||
|
msg.rpc_argp = &calldata->arg;
|
||||||
|
msg.rpc_resp = &calldata->res;
|
||||||
|
task_setup_data.callback_data = calldata;
|
||||||
|
task = rpc_run_task(&task_setup_data);
|
||||||
|
if (IS_ERR(task))
|
||||||
|
status = PTR_ERR(task);
|
||||||
|
rpc_put_task(task);
|
||||||
|
out:
|
||||||
|
dprintk("<-- %s status=%d\n", __func__, status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
#endif /* CONFIG_NFS_V4_1 */
|
#endif /* CONFIG_NFS_V4_1 */
|
||||||
|
|
||||||
struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
|
struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
|
||||||
@ -4990,6 +5094,7 @@ struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
|
|||||||
.recover_lock = nfs4_lock_reclaim,
|
.recover_lock = nfs4_lock_reclaim,
|
||||||
.establish_clid = nfs41_init_clientid,
|
.establish_clid = nfs41_init_clientid,
|
||||||
.get_clid_cred = nfs4_get_exchange_id_cred,
|
.get_clid_cred = nfs4_get_exchange_id_cred,
|
||||||
|
.reclaim_complete = nfs41_proc_reclaim_complete,
|
||||||
};
|
};
|
||||||
#endif /* CONFIG_NFS_V4_1 */
|
#endif /* CONFIG_NFS_V4_1 */
|
||||||
|
|
||||||
|
@ -1032,6 +1032,14 @@ static void nfs4_state_start_reclaim_reboot(struct nfs_client *clp)
|
|||||||
nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_reboot);
|
nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_reboot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nfs4_reclaim_complete(struct nfs_client *clp,
|
||||||
|
const struct nfs4_state_recovery_ops *ops)
|
||||||
|
{
|
||||||
|
/* Notify the server we're done reclaiming our state */
|
||||||
|
if (ops->reclaim_complete)
|
||||||
|
(void)ops->reclaim_complete(clp);
|
||||||
|
}
|
||||||
|
|
||||||
static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
|
static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
|
||||||
{
|
{
|
||||||
struct nfs4_state_owner *sp;
|
struct nfs4_state_owner *sp;
|
||||||
|
Loading…
Reference in New Issue
Block a user