Commit 3f493fce authored by Matthew Sakai's avatar Matthew Sakai Committed by Mike Snitzer

dm vdo: add administrative state and action manager

This patch adds the admin_state structures which are used to track the
states of individual vdo components for handling of operations like suspend
and resume. It also adds the action manager which is used to schedule and
manage cross-thread administrative and internal operations.
Co-developed-by: default avatarJ. corwin Coburn <corwin@hurlbutnet.net>
Signed-off-by: default avatarJ. corwin Coburn <corwin@hurlbutnet.net>
Signed-off-by: default avatarMatthew Sakai <msakai@redhat.com>
Signed-off-by: default avatarMike Snitzer <snitzer@kernel.org>
parent 8ce89dde
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2023 Red Hat
*/
#ifndef VDO_ACTION_MANAGER_H
#define VDO_ACTION_MANAGER_H
#include "admin-state.h"
#include "types.h"
/*
* An action_manager provides a generic mechanism for applying actions to multi-zone entities (such
* as the block map or slab depot). Each action manager is tied to a specific context for which it
* manages actions. The manager ensures that only one action is active on that context at a time,
* and supports at most one pending action. Calls to schedule an action when there is already a
* pending action will result in VDO_COMPONENT_BUSY errors. Actions may only be submitted to the
* action manager from a single thread (which thread is determined when the action manager is
* constructed).
*
* A scheduled action consists of four components:
*
* preamble
* an optional method to be run on the initiator thread before applying the action to all zones
* zone_action
* an optional method to be applied to each of the zones
* conclusion
* an optional method to be run on the initiator thread once the per-zone method has been
* applied to all zones
* parent
* an optional completion to be finished once the conclusion is done
*
* At least one of the three methods must be provided.
*/
/*
* A function which is to be applied asynchronously to a set of zones.
* @context: The object which holds the per-zone context for the action
* @zone_number: The number of zone to which the action is being applied
* @parent: The object to notify when the action is complete
*/
typedef void (*vdo_zone_action_fn)(void *context, zone_count_t zone_number,
struct vdo_completion *parent);
/*
* A function which is to be applied asynchronously on an action manager's initiator thread as the
* preamble of an action.
* @context: The object which holds the per-zone context for the action
* @parent: The object to notify when the action is complete
*/
typedef void (*vdo_action_preamble_fn)(void *context, struct vdo_completion *parent);
/*
* A function which will run on the action manager's initiator thread as the conclusion of an
* action.
* @context: The object which holds the per-zone context for the action
*
* Return: VDO_SUCCESS or an error
*/
typedef int (*vdo_action_conclusion_fn)(void *context);
/*
* A function to schedule an action.
* @context: The object which holds the per-zone context for the action
*
* Return: true if an action was scheduled
*/
typedef bool (*vdo_action_scheduler_fn)(void *context);
/*
* A function to get the id of the thread associated with a given zone.
* @context: The action context
* @zone_number: The number of the zone for which the thread ID is desired
*/
typedef thread_id_t (*vdo_zone_thread_getter_fn)(void *context, zone_count_t zone_number);
struct action_manager;
int __must_check 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);
const struct admin_state_code *__must_check
vdo_get_current_manager_operation(struct action_manager *manager);
void * __must_check vdo_get_current_action_context(struct action_manager *manager);
bool vdo_schedule_default_action(struct action_manager *manager);
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);
bool vdo_schedule_operation(struct action_manager *manager,
const struct admin_state_code *operation,
vdo_action_preamble_fn preamble, vdo_zone_action_fn action,
vdo_action_conclusion_fn conclusion,
struct vdo_completion *parent);
bool vdo_schedule_operation_with_context(struct action_manager *manager,
const struct 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);
#endif /* VDO_ACTION_MANAGER_H */
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2023 Red Hat
*/
#ifndef VDO_ADMIN_STATE_H
#define VDO_ADMIN_STATE_H
#include "completion.h"
#include "types.h"
struct admin_state_code {
const char *name;
/* Normal operation, data_vios may be active */
bool normal;
/* I/O is draining, new requests should not start */
bool draining;
/* This is a startup time operation */
bool loading;
/* The next state will be quiescent */
bool quiescing;
/* The VDO is quiescent, there should be no I/O */
bool quiescent;
/* Whether an operation is in progress and so no other operation may be started */
bool operating;
};
extern const struct admin_state_code *VDO_ADMIN_STATE_NORMAL_OPERATION;
extern const struct admin_state_code *VDO_ADMIN_STATE_OPERATING;
extern const struct admin_state_code *VDO_ADMIN_STATE_FORMATTING;
extern const struct admin_state_code *VDO_ADMIN_STATE_PRE_LOADING;
extern const struct admin_state_code *VDO_ADMIN_STATE_PRE_LOADED;
extern const struct admin_state_code *VDO_ADMIN_STATE_LOADING;
extern const struct admin_state_code *VDO_ADMIN_STATE_LOADING_FOR_RECOVERY;
extern const struct admin_state_code *VDO_ADMIN_STATE_LOADING_FOR_REBUILD;
extern const struct admin_state_code *VDO_ADMIN_STATE_WAITING_FOR_RECOVERY;
extern const struct admin_state_code *VDO_ADMIN_STATE_NEW;
extern const struct admin_state_code *VDO_ADMIN_STATE_INITIALIZED;
extern const struct admin_state_code *VDO_ADMIN_STATE_RECOVERING;
extern const struct admin_state_code *VDO_ADMIN_STATE_REBUILDING;
extern const struct admin_state_code *VDO_ADMIN_STATE_SAVING;
extern const struct admin_state_code *VDO_ADMIN_STATE_SAVED;
extern const struct admin_state_code *VDO_ADMIN_STATE_SCRUBBING;
extern const struct admin_state_code *VDO_ADMIN_STATE_SAVE_FOR_SCRUBBING;
extern const struct admin_state_code *VDO_ADMIN_STATE_STOPPING;
extern const struct admin_state_code *VDO_ADMIN_STATE_STOPPED;
extern const struct admin_state_code *VDO_ADMIN_STATE_SUSPENDING;
extern const struct admin_state_code *VDO_ADMIN_STATE_SUSPENDED;
extern const struct admin_state_code *VDO_ADMIN_STATE_SUSPENDED_OPERATION;
extern const struct admin_state_code *VDO_ADMIN_STATE_RESUMING;
struct admin_state {
const struct admin_state_code *current_state;
/* The next administrative state (when the current operation finishes) */
const struct admin_state_code *next_state;
/* A completion waiting on a state change */
struct vdo_completion *waiter;
/* Whether an operation is being initiated */
bool starting;
/* Whether an operation has completed in the initiator */
bool complete;
};
/**
* typedef vdo_admin_initiator_fn - A method to be called once an admin operation may be initiated.
*/
typedef void (*vdo_admin_initiator_fn)(struct admin_state *state);
static inline const struct admin_state_code * __must_check
vdo_get_admin_state_code(const struct admin_state *state)
{
return READ_ONCE(state->current_state);
}
/**
* vdo_set_admin_state_code() - Set the current admin state code.
*
* This function should be used primarily for initialization and by adminState internals. Most uses
* should go through the operation interfaces.
*/
static inline void vdo_set_admin_state_code(struct admin_state *state,
const struct admin_state_code *code)
{
WRITE_ONCE(state->current_state, code);
}
static inline bool __must_check vdo_is_state_normal(const struct admin_state *state)
{
return vdo_get_admin_state_code(state)->normal;
}
static inline bool __must_check vdo_is_state_suspending(const struct admin_state *state)
{
return (vdo_get_admin_state_code(state) == VDO_ADMIN_STATE_SUSPENDING);
}
static inline bool __must_check vdo_is_state_saving(const struct admin_state *state)
{
return (vdo_get_admin_state_code(state) == VDO_ADMIN_STATE_SAVING);
}
static inline bool __must_check vdo_is_state_saved(const struct admin_state *state)
{
return (vdo_get_admin_state_code(state) == VDO_ADMIN_STATE_SAVED);
}
static inline bool __must_check vdo_is_state_draining(const struct admin_state *state)
{
return vdo_get_admin_state_code(state)->draining;
}
static inline bool __must_check vdo_is_state_loading(const struct admin_state *state)
{
return vdo_get_admin_state_code(state)->loading;
}
static inline bool __must_check vdo_is_state_resuming(const struct admin_state *state)
{
return (vdo_get_admin_state_code(state) == VDO_ADMIN_STATE_RESUMING);
}
static inline bool __must_check vdo_is_state_clean_load(const struct admin_state *state)
{
const struct admin_state_code *code = vdo_get_admin_state_code(state);
return ((code == VDO_ADMIN_STATE_FORMATTING) || (code == VDO_ADMIN_STATE_LOADING));
}
static inline bool __must_check vdo_is_state_quiescing(const struct admin_state *state)
{
return vdo_get_admin_state_code(state)->quiescing;
}
static inline bool __must_check vdo_is_state_quiescent(const struct admin_state *state)
{
return vdo_get_admin_state_code(state)->quiescent;
}
bool __must_check vdo_assert_load_operation(const struct admin_state_code *operation,
struct vdo_completion *waiter);
bool vdo_start_loading(struct admin_state *state,
const struct admin_state_code *operation,
struct vdo_completion *waiter, vdo_admin_initiator_fn initiator);
bool vdo_finish_loading(struct admin_state *state);
bool vdo_finish_loading_with_result(struct admin_state *state, int result);
bool vdo_start_resuming(struct admin_state *state,
const struct admin_state_code *operation,
struct vdo_completion *waiter, vdo_admin_initiator_fn initiator);
bool vdo_finish_resuming(struct admin_state *state);
bool vdo_finish_resuming_with_result(struct admin_state *state, int result);
int vdo_resume_if_quiescent(struct admin_state *state);
bool vdo_start_draining(struct admin_state *state,
const struct admin_state_code *operation,
struct vdo_completion *waiter, vdo_admin_initiator_fn initiator);
bool vdo_finish_draining(struct admin_state *state);
bool vdo_finish_draining_with_result(struct admin_state *state, int result);
int vdo_start_operation(struct admin_state *state,
const struct admin_state_code *operation);
int vdo_start_operation_with_waiter(struct admin_state *state,
const struct admin_state_code *operation,
struct vdo_completion *waiter,
vdo_admin_initiator_fn initiator);
bool vdo_finish_operation(struct admin_state *state, int result);
#endif /* VDO_ADMIN_STATE_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment