xref: /linux/drivers/md/dm-vdo/admin-state.c (revision d358e5254674b70f34c847715ca509e46eb81e6f)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright 2023 Red Hat
4  */
5 
6 #include "admin-state.h"
7 
8 #include "logger.h"
9 #include "memory-alloc.h"
10 #include "permassert.h"
11 
12 #include "completion.h"
13 #include "types.h"
14 
15 static const struct admin_state_code VDO_CODE_NORMAL_OPERATION = {
16 	.name = "VDO_ADMIN_STATE_NORMAL_OPERATION",
17 	.normal = true,
18 };
19 const struct admin_state_code *VDO_ADMIN_STATE_NORMAL_OPERATION = &VDO_CODE_NORMAL_OPERATION;
20 static const struct admin_state_code VDO_CODE_OPERATING = {
21 	.name = "VDO_ADMIN_STATE_OPERATING",
22 	.normal = true,
23 	.operating = true,
24 };
25 const struct admin_state_code *VDO_ADMIN_STATE_OPERATING = &VDO_CODE_OPERATING;
26 static const struct admin_state_code VDO_CODE_FORMATTING = {
27 	.name = "VDO_ADMIN_STATE_FORMATTING",
28 	.operating = true,
29 	.loading = true,
30 };
31 const struct admin_state_code *VDO_ADMIN_STATE_FORMATTING = &VDO_CODE_FORMATTING;
32 static const struct admin_state_code VDO_CODE_PRE_LOADING = {
33 	.name = "VDO_ADMIN_STATE_PRE_LOADING",
34 	.operating = true,
35 	.loading = true,
36 };
37 const struct admin_state_code *VDO_ADMIN_STATE_PRE_LOADING = &VDO_CODE_PRE_LOADING;
38 static const struct admin_state_code VDO_CODE_PRE_LOADED = {
39 	.name = "VDO_ADMIN_STATE_PRE_LOADED",
40 };
41 const struct admin_state_code *VDO_ADMIN_STATE_PRE_LOADED = &VDO_CODE_PRE_LOADED;
42 static const struct admin_state_code VDO_CODE_LOADING = {
43 	.name = "VDO_ADMIN_STATE_LOADING",
44 	.normal = true,
45 	.operating = true,
46 	.loading = true,
47 };
48 const struct admin_state_code *VDO_ADMIN_STATE_LOADING = &VDO_CODE_LOADING;
49 static const struct admin_state_code VDO_CODE_LOADING_FOR_RECOVERY = {
50 	.name = "VDO_ADMIN_STATE_LOADING_FOR_RECOVERY",
51 	.operating = true,
52 	.loading = true,
53 };
54 const struct admin_state_code *VDO_ADMIN_STATE_LOADING_FOR_RECOVERY =
55 	&VDO_CODE_LOADING_FOR_RECOVERY;
56 static const struct admin_state_code VDO_CODE_LOADING_FOR_REBUILD = {
57 	.name = "VDO_ADMIN_STATE_LOADING_FOR_REBUILD",
58 	.operating = true,
59 	.loading = true,
60 };
61 const struct admin_state_code *VDO_ADMIN_STATE_LOADING_FOR_REBUILD = &VDO_CODE_LOADING_FOR_REBUILD;
62 static const struct admin_state_code VDO_CODE_WAITING_FOR_RECOVERY = {
63 	.name = "VDO_ADMIN_STATE_WAITING_FOR_RECOVERY",
64 	.operating = true,
65 };
66 const struct admin_state_code *VDO_ADMIN_STATE_WAITING_FOR_RECOVERY =
67 	&VDO_CODE_WAITING_FOR_RECOVERY;
68 static const struct admin_state_code VDO_CODE_NEW = {
69 	.name = "VDO_ADMIN_STATE_NEW",
70 	.quiescent = true,
71 };
72 const struct admin_state_code *VDO_ADMIN_STATE_NEW = &VDO_CODE_NEW;
73 static const struct admin_state_code VDO_CODE_INITIALIZED = {
74 	.name = "VDO_ADMIN_STATE_INITIALIZED",
75 };
76 const struct admin_state_code *VDO_ADMIN_STATE_INITIALIZED = &VDO_CODE_INITIALIZED;
77 static const struct admin_state_code VDO_CODE_RECOVERING = {
78 	.name = "VDO_ADMIN_STATE_RECOVERING",
79 	.draining = true,
80 	.operating = true,
81 };
82 const struct admin_state_code *VDO_ADMIN_STATE_RECOVERING = &VDO_CODE_RECOVERING;
83 static const struct admin_state_code VDO_CODE_REBUILDING = {
84 	.name = "VDO_ADMIN_STATE_REBUILDING",
85 	.draining = true,
86 	.operating = true,
87 };
88 const struct admin_state_code *VDO_ADMIN_STATE_REBUILDING = &VDO_CODE_REBUILDING;
89 static const struct admin_state_code VDO_CODE_SAVING = {
90 	.name = "VDO_ADMIN_STATE_SAVING",
91 	.draining = true,
92 	.quiescing = true,
93 	.operating = true,
94 };
95 const struct admin_state_code *VDO_ADMIN_STATE_SAVING = &VDO_CODE_SAVING;
96 static const struct admin_state_code VDO_CODE_SAVED = {
97 	.name = "VDO_ADMIN_STATE_SAVED",
98 	.quiescent = true,
99 };
100 const struct admin_state_code *VDO_ADMIN_STATE_SAVED = &VDO_CODE_SAVED;
101 static const struct admin_state_code VDO_CODE_SCRUBBING = {
102 	.name = "VDO_ADMIN_STATE_SCRUBBING",
103 	.draining = true,
104 	.loading = true,
105 	.operating = true,
106 };
107 const struct admin_state_code *VDO_ADMIN_STATE_SCRUBBING = &VDO_CODE_SCRUBBING;
108 static const struct admin_state_code VDO_CODE_SAVE_FOR_SCRUBBING = {
109 	.name = "VDO_ADMIN_STATE_SAVE_FOR_SCRUBBING",
110 	.draining = true,
111 	.operating = true,
112 };
113 const struct admin_state_code *VDO_ADMIN_STATE_SAVE_FOR_SCRUBBING = &VDO_CODE_SAVE_FOR_SCRUBBING;
114 static const struct admin_state_code VDO_CODE_STOPPING = {
115 	.name = "VDO_ADMIN_STATE_STOPPING",
116 	.draining = true,
117 	.quiescing = true,
118 	.operating = true,
119 };
120 const struct admin_state_code *VDO_ADMIN_STATE_STOPPING = &VDO_CODE_STOPPING;
121 static const struct admin_state_code VDO_CODE_STOPPED = {
122 	.name = "VDO_ADMIN_STATE_STOPPED",
123 	.quiescent = true,
124 };
125 const struct admin_state_code *VDO_ADMIN_STATE_STOPPED = &VDO_CODE_STOPPED;
126 static const struct admin_state_code VDO_CODE_SUSPENDING = {
127 	.name = "VDO_ADMIN_STATE_SUSPENDING",
128 	.draining = true,
129 	.quiescing = true,
130 	.operating = true,
131 };
132 const struct admin_state_code *VDO_ADMIN_STATE_SUSPENDING = &VDO_CODE_SUSPENDING;
133 static const struct admin_state_code VDO_CODE_SUSPENDED = {
134 	.name = "VDO_ADMIN_STATE_SUSPENDED",
135 	.quiescent = true,
136 };
137 const struct admin_state_code *VDO_ADMIN_STATE_SUSPENDED = &VDO_CODE_SUSPENDED;
138 static const struct admin_state_code VDO_CODE_SUSPENDED_OPERATION = {
139 	.name = "VDO_ADMIN_STATE_SUSPENDED_OPERATION",
140 	.operating = true,
141 };
142 const struct admin_state_code *VDO_ADMIN_STATE_SUSPENDED_OPERATION = &VDO_CODE_SUSPENDED_OPERATION;
143 static const struct admin_state_code VDO_CODE_RESUMING = {
144 	.name = "VDO_ADMIN_STATE_RESUMING",
145 	.operating = true,
146 };
147 const struct admin_state_code *VDO_ADMIN_STATE_RESUMING = &VDO_CODE_RESUMING;
148 
149 /**
150  * get_next_state() - Determine the state which should be set after a given operation completes
151  *                    based on the operation and the current state.
152  * @state: The current admin state.
153  * @operation: The operation to be started.
154  *
155  * Return: The state to set when the operation completes or NULL if the operation can not be
156  *         started in the current state.
157  */
get_next_state(const struct admin_state * state,const struct admin_state_code * operation)158 static const struct admin_state_code *get_next_state(const struct admin_state *state,
159 						     const struct admin_state_code *operation)
160 {
161 	const struct admin_state_code *code = vdo_get_admin_state_code(state);
162 
163 	if (code->operating)
164 		return NULL;
165 
166 	if (operation == VDO_ADMIN_STATE_SAVING)
167 		return (code == VDO_ADMIN_STATE_NORMAL_OPERATION ? VDO_ADMIN_STATE_SAVED : NULL);
168 
169 	if (operation == VDO_ADMIN_STATE_SUSPENDING) {
170 		return (code == VDO_ADMIN_STATE_NORMAL_OPERATION
171 			? VDO_ADMIN_STATE_SUSPENDED
172 			: NULL);
173 	}
174 
175 	if (operation == VDO_ADMIN_STATE_STOPPING)
176 		return (code == VDO_ADMIN_STATE_NORMAL_OPERATION ? VDO_ADMIN_STATE_STOPPED : NULL);
177 
178 	if (operation == VDO_ADMIN_STATE_PRE_LOADING)
179 		return (code == VDO_ADMIN_STATE_INITIALIZED ? VDO_ADMIN_STATE_PRE_LOADED : NULL);
180 
181 	if (operation == VDO_ADMIN_STATE_SUSPENDED_OPERATION) {
182 		return (((code == VDO_ADMIN_STATE_SUSPENDED) ||
183 			 (code == VDO_ADMIN_STATE_SAVED)) ? code : NULL);
184 	}
185 
186 	return VDO_ADMIN_STATE_NORMAL_OPERATION;
187 }
188 
189 /**
190  * vdo_finish_operation() - Finish the current operation.
191  * @state: The current admin state.
192  * @result: The result of the operation.
193  *
194  * Will notify the operation waiter if there is one. This method should be used for operations
195  * started with vdo_start_operation(). For operations which were started with vdo_start_draining(),
196  * use vdo_finish_draining() instead.
197  *
198  * Return: true if there was an operation to finish.
199  */
vdo_finish_operation(struct admin_state * state,int result)200 bool vdo_finish_operation(struct admin_state *state, int result)
201 {
202 	if (!vdo_get_admin_state_code(state)->operating)
203 		return false;
204 
205 	state->complete = state->starting;
206 	if (state->waiter != NULL)
207 		vdo_set_completion_result(state->waiter, result);
208 
209 	if (!state->starting) {
210 		vdo_set_admin_state_code(state, state->next_state);
211 		if (state->waiter != NULL)
212 			vdo_launch_completion(vdo_forget(state->waiter));
213 	}
214 
215 	return true;
216 }
217 
218 /**
219  * begin_operation() - Begin an operation if it may be started given the current state.
220  * @state: The current admin state.
221  * @operation: The operation to be started.
222  * @waiter: A completion to notify when the operation is complete; may be NULL.
223  * @initiator: The vdo_admin_initiator_fn to call if the operation may begin; may be NULL.
224  *
225  * Return: VDO_SUCCESS or an error.
226  */
begin_operation(struct admin_state * state,const struct admin_state_code * operation,struct vdo_completion * waiter,vdo_admin_initiator_fn initiator)227 static int __must_check begin_operation(struct admin_state *state,
228 					const struct admin_state_code *operation,
229 					struct vdo_completion *waiter,
230 					vdo_admin_initiator_fn initiator)
231 {
232 	int result;
233 	const struct admin_state_code *next_state = get_next_state(state, operation);
234 
235 	if (next_state == NULL) {
236 		result = vdo_log_error_strerror(VDO_INVALID_ADMIN_STATE,
237 						"Can't start %s from %s",
238 						operation->name,
239 						vdo_get_admin_state_code(state)->name);
240 	} else if (state->waiter != NULL) {
241 		result = vdo_log_error_strerror(VDO_COMPONENT_BUSY,
242 						"Can't start %s with extant waiter",
243 						operation->name);
244 	} else {
245 		state->waiter = waiter;
246 		state->next_state = next_state;
247 		vdo_set_admin_state_code(state, operation);
248 		if (initiator != NULL) {
249 			state->starting = true;
250 			initiator(state);
251 			state->starting = false;
252 			if (state->complete)
253 				vdo_finish_operation(state, VDO_SUCCESS);
254 		}
255 
256 		return VDO_SUCCESS;
257 	}
258 
259 	if (waiter != NULL)
260 		vdo_continue_completion(waiter, result);
261 
262 	return result;
263 }
264 
265 /**
266  * start_operation() - Start an operation if it may be started given the current state.
267  * @state: The current admin state.
268  * @operation: The operation to be started.
269  * @waiter: A completion to notify when the operation is complete; may be NULL.
270  * @initiator: The vdo_admin_initiator_fn to call if the operation may begin; may be NULL.
271  *
272  * Return: true if the operation was started.
273  */
start_operation(struct admin_state * state,const struct admin_state_code * operation,struct vdo_completion * waiter,vdo_admin_initiator_fn initiator)274 static inline bool __must_check start_operation(struct admin_state *state,
275 						const struct admin_state_code *operation,
276 						struct vdo_completion *waiter,
277 						vdo_admin_initiator_fn initiator)
278 {
279 	return (begin_operation(state, operation, waiter, initiator) == VDO_SUCCESS);
280 }
281 
282 /**
283  * check_code() - Check the result of a state validation.
284  * @valid: True if the code is of an appropriate type.
285  * @code: The code which failed to be of the correct type.
286  * @what: What the code failed to be, for logging.
287  * @waiter: The completion to notify of the error; may be NULL.
288  *
289  * If the result failed, log an invalid state error and, if there is a waiter, notify it.
290  *
291  * Return: The result of the check.
292  */
check_code(bool valid,const struct admin_state_code * code,const char * what,struct vdo_completion * waiter)293 static bool check_code(bool valid, const struct admin_state_code *code, const char *what,
294 		       struct vdo_completion *waiter)
295 {
296 	int result;
297 
298 	if (valid)
299 		return true;
300 
301 	result = vdo_log_error_strerror(VDO_INVALID_ADMIN_STATE,
302 					"%s is not a %s", code->name, what);
303 	if (waiter != NULL)
304 		vdo_continue_completion(waiter, result);
305 
306 	return false;
307 }
308 
309 /**
310  * assert_vdo_drain_operation() - Check that an operation is a drain.
311  * @operation: The operation to check.
312  * @waiter: The completion to finish with an error if the operation is not a drain.
313  *
314  * Return: true if the specified operation is a drain.
315  */
assert_vdo_drain_operation(const struct admin_state_code * operation,struct vdo_completion * waiter)316 static bool __must_check assert_vdo_drain_operation(const struct admin_state_code *operation,
317 						    struct vdo_completion *waiter)
318 {
319 	return check_code(operation->draining, operation, "drain operation", waiter);
320 }
321 
322 /**
323  * vdo_start_draining() - Initiate a drain operation if the current state permits it.
324  * @state: The current admin state.
325  * @operation: The type of drain to initiate.
326  * @waiter: The completion to notify when the drain is complete.
327  * @initiator: The vdo_admin_initiator_fn to call if the operation may begin; may be NULL.
328  *
329  * Return: true if the drain was initiated, if not the waiter will be notified.
330  */
vdo_start_draining(struct admin_state * state,const struct admin_state_code * operation,struct vdo_completion * waiter,vdo_admin_initiator_fn initiator)331 bool vdo_start_draining(struct admin_state *state,
332 			const struct admin_state_code *operation,
333 			struct vdo_completion *waiter, vdo_admin_initiator_fn initiator)
334 {
335 	const struct admin_state_code *code = vdo_get_admin_state_code(state);
336 
337 	if (!assert_vdo_drain_operation(operation, waiter))
338 		return false;
339 
340 	if (code->quiescent) {
341 		vdo_launch_completion(waiter);
342 		return false;
343 	}
344 
345 	if (!code->normal) {
346 		vdo_log_error_strerror(VDO_INVALID_ADMIN_STATE, "can't start %s from %s",
347 				       operation->name, code->name);
348 		vdo_continue_completion(waiter, VDO_INVALID_ADMIN_STATE);
349 		return false;
350 	}
351 
352 	return start_operation(state, operation, waiter, initiator);
353 }
354 
355 /**
356  * vdo_finish_draining() - Finish a drain operation if one was in progress.
357  * @state: The current admin state.
358  *
359  * Return: true if the state was draining; will notify the waiter if so.
360  */
vdo_finish_draining(struct admin_state * state)361 bool vdo_finish_draining(struct admin_state *state)
362 {
363 	return vdo_finish_draining_with_result(state, VDO_SUCCESS);
364 }
365 
366 /**
367  * vdo_finish_draining_with_result() - Finish a drain operation with a status code.
368  * @state: The current admin state.
369  * @result: The result of the drain operation.
370  *
371  * Return: true if the state was draining; will notify the waiter if so.
372  */
vdo_finish_draining_with_result(struct admin_state * state,int result)373 bool vdo_finish_draining_with_result(struct admin_state *state, int result)
374 {
375 	return (vdo_is_state_draining(state) && vdo_finish_operation(state, result));
376 }
377 
378 /**
379  * vdo_assert_load_operation() - Check that an operation is a load.
380  * @operation: The operation to check.
381  * @waiter: The completion to finish with an error if the operation is not a load.
382  *
383  * Return: true if the specified operation is a load.
384  */
vdo_assert_load_operation(const struct admin_state_code * operation,struct vdo_completion * waiter)385 bool vdo_assert_load_operation(const struct admin_state_code *operation,
386 			       struct vdo_completion *waiter)
387 {
388 	return check_code(operation->loading, operation, "load operation", waiter);
389 }
390 
391 /**
392  * vdo_start_loading() - Initiate a load operation if the current state permits it.
393  * @state: The current admin state.
394  * @operation: The type of load to initiate.
395  * @waiter: The completion to notify when the load is complete; may be NULL.
396  * @initiator: The vdo_admin_initiator_fn to call if the operation may begin; may be NULL.
397  *
398  * Return: true if the load was initiated, if not the waiter will be notified.
399  */
vdo_start_loading(struct admin_state * state,const struct admin_state_code * operation,struct vdo_completion * waiter,vdo_admin_initiator_fn initiator)400 bool vdo_start_loading(struct admin_state *state,
401 		       const struct admin_state_code *operation,
402 		       struct vdo_completion *waiter, vdo_admin_initiator_fn initiator)
403 {
404 	return (vdo_assert_load_operation(operation, waiter) &&
405 		start_operation(state, operation, waiter, initiator));
406 }
407 
408 /**
409  * vdo_finish_loading() - Finish a load operation if one was in progress.
410  * @state: The current admin state.
411  *
412  * Return: true if the state was loading; will notify the waiter if so.
413  */
vdo_finish_loading(struct admin_state * state)414 bool vdo_finish_loading(struct admin_state *state)
415 {
416 	return vdo_finish_loading_with_result(state, VDO_SUCCESS);
417 }
418 
419 /**
420  * vdo_finish_loading_with_result() - Finish a load operation with a status code.
421  * @state: The current admin state.
422  * @result: The result of the load operation.
423  *
424  * Return: true if the state was loading; will notify the waiter if so.
425  */
vdo_finish_loading_with_result(struct admin_state * state,int result)426 bool vdo_finish_loading_with_result(struct admin_state *state, int result)
427 {
428 	return (vdo_is_state_loading(state) && vdo_finish_operation(state, result));
429 }
430 
431 /**
432  * assert_vdo_resume_operation() - Check whether an admin_state_code is a resume operation.
433  * @operation: The operation to check.
434  * @waiter: The completion to notify if the operation is not a resume operation; may be NULL.
435  *
436  * Return: true if the code is a resume operation.
437  */
assert_vdo_resume_operation(const struct admin_state_code * operation,struct vdo_completion * waiter)438 static bool __must_check assert_vdo_resume_operation(const struct admin_state_code *operation,
439 						     struct vdo_completion *waiter)
440 {
441 	return check_code(operation == VDO_ADMIN_STATE_RESUMING, operation,
442 			  "resume operation", waiter);
443 }
444 
445 /**
446  * vdo_start_resuming() - Initiate a resume operation if the current state permits it.
447  * @state: The current admin state.
448  * @operation: The type of resume to start.
449  * @waiter: The completion to notify when the resume is complete; may be NULL.
450  * @initiator: The vdo_admin_initiator_fn to call if the operation may begin; may be NULL.
451  *
452  * Return: true if the resume was initiated, if not the waiter will be notified.
453  */
vdo_start_resuming(struct admin_state * state,const struct admin_state_code * operation,struct vdo_completion * waiter,vdo_admin_initiator_fn initiator)454 bool vdo_start_resuming(struct admin_state *state,
455 			const struct admin_state_code *operation,
456 			struct vdo_completion *waiter, vdo_admin_initiator_fn initiator)
457 {
458 	return (assert_vdo_resume_operation(operation, waiter) &&
459 		start_operation(state, operation, waiter, initiator));
460 }
461 
462 /**
463  * vdo_finish_resuming() - Finish a resume operation if one was in progress.
464  * @state: The current admin state.
465  *
466  * Return: true if the state was resuming; will notify the waiter if so.
467  */
vdo_finish_resuming(struct admin_state * state)468 bool vdo_finish_resuming(struct admin_state *state)
469 {
470 	return vdo_finish_resuming_with_result(state, VDO_SUCCESS);
471 }
472 
473 /**
474  * vdo_finish_resuming_with_result() - Finish a resume operation with a status code.
475  * @state: The current admin state.
476  * @result: The result of the resume operation.
477  *
478  * Return: true if the state was resuming; will notify the waiter if so.
479  */
vdo_finish_resuming_with_result(struct admin_state * state,int result)480 bool vdo_finish_resuming_with_result(struct admin_state *state, int result)
481 {
482 	return (vdo_is_state_resuming(state) && vdo_finish_operation(state, result));
483 }
484 
485 /**
486  * vdo_resume_if_quiescent() - Change the state to normal operation if the current state is
487  *                             quiescent.
488  * @state: The current admin state.
489  *
490  * Return: VDO_SUCCESS if the state resumed, VDO_INVALID_ADMIN_STATE otherwise.
491  */
vdo_resume_if_quiescent(struct admin_state * state)492 int vdo_resume_if_quiescent(struct admin_state *state)
493 {
494 	if (!vdo_is_state_quiescent(state))
495 		return VDO_INVALID_ADMIN_STATE;
496 
497 	vdo_set_admin_state_code(state, VDO_ADMIN_STATE_NORMAL_OPERATION);
498 	return VDO_SUCCESS;
499 }
500 
501 /**
502  * vdo_start_operation() - Attempt to start an operation.
503  * @state: The current admin state.
504  * @operation: The operation to attempt to start.
505  *
506  * Return: VDO_SUCCESS if the operation was started, VDO_INVALID_ADMIN_STATE if not
507  */
vdo_start_operation(struct admin_state * state,const struct admin_state_code * operation)508 int vdo_start_operation(struct admin_state *state,
509 			const struct admin_state_code *operation)
510 {
511 	return vdo_start_operation_with_waiter(state, operation, NULL, NULL);
512 }
513 
514 /**
515  * vdo_start_operation_with_waiter() - Attempt to start an operation.
516  * @state: The current admin state.
517  * @operation: The operation to attempt to start.
518  * @waiter: The completion to notify when the operation completes or fails to start; may be NULL.
519  * @initiator: The vdo_admin_initiator_fn to call if the operation may begin; may be NULL.
520  *
521  * Return: VDO_SUCCESS if the operation was started, VDO_INVALID_ADMIN_STATE if not
522  */
vdo_start_operation_with_waiter(struct admin_state * state,const struct admin_state_code * operation,struct vdo_completion * waiter,vdo_admin_initiator_fn initiator)523 int vdo_start_operation_with_waiter(struct admin_state *state,
524 				    const struct admin_state_code *operation,
525 				    struct vdo_completion *waiter,
526 				    vdo_admin_initiator_fn initiator)
527 {
528 	return (check_code(operation->operating, operation, "operation", waiter) ?
529 		begin_operation(state, operation, waiter, initiator) :
530 		VDO_INVALID_ADMIN_STATE);
531 }
532