LOAD_PHASE_DRAIN_JOURNAL,
LOAD_PHASE_WAIT_FOR_READ_ONLY,
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_END,
PREPARE_GROW_PHYSICAL_PHASE_START,
"LOAD_PHASE_DRAIN_JOURNAL",
"LOAD_PHASE_WAIT_FOR_READ_ONLY",
"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_END",
"PREPARE_GROW_PHYSICAL_PHASE_START",
vdo_continue_completion(completion, result);
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);
return;
return result;
}
+ vdo->needs_formatting = true;
+
return VDO_SUCCESS;
}
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.
- * @completion: The super block vio.
+ * continue_parent() - Continue the parent of a save operation.
+ * @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);
}
+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.
*
* 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 =
container_of(as_vio(completion), struct vdo_super_block, vio);
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_completion *parent = vio->completion.parent;
+ struct vdo_super_block *super_block = &vdo->super_block;
- continue_vio_after_io(vio, continue_super_block_parent,
- parent->callback_thread_id);
+ 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),
+ 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.
* @parent: The completion to notify when the save is complete.
*/
}
record_vdo(vdo);
-
- 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);
+ vdo_save_super_block(vdo, parent);
}
/**