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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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