/* * The UDS layout on storage media is divided into a number of fixed-size regions, the sizes of * which are computed when the index is created. Every header and region begins on 4K block * boundary. Save regions are further sub-divided into regions of their own. * * Each region has a kind and an instance number. Some kinds only have one instance and therefore * use RL_SOLE_INSTANCE (-1) as the instance number. The RL_KIND_INDEX used to use instances to * represent sub-indices; now, however there is only ever one sub-index and therefore one instance. * The RL_KIND_VOLUME_INDEX uses instances to record which zone is being saved. * * Every region header has a type and version. * * +-+-+---------+--------+--------+-+ * | | | I N D E X 0 101, 0 | | * |H|C+---------+--------+--------+S| * |D|f| Volume | Save | Save |e| * |R|g| Region | Region | Region |a| * | | | 201, -1 | 202, 0 | 202, 1 |l| * +-+-+--------+---------+--------+-+ * * The header contains the encoded region layout table as well as some index configuration data. * The sub-index region and its subdivisions are maintained in the same table. * * There are two save regions to preserve the old state in case saving the new state is incomplete. * They are used in alternation. Each save region is further divided into sub-regions. * * +-+-----+------+------+-----+-----+ * |H| IPM | MI | MI | | OC | * |D| | zone | zone | ... | | * |R| 301 | 302 | 302 | | 303 | * | | -1 | 0 | 1 | | -1 | * +-+-----+------+------+-----+-----+ * * The header contains the encoded region layout table as well as index state data for that save. * Each save also has a unique nonce.
*/
/* Some region types are historical and are no longer used. */ enum region_type {
RH_TYPE_FREE = 0, /* unused */
RH_TYPE_SUPER = 1,
RH_TYPE_SAVE = 2,
RH_TYPE_CHECKPOINT = 3, /* unused */
RH_TYPE_UNSAVED = 4,
};
#define RL_SOLE_INSTANCE 65535
/* * Super block version 2 is the first released version. * * Super block version 3 is the normal version used from RHEL 8.2 onwards. * * Super block versions 4 through 6 were incremental development versions and * are not supported. * * Super block version 7 is used for volumes which have been reduced in size by one chapter in * order to make room to prepend LVM metadata to a volume originally created without lvm. This * allows the index to retain most its deduplication records.
*/ #define SUPER_VERSION_MINIMUM 3 #define SUPER_VERSION_CURRENT 3 #define SUPER_VERSION_MAXIMUM 7
result = uds_compute_volume_index_save_blocks(config, sls->block_size,
&sls->volume_index_blocks); if (result != UDS_SUCCESS) return vdo_log_error_strerror(result, "cannot compute index save size");
/* Create unique data using the current time and a pseudorandom number. */ staticvoid create_unique_nonce_data(u8 *buffer)
{
ktime_t now = current_time_ns(CLOCK_REALTIME);
u32 rand;
size_t offset = 0;
/* Generate a primary nonce from the provided data. */ static u64 generate_primary_nonce(constvoid *data, size_t len)
{ return hash_stuff(0xa1b1e0fc, data, len);
}
/* * Deterministically generate a secondary nonce from an existing nonce and some arbitrary data by * hashing the original nonce and the data to produce a new nonce.
*/ static u64 generate_secondary_nonce(u64 nonce, constvoid *data, size_t len)
{ return hash_stuff(nonce + 1, data, len);
}
if (isl->zone_count > 0) { /* * Normal save regions: header, page map, volume index zones, * open chapter, and possibly free space.
*/
region_count = 3 + isl->zone_count; if (isl->free_space.block_count > 0)
region_count++;
result = vdo_allocate_extended(struct region_table, region_count, struct layout_region, "layout region table for ISL", &table); if (result != VDO_SUCCESS) return result;
lr = &table->regions[0];
*lr++ = isl->header;
*lr++ = isl->index_page_map; for (z = 0; z < isl->zone_count; z++)
*lr++ = isl->volume_index_zones[z];
if (isl->zone_count > 0)
*lr++ = isl->open_chapter;
if (isl->free_space.block_count > 0)
*lr++ = isl->free_space;
staticint discard_index_state_data(struct index_layout *layout)
{ int result; int saved_result = UDS_SUCCESS; unsignedint i;
for (i = 0; i < layout->super.max_saves; i++) {
result = invalidate_old_save(layout, &layout->index.saves[i]); if (result != UDS_SUCCESS)
saved_result = result;
}
if (saved_result != UDS_SUCCESS) { return vdo_log_error_strerror(result, "%s: cannot destroy all index saves",
__func__);
}
result = open_layout_writer(layout, &layout->config, offset, &writer); if (result != UDS_SUCCESS) return vdo_log_error_strerror(result, "failed to open config region");
result = uds_write_config_contents(writer, config, layout->super.version); if (result != UDS_SUCCESS) {
uds_free_buffered_writer(writer); return vdo_log_error_strerror(result, "failed to write config region");
}
result = uds_flush_buffered_writer(writer); if (result != UDS_SUCCESS) {
uds_free_buffered_writer(writer); return vdo_log_error_strerror(result, "cannot flush config writer");
}
result = open_region_reader(layout, &isl->open_chapter, &readers[0]); if (result != UDS_SUCCESS) return result;
result = uds_load_open_chapter(index, readers[0]);
uds_free_buffered_reader(readers[0]); if (result != UDS_SUCCESS) return result;
for (zone = 0; zone < isl->zone_count; zone++) {
result = open_region_reader(layout, &isl->volume_index_zones[zone],
&readers[zone]); if (result != UDS_SUCCESS) { for (; zone > 0; zone--)
uds_free_buffered_reader(readers[zone - 1]);
return result;
}
}
result = uds_load_volume_index(index->volume_index, readers, isl->zone_count); for (zone = 0; zone < isl->zone_count; zone++)
uds_free_buffered_reader(readers[zone]); if (result != UDS_SUCCESS) return result;
result = open_region_reader(layout, &isl->index_page_map, &readers[0]); if (result != UDS_SUCCESS) return result;
result = uds_read_index_page_map(index->volume->index_page_map, readers[0]);
uds_free_buffered_reader(readers[0]);
result = open_region_writer(layout, &isl->open_chapter, &writers[0]); if (result != UDS_SUCCESS) {
cancel_uds_index_save(isl); return result;
}
result = uds_save_open_chapter(index, writers[0]);
uds_free_buffered_writer(writers[0]); if (result != UDS_SUCCESS) {
cancel_uds_index_save(isl); return result;
}
for (zone = 0; zone < index->zone_count; zone++) {
result = open_region_writer(layout, &isl->volume_index_zones[zone],
&writers[zone]); if (result != UDS_SUCCESS) { for (; zone > 0; zone--)
uds_free_buffered_writer(writers[zone - 1]);
cancel_uds_index_save(isl); return result;
}
}
result = uds_save_volume_index(index->volume_index, writers, index->zone_count); for (zone = 0; zone < index->zone_count; zone++)
uds_free_buffered_writer(writers[zone]); if (result != UDS_SUCCESS) {
cancel_uds_index_save(isl); return result;
}
result = open_region_writer(layout, &isl->index_page_map, &writers[0]); if (result != UDS_SUCCESS) {
cancel_uds_index_save(isl); return result;
}
result = uds_write_index_page_map(index->volume->index_page_map, writers[0]);
uds_free_buffered_writer(writers[0]); if (result != UDS_SUCCESS) {
cancel_uds_index_save(isl); return result;
}
/* Sub-indexes are no longer used but the layout retains this field. */ if (super->index_count != 1) { return vdo_log_error_strerror(UDS_CORRUPT_DATA, "invalid subindex count %u",
super->index_count);
}
next_block -= layout->super.volume_offset; if (next_block != start_block + sil->sub_index.block_count) { return vdo_log_error_strerror(UDS_CORRUPT_DATA, "sub index region does not span all saves");
}
layout->seal = table->regions[table->header.region_count - 1];
result = verify_region(&layout->seal, next_block + layout->super.volume_offset,
RL_KIND_SEAL, RL_SOLE_INSTANCE); if (result != UDS_SUCCESS) return result;
if (++next_block != (first_block + layout->total_blocks)) { return vdo_log_error_strerror(UDS_CORRUPT_DATA, "layout table does not span total blocks");
}
if (saved_size != sizeof(buffer)) { return vdo_log_error_strerror(UDS_CORRUPT_DATA, "unexpected index save data size %zu",
saved_size);
}
result = uds_read_from_buffered_reader(reader, buffer, sizeof(buffer)); if (result != UDS_SUCCESS) return vdo_log_error_strerror(result, "cannot read index save data");
if (isl->save_data.version > 1) { return vdo_log_error_strerror(UDS_UNSUPPORTED_VERSION, "unknown index save version number %u",
isl->save_data.version);
}
if ((file_version.signature != INDEX_STATE_VERSION_301.signature) ||
(file_version.version_id != INDEX_STATE_VERSION_301.version_id)) { return vdo_log_error_strerror(UDS_UNSUPPORTED_VERSION, "index state version %d,%d is unsupported",
file_version.signature,
file_version.version_id);
}
decode_u64_le(buffer, &offset, &isl->state_data.newest_chapter);
decode_u64_le(buffer, &offset, &isl->state_data.oldest_chapter);
decode_u64_le(buffer, &offset, &isl->state_data.last_save); /* Skip past some historical fields that are now unused */
offset += sizeof(u32) + sizeof(u32); return UDS_SUCCESS;
}
result = load_region_table(reader, &table); if (result != UDS_SUCCESS) { return vdo_log_error_strerror(result, "cannot read index save %u header",
instance);
}
if (table->header.region_blocks != isl->index_save.block_count) {
u64 region_blocks = table->header.region_blocks;
vdo_free(table); return vdo_log_error_strerror(UDS_CORRUPT_DATA, "unexpected index save %u region block count %llu",
instance,
(unsignedlonglong) region_blocks);
}
if (table->header.type != RH_TYPE_SAVE) {
vdo_log_error_strerror(UDS_CORRUPT_DATA, "unexpected index save %u header type %u",
instance, table->header.type);
vdo_free(table); return UDS_CORRUPT_DATA;
}
result = read_index_save_data(reader, isl, table->header.payload); if (result != UDS_SUCCESS) {
vdo_free(table); return vdo_log_error_strerror(result, "unknown index save %u data format",
instance);
}
result = reconstruct_index_save(isl, table);
vdo_free(table); if (result != UDS_SUCCESS) { return vdo_log_error_strerror(result, "cannot reconstruct index save %u",
instance);
}
for (j = 0; j < layout->super.max_saves; j++) {
isl = &layout->index.saves[j];
result = open_region_reader(layout, &isl->index_save, &reader);
if (result != UDS_SUCCESS) {
vdo_log_error_strerror(result, "cannot get reader for index 0 save %u",
j); return result;
}
result = load_index_save(isl, reader, j);
uds_free_buffered_reader(reader); if (result != UDS_SUCCESS) { /* Another save slot might be valid. */
reset_index_save_layout(isl, 0); continue;
}
}
int uds_make_index_layout(struct uds_configuration *config, bool new_layout, struct index_layout **layout_ptr)
{ int result; struct index_layout *layout = NULL; struct save_layout_sizes sizes;
result = compute_sizes(config, &sizes); if (result != UDS_SUCCESS) return result;
result = vdo_allocate(1, struct index_layout, __func__, &layout); if (result != VDO_SUCCESS) return result;
result = create_layout_factory(layout, config); if (result != UDS_SUCCESS) {
uds_free_index_layout(layout); return result;
}
if (layout->factory_size < sizes.total_size) {
vdo_log_error("index storage (%zu) is smaller than the required size %llu",
layout->factory_size,
(unsignedlonglong) sizes.total_size);
uds_free_index_layout(layout); return -ENOSPC;
}
if (new_layout)
result = create_index_layout(layout, config); else
result = load_index_layout(layout, config); if (result != UDS_SUCCESS) {
uds_free_index_layout(layout); return result;
}
*layout_ptr = layout; return UDS_SUCCESS;
}
void uds_free_index_layout(struct index_layout *layout)
{ if (layout == NULL) return;
vdo_free(layout->index.saves); if (layout->factory != NULL)
uds_put_io_factory(layout->factory);
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.