Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 531 lines 18 kB view raw
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 15static const struct admin_state_code VDO_CODE_NORMAL_OPERATION = { 16 .name = "VDO_ADMIN_STATE_NORMAL_OPERATION", 17 .normal = true, 18}; 19const struct admin_state_code *VDO_ADMIN_STATE_NORMAL_OPERATION = &VDO_CODE_NORMAL_OPERATION; 20static const struct admin_state_code VDO_CODE_OPERATING = { 21 .name = "VDO_ADMIN_STATE_OPERATING", 22 .normal = true, 23 .operating = true, 24}; 25const struct admin_state_code *VDO_ADMIN_STATE_OPERATING = &VDO_CODE_OPERATING; 26static const struct admin_state_code VDO_CODE_FORMATTING = { 27 .name = "VDO_ADMIN_STATE_FORMATTING", 28 .operating = true, 29 .loading = true, 30}; 31const struct admin_state_code *VDO_ADMIN_STATE_FORMATTING = &VDO_CODE_FORMATTING; 32static const struct admin_state_code VDO_CODE_PRE_LOADING = { 33 .name = "VDO_ADMIN_STATE_PRE_LOADING", 34 .operating = true, 35 .loading = true, 36}; 37const struct admin_state_code *VDO_ADMIN_STATE_PRE_LOADING = &VDO_CODE_PRE_LOADING; 38static const struct admin_state_code VDO_CODE_PRE_LOADED = { 39 .name = "VDO_ADMIN_STATE_PRE_LOADED", 40}; 41const struct admin_state_code *VDO_ADMIN_STATE_PRE_LOADED = &VDO_CODE_PRE_LOADED; 42static const struct admin_state_code VDO_CODE_LOADING = { 43 .name = "VDO_ADMIN_STATE_LOADING", 44 .normal = true, 45 .operating = true, 46 .loading = true, 47}; 48const struct admin_state_code *VDO_ADMIN_STATE_LOADING = &VDO_CODE_LOADING; 49static 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}; 54const struct admin_state_code *VDO_ADMIN_STATE_LOADING_FOR_RECOVERY = 55 &VDO_CODE_LOADING_FOR_RECOVERY; 56static 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}; 61const struct admin_state_code *VDO_ADMIN_STATE_LOADING_FOR_REBUILD = &VDO_CODE_LOADING_FOR_REBUILD; 62static const struct admin_state_code VDO_CODE_WAITING_FOR_RECOVERY = { 63 .name = "VDO_ADMIN_STATE_WAITING_FOR_RECOVERY", 64 .operating = true, 65}; 66const struct admin_state_code *VDO_ADMIN_STATE_WAITING_FOR_RECOVERY = 67 &VDO_CODE_WAITING_FOR_RECOVERY; 68static const struct admin_state_code VDO_CODE_NEW = { 69 .name = "VDO_ADMIN_STATE_NEW", 70 .quiescent = true, 71}; 72const struct admin_state_code *VDO_ADMIN_STATE_NEW = &VDO_CODE_NEW; 73static const struct admin_state_code VDO_CODE_INITIALIZED = { 74 .name = "VDO_ADMIN_STATE_INITIALIZED", 75}; 76const struct admin_state_code *VDO_ADMIN_STATE_INITIALIZED = &VDO_CODE_INITIALIZED; 77static const struct admin_state_code VDO_CODE_RECOVERING = { 78 .name = "VDO_ADMIN_STATE_RECOVERING", 79 .draining = true, 80 .operating = true, 81}; 82const struct admin_state_code *VDO_ADMIN_STATE_RECOVERING = &VDO_CODE_RECOVERING; 83static const struct admin_state_code VDO_CODE_REBUILDING = { 84 .name = "VDO_ADMIN_STATE_REBUILDING", 85 .draining = true, 86 .operating = true, 87}; 88const struct admin_state_code *VDO_ADMIN_STATE_REBUILDING = &VDO_CODE_REBUILDING; 89static const struct admin_state_code VDO_CODE_SAVING = { 90 .name = "VDO_ADMIN_STATE_SAVING", 91 .draining = true, 92 .quiescing = true, 93 .operating = true, 94}; 95const struct admin_state_code *VDO_ADMIN_STATE_SAVING = &VDO_CODE_SAVING; 96static const struct admin_state_code VDO_CODE_SAVED = { 97 .name = "VDO_ADMIN_STATE_SAVED", 98 .quiescent = true, 99}; 100const struct admin_state_code *VDO_ADMIN_STATE_SAVED = &VDO_CODE_SAVED; 101static const struct admin_state_code VDO_CODE_SCRUBBING = { 102 .name = "VDO_ADMIN_STATE_SCRUBBING", 103 .draining = true, 104 .loading = true, 105 .operating = true, 106}; 107const struct admin_state_code *VDO_ADMIN_STATE_SCRUBBING = &VDO_CODE_SCRUBBING; 108static 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}; 113const struct admin_state_code *VDO_ADMIN_STATE_SAVE_FOR_SCRUBBING = &VDO_CODE_SAVE_FOR_SCRUBBING; 114static const struct admin_state_code VDO_CODE_STOPPING = { 115 .name = "VDO_ADMIN_STATE_STOPPING", 116 .draining = true, 117 .quiescing = true, 118 .operating = true, 119}; 120const struct admin_state_code *VDO_ADMIN_STATE_STOPPING = &VDO_CODE_STOPPING; 121static const struct admin_state_code VDO_CODE_STOPPED = { 122 .name = "VDO_ADMIN_STATE_STOPPED", 123 .quiescent = true, 124}; 125const struct admin_state_code *VDO_ADMIN_STATE_STOPPED = &VDO_CODE_STOPPED; 126static const struct admin_state_code VDO_CODE_SUSPENDING = { 127 .name = "VDO_ADMIN_STATE_SUSPENDING", 128 .draining = true, 129 .quiescing = true, 130 .operating = true, 131}; 132const struct admin_state_code *VDO_ADMIN_STATE_SUSPENDING = &VDO_CODE_SUSPENDING; 133static const struct admin_state_code VDO_CODE_SUSPENDED = { 134 .name = "VDO_ADMIN_STATE_SUSPENDED", 135 .quiescent = true, 136}; 137const struct admin_state_code *VDO_ADMIN_STATE_SUSPENDED = &VDO_CODE_SUSPENDED; 138static const struct admin_state_code VDO_CODE_SUSPENDED_OPERATION = { 139 .name = "VDO_ADMIN_STATE_SUSPENDED_OPERATION", 140 .operating = true, 141}; 142const struct admin_state_code *VDO_ADMIN_STATE_SUSPENDED_OPERATION = &VDO_CODE_SUSPENDED_OPERATION; 143static const struct admin_state_code VDO_CODE_RESUMING = { 144 .name = "VDO_ADMIN_STATE_RESUMING", 145 .operating = true, 146}; 147const 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 */ 158static 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 */ 200bool 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 */ 227static 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 */ 274static 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 */ 293static 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 */ 316static 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 */ 331bool 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 */ 361bool 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 */ 373bool 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 */ 385bool 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 */ 400bool 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 */ 414bool 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 */ 426bool 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 */ 438static 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 */ 454bool 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 */ 468bool 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 */ 480bool 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 */ 492int 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 */ 508int 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 */ 523int 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}