aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/nfs4_fs.h1
-rw-r--r--fs/nfs/nfs4proc.c105
-rw-r--r--fs/nfs/nfs4state.c8
3 files changed, 114 insertions, 0 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 9a866368896a..90923223a7c1 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -181,6 +181,7 @@ struct nfs4_state_recovery_ops {
181 int (*recover_lock)(struct nfs4_state *, struct file_lock *); 181 int (*recover_lock)(struct nfs4_state *, struct file_lock *);
182 int (*establish_clid)(struct nfs_client *, struct rpc_cred *); 182 int (*establish_clid)(struct nfs_client *, struct rpc_cred *);
183 struct rpc_cred * (*get_clid_cred)(struct nfs_client *); 183 struct rpc_cred * (*get_clid_cred)(struct nfs_client *);
184 int (*reclaim_complete)(struct nfs_client *);
184}; 185};
185 186
186struct nfs4_state_maintenance_ops { 187struct nfs4_state_maintenance_ops {
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 71993f122214..206ce30a595d 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -4971,6 +4971,110 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp,
4971 &nfs41_sequence_ops, (void *)clp); 4971 &nfs41_sequence_ops, (void *)clp);
4972} 4972}
4973 4973
4974struct nfs4_reclaim_complete_data {
4975 struct nfs_client *clp;
4976 struct nfs41_reclaim_complete_args arg;
4977 struct nfs41_reclaim_complete_res res;
4978};
4979
4980static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data)
4981{
4982 struct nfs4_reclaim_complete_data *calldata = data;
4983
4984 if (nfs4_setup_sequence(calldata->clp, &calldata->arg.seq_args,
4985 &calldata->res.seq_res, 0, task))
4986 return;
4987
4988 rpc_call_start(task);
4989}
4990
4991static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data)
4992{
4993 struct nfs4_reclaim_complete_data *calldata = data;
4994 struct nfs_client *clp = calldata->clp;
4995 struct nfs4_sequence_res *res = &calldata->res.seq_res;
4996
4997 dprintk("--> %s\n", __func__);
4998 nfs41_sequence_done(clp, res, task->tk_status);
4999 switch (task->tk_status) {
5000 case 0:
5001 case -NFS4ERR_COMPLETE_ALREADY:
5002 break;
5003 case -NFS4ERR_BADSESSION:
5004 case -NFS4ERR_DEADSESSION:
5005 /*
5006 * Handle the session error, but do not retry the operation, as
5007 * we have no way of telling whether the clientid had to be
5008 * reset before we got our reply. If reset, a new wave of
5009 * reclaim operations will follow, containing their own reclaim
5010 * complete. We don't want our retry to get on the way of
5011 * recovery by incorrectly indicating to the server that we're
5012 * done reclaiming state since the process had to be restarted.
5013 */
5014 _nfs4_async_handle_error(task, NULL, clp, NULL);
5015 break;
5016 default:
5017 if (_nfs4_async_handle_error(
5018 task, NULL, clp, NULL) == -EAGAIN) {
5019 rpc_restart_call_prepare(task);
5020 return;
5021 }
5022 }
5023 nfs41_sequence_free_slot(clp, res);
5024
5025 dprintk("<-- %s\n", __func__);
5026}
5027
5028static void nfs4_free_reclaim_complete_data(void *data)
5029{
5030 struct nfs4_reclaim_complete_data *calldata = data;
5031
5032 kfree(calldata);
5033}
5034
5035static const struct rpc_call_ops nfs4_reclaim_complete_call_ops = {
5036 .rpc_call_prepare = nfs4_reclaim_complete_prepare,
5037 .rpc_call_done = nfs4_reclaim_complete_done,
5038 .rpc_release = nfs4_free_reclaim_complete_data,
5039};
5040
5041/*
5042 * Issue a global reclaim complete.
5043 */
5044static int nfs41_proc_reclaim_complete(struct nfs_client *clp)
5045{
5046 struct nfs4_reclaim_complete_data *calldata;
5047 struct rpc_task *task;
5048 struct rpc_message msg = {
5049 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RECLAIM_COMPLETE],
5050 };
5051 struct rpc_task_setup task_setup_data = {
5052 .rpc_client = clp->cl_rpcclient,
5053 .rpc_message = &msg,
5054 .callback_ops = &nfs4_reclaim_complete_call_ops,
5055 .flags = RPC_TASK_ASYNC,
5056 };
5057 int status = -ENOMEM;
5058
5059 dprintk("--> %s\n", __func__);
5060 calldata = kzalloc(sizeof(*calldata), GFP_KERNEL);
5061 if (calldata == NULL)
5062 goto out;
5063 calldata->clp = clp;
5064 calldata->arg.one_fs = 0;
5065 calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
5066
5067 msg.rpc_argp = &calldata->arg;
5068 msg.rpc_resp = &calldata->res;
5069 task_setup_data.callback_data = calldata;
5070 task = rpc_run_task(&task_setup_data);
5071 if (IS_ERR(task))
5072 status = PTR_ERR(task);
5073 rpc_put_task(task);
5074out:
5075 dprintk("<-- %s status=%d\n", __func__, status);
5076 return status;
5077}
4974#endif /* CONFIG_NFS_V4_1 */ 5078#endif /* CONFIG_NFS_V4_1 */
4975 5079
4976struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { 5080struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
@@ -4990,6 +5094,7 @@ struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
4990 .recover_lock = nfs4_lock_reclaim, 5094 .recover_lock = nfs4_lock_reclaim,
4991 .establish_clid = nfs41_init_clientid, 5095 .establish_clid = nfs41_init_clientid,
4992 .get_clid_cred = nfs4_get_exchange_id_cred, 5096 .get_clid_cred = nfs4_get_exchange_id_cred,
5097 .reclaim_complete = nfs41_proc_reclaim_complete,
4993}; 5098};
4994#endif /* CONFIG_NFS_V4_1 */ 5099#endif /* CONFIG_NFS_V4_1 */
4995 5100
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index bc4ca6f4d8c6..f2d2dc497551 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1032,6 +1032,14 @@ static void nfs4_state_start_reclaim_reboot(struct nfs_client *clp)
1032 nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_reboot); 1032 nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_reboot);
1033} 1033}
1034 1034
1035static void nfs4_reclaim_complete(struct nfs_client *clp,
1036 const struct nfs4_state_recovery_ops *ops)
1037{
1038 /* Notify the server we're done reclaiming our state */
1039 if (ops->reclaim_complete)
1040 (void)ops->reclaim_complete(clp);
1041}
1042
1035static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp) 1043static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
1036{ 1044{
1037 struct nfs4_state_owner *sp; 1045 struct nfs4_state_owner *sp;