diff options
-rw-r--r-- | fs/nfs/nfs4_fs.h | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 105 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 8 |
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 | ||
186 | struct nfs4_state_maintenance_ops { | 187 | struct 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 | ||
4974 | struct 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 | |||
4980 | static 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 | |||
4991 | static 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 | |||
5028 | static void nfs4_free_reclaim_complete_data(void *data) | ||
5029 | { | ||
5030 | struct nfs4_reclaim_complete_data *calldata = data; | ||
5031 | |||
5032 | kfree(calldata); | ||
5033 | } | ||
5034 | |||
5035 | static 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 | */ | ||
5044 | static 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); | ||
5074 | out: | ||
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 | ||
4976 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | 5080 | struct 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 | ||
1035 | static 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 | |||
1035 | static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp) | 1043 | static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp) |
1036 | { | 1044 | { |
1037 | struct nfs4_state_owner *sp; | 1045 | struct nfs4_state_owner *sp; |