/** * struct action - An action to be performed in each of a set of zones. * @in_use: Whether this structure is in use. * @operation: The admin operation associated with this action. * @preamble: The method to run on the initiator thread before the action is applied to each zone. * @zone_action: The action to be performed in each zone. * @conclusion: The method to run on the initiator thread after the action is applied to each zone. * @parent: The object to notify when the action is complete. * @context: The action specific context. * @next: The action to perform after this one.
*/ struct action { bool in_use; conststruct admin_state_code *operation;
vdo_action_preamble_fn preamble;
vdo_zone_action_fn zone_action;
vdo_action_conclusion_fn conclusion; struct vdo_completion *parent; void *context; struct action *next;
};
/** * struct action_manager - Definition of an action manager. * @completion: The completion for performing actions. * @state: The state of this action manager. * @actions: The two action slots. * @current_action: The current action slot. * @zones: The number of zones in which an action is to be applied. * @Scheduler: A function to schedule a default next action. * @get_zone_thread_id: A function to get the id of the thread on which to apply an action to a * zone. * @initiator_thread_id: The ID of the thread on which actions may be initiated. * @context: Opaque data associated with this action manager. * @acting_zone: The zone currently being acted upon.
*/ struct action_manager { struct vdo_completion completion; struct admin_state state; struct action actions[2]; struct action *current_action;
zone_count_t zones;
vdo_action_scheduler_fn scheduler;
vdo_zone_thread_getter_fn get_zone_thread_id;
thread_id_t initiator_thread_id; void *context;
zone_count_t acting_zone;
};
/** * vdo_make_action_manager() - Make an action manager. * @zones: The number of zones to which actions will be applied. * @get_zone_thread_id: A function to get the thread id associated with a zone. * @initiator_thread_id: The thread on which actions may initiated. * @context: The object which holds the per-zone context for the action. * @scheduler: A function to schedule a next action after an action concludes if there is no * pending action (may be NULL). * @vdo: The vdo used to initialize completions. * @manager_ptr: A pointer to hold the new action manager. * * Return: VDO_SUCCESS or an error code.
*/ int vdo_make_action_manager(zone_count_t zones,
vdo_zone_thread_getter_fn get_zone_thread_id,
thread_id_t initiator_thread_id, void *context,
vdo_action_scheduler_fn scheduler, struct vdo *vdo, struct action_manager **manager_ptr)
{ struct action_manager *manager; int result = vdo_allocate(1, struct action_manager, __func__, &manager);
VDO_ASSERT_LOG_ONLY((vdo_get_callback_thread_id() == get_acting_zone_thread_id(manager)), "%s() called on acting zones's thread", __func__);
zone = manager->acting_zone++; if (manager->acting_zone == manager->zones) { /* * We are about to apply to the last zone. Once that is finished, we're done, so go * back to the initiator thread and finish up.
*/
prepare_for_conclusion(manager);
} else { /* Prepare to come back on the next zone */
prepare_for_next_zone(manager);
}
staticvoid handle_preamble_error(struct vdo_completion *completion)
{ /* Skip the zone actions since the preamble failed. */
completion->callback = finish_action_callback;
preserve_error(completion);
}
staticvoid launch_current_action(struct action_manager *manager)
{ struct action *action = manager->current_action; int result = vdo_start_operation(&manager->state, action->operation);
if (result != VDO_SUCCESS) { if (action->parent != NULL)
vdo_set_completion_result(action->parent, result);
/* We aren't going to run the preamble, so don't run the conclusion */
action->conclusion = no_conclusion;
finish_action_callback(&manager->completion); return;
}
/** * vdo_schedule_default_action() - Attempt to schedule the default action. * @manager: The action manager. * * If the manager is not operating normally, the action will not be scheduled. * * Return: true if an action was scheduled.
*/ bool vdo_schedule_default_action(struct action_manager *manager)
{ /* Don't schedule a default action if we are operating or not in normal operation. */ conststruct admin_state_code *code = vdo_get_current_manager_operation(manager);
/* * We need to check this now to avoid use-after-free issues if running the conclusion or * notifying the parent results in the manager being freed.
*/
has_next_action =
(manager->current_action->in_use || vdo_schedule_default_action(manager));
result = action.conclusion(manager->context);
vdo_finish_operation(&manager->state, VDO_SUCCESS); if (action.parent != NULL)
vdo_continue_completion(action.parent, result);
if (has_next_action)
launch_current_action(manager);
}
/** * vdo_schedule_action() - Schedule an action to be applied to all zones. * @manager: The action manager to schedule the action on. * @preamble: A method to be invoked on the initiator thread once this action is started but before * applying to each zone; may be NULL. * @action: The action to apply to each zone; may be NULL. * @conclusion: A method to be invoked back on the initiator thread once the action has been * applied to all zones; may be NULL. * @parent: The object to notify once the action is complete or if the action can not be scheduled; * may be NULL. * * The action will be launched immediately if there is no current action, or as soon as the current * action completes. If there is already a pending action, this action will not be scheduled, and, * if it has a parent, that parent will be notified. At least one of the preamble, action, or * conclusion must not be NULL. * * Return: true if the action was scheduled.
*/ bool vdo_schedule_action(struct action_manager *manager, vdo_action_preamble_fn preamble,
vdo_zone_action_fn action, vdo_action_conclusion_fn conclusion, struct vdo_completion *parent)
{ return vdo_schedule_operation(manager, VDO_ADMIN_STATE_OPERATING, preamble,
action, conclusion, parent);
}
/** * vdo_schedule_operation() - Schedule an operation to be applied to all zones. * @manager: The action manager to schedule the action on. * @operation: The operation this action will perform * @preamble: A method to be invoked on the initiator thread once this action is started but before * applying to each zone; may be NULL. * @action: The action to apply to each zone; may be NULL. * @conclusion: A method to be invoked back on the initiator thread once the action has been * applied to all zones; may be NULL. * @parent: The object to notify once the action is complete or if the action can not be scheduled; * may be NULL. * * The operation's action will be launched immediately if there is no current action, or as soon as * the current action completes. If there is already a pending action, this operation will not be * scheduled, and, if it has a parent, that parent will be notified. At least one of the preamble, * action, or conclusion must not be NULL. * * Return: true if the action was scheduled.
*/ bool vdo_schedule_operation(struct action_manager *manager, conststruct admin_state_code *operation,
vdo_action_preamble_fn preamble, vdo_zone_action_fn action,
vdo_action_conclusion_fn conclusion, struct vdo_completion *parent)
{ return vdo_schedule_operation_with_context(manager, operation, preamble, action,
conclusion, NULL, parent);
}
/** * vdo_schedule_operation_with_context() - Schedule an operation on all zones. * @manager: The action manager to schedule the action on. * @operation: The operation this action will perform. * @preamble: A method to be invoked on the initiator thread once this action is started but before * applying to each zone; may be NULL. * @action: The action to apply to each zone; may be NULL. * @conclusion: A method to be invoked back on the initiator thread once the action has been * applied to all zones; may be NULL. * @context: An action-specific context which may be retrieved via * vdo_get_current_action_context(); may be NULL. * @parent: The object to notify once the action is complete or if the action can not be scheduled; * may be NULL. * * The operation's action will be launched immediately if there is no current action, or as soon as * the current action completes. If there is already a pending action, this operation will not be * scheduled, and, if it has a parent, that parent will be notified. At least one of the preamble, * action, or conclusion must not be NULL. * * Return: true if the action was scheduled
*/ bool vdo_schedule_operation_with_context(struct action_manager *manager, conststruct admin_state_code *operation,
vdo_action_preamble_fn preamble,
vdo_zone_action_fn action,
vdo_action_conclusion_fn conclusion, void *context, struct vdo_completion *parent)
{ struct action *current_action;
VDO_ASSERT_LOG_ONLY((vdo_get_callback_thread_id() == manager->initiator_thread_id), "action initiated from correct thread"); if (!manager->current_action->in_use) {
current_action = manager->current_action;
} elseif (!manager->current_action->next->in_use) {
current_action = manager->current_action->next;
} else { if (parent != NULL)
vdo_continue_completion(parent, VDO_COMPONENT_BUSY);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.