mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 02:24:24 +02:00
dm vdo: save the formatted metadata to disk
Add vdo_save_super_block() and vdo_save_geometry_block() to perform asynchronous writes of the super block and geometry block respectively. Add vdo_clear_layout() to zero the UDS index's first block, the block map partition, and the recovery journal partition. These operations are driven by new phases in the pre-load state machine (PRE_LOAD_PHASE_FORMAT_*), ensuring that disk writes happen during pre-resume rather than during dmsetup create. Signed-off-by: Bruce Johnston <bjohnsto@redhat.com> Reviewed-by: Matthew Sakai <msakai@redhat.com> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
This commit is contained in:
parent
defce4e039
commit
fc1d438267
|
|
@ -61,6 +61,11 @@ enum admin_phases {
|
||||||
LOAD_PHASE_DRAIN_JOURNAL,
|
LOAD_PHASE_DRAIN_JOURNAL,
|
||||||
LOAD_PHASE_WAIT_FOR_READ_ONLY,
|
LOAD_PHASE_WAIT_FOR_READ_ONLY,
|
||||||
PRE_LOAD_PHASE_START,
|
PRE_LOAD_PHASE_START,
|
||||||
|
PRE_LOAD_PHASE_FORMAT_START,
|
||||||
|
PRE_LOAD_PHASE_FORMAT_SUPER,
|
||||||
|
PRE_LOAD_PHASE_FORMAT_GEOMETRY,
|
||||||
|
PRE_LOAD_PHASE_FORMAT_END,
|
||||||
|
PRE_LOAD_PHASE_LOAD_SUPER,
|
||||||
PRE_LOAD_PHASE_LOAD_COMPONENTS,
|
PRE_LOAD_PHASE_LOAD_COMPONENTS,
|
||||||
PRE_LOAD_PHASE_END,
|
PRE_LOAD_PHASE_END,
|
||||||
PREPARE_GROW_PHYSICAL_PHASE_START,
|
PREPARE_GROW_PHYSICAL_PHASE_START,
|
||||||
|
|
@ -110,6 +115,11 @@ static const char * const ADMIN_PHASE_NAMES[] = {
|
||||||
"LOAD_PHASE_DRAIN_JOURNAL",
|
"LOAD_PHASE_DRAIN_JOURNAL",
|
||||||
"LOAD_PHASE_WAIT_FOR_READ_ONLY",
|
"LOAD_PHASE_WAIT_FOR_READ_ONLY",
|
||||||
"PRE_LOAD_PHASE_START",
|
"PRE_LOAD_PHASE_START",
|
||||||
|
"PRE_LOAD_PHASE_FORMAT_START",
|
||||||
|
"PRE_LOAD_PHASE_FORMAT_SUPER",
|
||||||
|
"PRE_LOAD_PHASE_FORMAT_GEOMETRY",
|
||||||
|
"PRE_LOAD_PHASE_FORMAT_END",
|
||||||
|
"PRE_LOAD_PHASE_LOAD_SUPER",
|
||||||
"PRE_LOAD_PHASE_LOAD_COMPONENTS",
|
"PRE_LOAD_PHASE_LOAD_COMPONENTS",
|
||||||
"PRE_LOAD_PHASE_END",
|
"PRE_LOAD_PHASE_END",
|
||||||
"PREPARE_GROW_PHYSICAL_PHASE_START",
|
"PREPARE_GROW_PHYSICAL_PHASE_START",
|
||||||
|
|
@ -1487,7 +1497,33 @@ static void pre_load_callback(struct vdo_completion *completion)
|
||||||
vdo_continue_completion(completion, result);
|
vdo_continue_completion(completion, result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (vdo->needs_formatting)
|
||||||
|
vdo->admin.phase = PRE_LOAD_PHASE_FORMAT_START;
|
||||||
|
else
|
||||||
|
vdo->admin.phase = PRE_LOAD_PHASE_LOAD_SUPER;
|
||||||
|
|
||||||
|
vdo_continue_completion(completion, VDO_SUCCESS);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case PRE_LOAD_PHASE_FORMAT_START:
|
||||||
|
vdo_continue_completion(completion, vdo_clear_layout(vdo));
|
||||||
|
return;
|
||||||
|
|
||||||
|
case PRE_LOAD_PHASE_FORMAT_SUPER:
|
||||||
|
vdo_save_super_block(vdo, completion);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case PRE_LOAD_PHASE_FORMAT_GEOMETRY:
|
||||||
|
vdo_save_geometry_block(vdo, completion);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case PRE_LOAD_PHASE_FORMAT_END:
|
||||||
|
/* cleanup layout before load adds to it */
|
||||||
|
vdo_uninitialize_layout(&vdo->states.layout);
|
||||||
|
vdo_continue_completion(completion, VDO_SUCCESS);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case PRE_LOAD_PHASE_LOAD_SUPER:
|
||||||
vdo_load_super_block(vdo, completion);
|
vdo_load_super_block(vdo, completion);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -491,6 +491,8 @@ static int __must_check vdo_format(struct vdo *vdo, char **error_ptr)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vdo->needs_formatting = true;
|
||||||
|
|
||||||
return VDO_SUCCESS;
|
return VDO_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -951,24 +953,101 @@ static void record_vdo(struct vdo *vdo)
|
||||||
vdo->states.layout = vdo->layout;
|
vdo->states.layout = vdo->layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __must_check clear_partition(struct vdo *vdo, enum partition_id id)
|
||||||
|
{
|
||||||
|
struct partition *partition;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
result = vdo_get_partition(&vdo->states.layout, id, &partition);
|
||||||
|
if (result != VDO_SUCCESS)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
return blkdev_issue_zeroout(vdo_get_backing_device(vdo),
|
||||||
|
partition->offset * VDO_SECTORS_PER_BLOCK,
|
||||||
|
partition->count * VDO_SECTORS_PER_BLOCK,
|
||||||
|
GFP_NOWAIT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vdo_clear_layout(struct vdo *vdo)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
/* Zero out the uds index's first block. */
|
||||||
|
result = blkdev_issue_zeroout(vdo_get_backing_device(vdo),
|
||||||
|
VDO_SECTORS_PER_BLOCK,
|
||||||
|
VDO_SECTORS_PER_BLOCK,
|
||||||
|
GFP_NOWAIT, 0);
|
||||||
|
if (result != VDO_SUCCESS)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
result = clear_partition(vdo, VDO_BLOCK_MAP_PARTITION);
|
||||||
|
if (result != VDO_SUCCESS)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
return clear_partition(vdo, VDO_RECOVERY_JOURNAL_PARTITION);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* continue_super_block_parent() - Continue the parent of a super block save operation.
|
* continue_parent() - Continue the parent of a save operation.
|
||||||
* @completion: The super block vio.
|
* @completion: The completion to continue.
|
||||||
*
|
*
|
||||||
* This callback is registered in vdo_save_components().
|
|
||||||
*/
|
*/
|
||||||
static void continue_super_block_parent(struct vdo_completion *completion)
|
static void continue_parent(struct vdo_completion *completion)
|
||||||
{
|
{
|
||||||
vdo_continue_completion(vdo_forget(completion->parent), completion->result);
|
vdo_continue_completion(vdo_forget(completion->parent), completion->result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_write_endio(struct bio *bio)
|
||||||
|
{
|
||||||
|
struct vio *vio = bio->bi_private;
|
||||||
|
struct vdo_completion *parent = vio->completion.parent;
|
||||||
|
|
||||||
|
continue_vio_after_io(vio, continue_parent,
|
||||||
|
parent->callback_thread_id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* handle_save_error() - Log a super block save error.
|
* handle_geometry_block_save_error() - Log a geometry block save error.
|
||||||
|
* @completion: The super block vio.
|
||||||
|
*
|
||||||
|
* This error handler is registered in vdo_save_geometry_block().
|
||||||
|
*/
|
||||||
|
static void handle_geometry_block_save_error(struct vdo_completion *completion)
|
||||||
|
{
|
||||||
|
struct vdo_geometry_block *geometry_block =
|
||||||
|
container_of(as_vio(completion), struct vdo_geometry_block, vio);
|
||||||
|
|
||||||
|
vio_record_metadata_io_error(&geometry_block->vio);
|
||||||
|
vdo_log_error_strerror(completion->result, "geometry block save failed");
|
||||||
|
completion->callback(completion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vdo_save_geometry_block() - Encode the vdo and save the geometry block asynchronously.
|
||||||
|
* @vdo: The vdo whose state is being saved.
|
||||||
|
* @parent: The completion to notify when the save is complete.
|
||||||
|
*/
|
||||||
|
void vdo_save_geometry_block(struct vdo *vdo, struct vdo_completion *parent)
|
||||||
|
{
|
||||||
|
struct vdo_geometry_block *geometry_block = &vdo->geometry_block;
|
||||||
|
|
||||||
|
vdo_encode_volume_geometry(geometry_block->buffer, &vdo->geometry,
|
||||||
|
VDO_DEFAULT_GEOMETRY_BLOCK_VERSION);
|
||||||
|
geometry_block->vio.completion.parent = parent;
|
||||||
|
geometry_block->vio.completion.callback_thread_id = parent->callback_thread_id;
|
||||||
|
vdo_submit_metadata_vio(&geometry_block->vio,
|
||||||
|
VDO_GEOMETRY_BLOCK_LOCATION,
|
||||||
|
handle_write_endio, handle_geometry_block_save_error,
|
||||||
|
REQ_OP_WRITE | REQ_PREFLUSH | REQ_FUA);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle_super_block_save_error() - Log a super block save error.
|
||||||
* @completion: The super block vio.
|
* @completion: The super block vio.
|
||||||
*
|
*
|
||||||
* This error handler is registered in vdo_save_components().
|
* This error handler is registered in vdo_save_components().
|
||||||
*/
|
*/
|
||||||
static void handle_save_error(struct vdo_completion *completion)
|
static void handle_super_block_save_error(struct vdo_completion *completion)
|
||||||
{
|
{
|
||||||
struct vdo_super_block *super_block =
|
struct vdo_super_block *super_block =
|
||||||
container_of(as_vio(completion), struct vdo_super_block, vio);
|
container_of(as_vio(completion), struct vdo_super_block, vio);
|
||||||
|
|
@ -987,17 +1066,27 @@ static void handle_save_error(struct vdo_completion *completion)
|
||||||
completion->callback(completion);
|
completion->callback(completion);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void super_block_write_endio(struct bio *bio)
|
/**
|
||||||
|
* vdo_save_super_block() - Save the component states to the super block asynchronously.
|
||||||
|
* @vdo: The vdo whose state is being saved.
|
||||||
|
* @parent: The completion to notify when the save is complete.
|
||||||
|
*/
|
||||||
|
void vdo_save_super_block(struct vdo *vdo, struct vdo_completion *parent)
|
||||||
{
|
{
|
||||||
struct vio *vio = bio->bi_private;
|
struct vdo_super_block *super_block = &vdo->super_block;
|
||||||
struct vdo_completion *parent = vio->completion.parent;
|
|
||||||
|
|
||||||
continue_vio_after_io(vio, continue_super_block_parent,
|
vdo_encode_super_block(super_block->buffer, &vdo->states);
|
||||||
parent->callback_thread_id);
|
super_block->vio.completion.parent = parent;
|
||||||
|
super_block->vio.completion.callback_thread_id = parent->callback_thread_id;
|
||||||
|
vdo_submit_metadata_vio(&super_block->vio,
|
||||||
|
vdo_get_data_region_start(vdo->geometry),
|
||||||
|
handle_write_endio, handle_super_block_save_error,
|
||||||
|
REQ_OP_WRITE | REQ_PREFLUSH | REQ_FUA);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vdo_save_components() - Encode the vdo and save the super block asynchronously.
|
* vdo_save_components() - Copy the current state of the VDO to the states struct and save
|
||||||
|
* it to the super block asynchronously.
|
||||||
* @vdo: The vdo whose state is being saved.
|
* @vdo: The vdo whose state is being saved.
|
||||||
* @parent: The completion to notify when the save is complete.
|
* @parent: The completion to notify when the save is complete.
|
||||||
*/
|
*/
|
||||||
|
|
@ -1016,14 +1105,7 @@ void vdo_save_components(struct vdo *vdo, struct vdo_completion *parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
record_vdo(vdo);
|
record_vdo(vdo);
|
||||||
|
vdo_save_super_block(vdo, parent);
|
||||||
vdo_encode_super_block(super_block->buffer, &vdo->states);
|
|
||||||
super_block->vio.completion.parent = parent;
|
|
||||||
super_block->vio.completion.callback_thread_id = parent->callback_thread_id;
|
|
||||||
vdo_submit_metadata_vio(&super_block->vio,
|
|
||||||
vdo_get_data_region_start(vdo->geometry),
|
|
||||||
super_block_write_endio, handle_save_error,
|
|
||||||
REQ_OP_WRITE | REQ_PREFLUSH | REQ_FUA);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -246,6 +246,7 @@ struct vdo {
|
||||||
const struct admin_state_code *suspend_type;
|
const struct admin_state_code *suspend_type;
|
||||||
bool allocations_allowed;
|
bool allocations_allowed;
|
||||||
bool dump_on_shutdown;
|
bool dump_on_shutdown;
|
||||||
|
bool needs_formatting;
|
||||||
atomic_t processing_message;
|
atomic_t processing_message;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -314,6 +315,10 @@ int __must_check vdo_make(unsigned int instance, struct device_config *config,
|
||||||
|
|
||||||
void vdo_destroy(struct vdo *vdo);
|
void vdo_destroy(struct vdo *vdo);
|
||||||
|
|
||||||
|
int __must_check vdo_format_components(struct vdo *vdo);
|
||||||
|
|
||||||
|
void vdo_format_super_block(struct vdo *vdo, struct vdo_completion *parent);
|
||||||
|
|
||||||
void vdo_load_super_block(struct vdo *vdo, struct vdo_completion *parent);
|
void vdo_load_super_block(struct vdo *vdo, struct vdo_completion *parent);
|
||||||
|
|
||||||
struct block_device * __must_check vdo_get_backing_device(const struct vdo *vdo);
|
struct block_device * __must_check vdo_get_backing_device(const struct vdo *vdo);
|
||||||
|
|
@ -336,6 +341,10 @@ enum vdo_state __must_check vdo_get_state(const struct vdo *vdo);
|
||||||
|
|
||||||
void vdo_set_state(struct vdo *vdo, enum vdo_state state);
|
void vdo_set_state(struct vdo *vdo, enum vdo_state state);
|
||||||
|
|
||||||
|
int vdo_clear_layout(struct vdo *vdo);
|
||||||
|
void vdo_save_geometry_block(struct vdo *vdo, struct vdo_completion *parent);
|
||||||
|
void vdo_save_super_block(struct vdo *vdo, struct vdo_completion *parent);
|
||||||
|
|
||||||
void vdo_save_components(struct vdo *vdo, struct vdo_completion *parent);
|
void vdo_save_components(struct vdo *vdo, struct vdo_completion *parent);
|
||||||
|
|
||||||
int vdo_register_read_only_listener(struct vdo *vdo, void *listener,
|
int vdo_register_read_only_listener(struct vdo *vdo, void *listener,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user