From 33836a60616d603f2ece2496e1f055bd52506d6e Mon Sep 17 00:00:00 2001 From: Alessio Balsini Date: Mon, 2 Dec 2019 11:46:52 +0000 Subject: [PATCH] PartitionCowCreator accounts for extra extents dm-verity and error correction use part of the partitions using these features to store their data. Their data may be modified during an update, so the COW device for the dm-snapshot must reserve some extra space for them. This patch extends the PartitionCowCreator data structure with the extra_extents field that will store the (optional) additional extents, e.g., the hash table extent for dm-verity or the error correction extent. Test: incremental OTA apply Test: libsnapshot_test Bug: 145180464 Change-Id: I387a6cc8438507ad41a85cc3400241ecaf627b8f Signed-off-by: Alessio Balsini --- fs_mgr/libsnapshot/partition_cow_creator.cpp | 29 ++++++++++------ fs_mgr/libsnapshot/partition_cow_creator.h | 5 +++ fs_mgr/libsnapshot/snapshot.cpp | 35 +++++++++++++++----- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/fs_mgr/libsnapshot/partition_cow_creator.cpp b/fs_mgr/libsnapshot/partition_cow_creator.cpp index 77315b4e0..0ba2a88e7 100644 --- a/fs_mgr/libsnapshot/partition_cow_creator.cpp +++ b/fs_mgr/libsnapshot/partition_cow_creator.cpp @@ -62,27 +62,34 @@ bool PartitionCowCreator::HasExtent(Partition* p, Extent* e) { return false; } +void WriteExtent(DmSnapCowSizeCalculator* sc, const chromeos_update_engine::Extent& de, + unsigned int sectors_per_block) { + const auto block_boundary = de.start_block() + de.num_blocks(); + for (auto b = de.start_block(); b < block_boundary; ++b) { + for (unsigned int s = 0; s < sectors_per_block; ++s) { + const auto sector_id = b * sectors_per_block + s; + sc->WriteSector(sector_id); + } + } +} + uint64_t PartitionCowCreator::GetCowSize() { // WARNING: The origin partition should be READ-ONLY const uint64_t logical_block_size = current_metadata->logical_block_size(); const unsigned int sectors_per_block = logical_block_size / kSectorSize; DmSnapCowSizeCalculator sc(kSectorSize, kSnapshotChunkSize); + // Allocate space for extra extents (if any). These extents are those that can be + // used for error corrections or to store verity hash trees. + for (const auto& de : extra_extents) { + WriteExtent(&sc, de, sectors_per_block); + } + if (operations == nullptr) return sc.cow_size_bytes(); for (const auto& iop : *operations) { for (const auto& de : iop.dst_extents()) { - // Skip if no blocks are written - if (de.num_blocks() == 0) continue; - - // Flag all the blocks that were written - const auto block_boundary = de.start_block() + de.num_blocks(); - for (auto b = de.start_block(); b < block_boundary; ++b) { - for (unsigned int s = 0; s < sectors_per_block; ++s) { - const auto sector_id = b * sectors_per_block + s; - sc.WriteSector(sector_id); - } - } + WriteExtent(&sc, de, sectors_per_block); } } diff --git a/fs_mgr/libsnapshot/partition_cow_creator.h b/fs_mgr/libsnapshot/partition_cow_creator.h index d3d186b2f..699f9a1a4 100644 --- a/fs_mgr/libsnapshot/partition_cow_creator.h +++ b/fs_mgr/libsnapshot/partition_cow_creator.h @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -30,6 +31,7 @@ namespace snapshot { // Helper class that creates COW for a partition. struct PartitionCowCreator { using Extent = android::fs_mgr::Extent; + using ChromeOSExtent = chromeos_update_engine::Extent; using Interval = android::fs_mgr::Interval; using MetadataBuilder = android::fs_mgr::MetadataBuilder; using Partition = android::fs_mgr::Partition; @@ -50,6 +52,9 @@ struct PartitionCowCreator { std::string current_suffix; // List of operations to be applied on the partition. const RepeatedPtrField* operations = nullptr; + // Extra extents that are going to be invalidated during the update + // process. + std::vector extra_extents = {}; struct Return { SnapshotStatus snapshot_status; diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index 0fb4af94c..5573abc97 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -65,6 +65,7 @@ using android::fs_mgr::MetadataBuilder; using android::fs_mgr::SlotNumberForSlotSuffix; using android::hardware::boot::V1_1::MergeStatus; using chromeos_update_engine::DeltaArchiveManifest; +using chromeos_update_engine::Extent; using chromeos_update_engine::InstallOperation; template using RepeatedPtrField = google::protobuf::RepeatedPtrField; @@ -1886,12 +1887,15 @@ bool SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manifest // these devices. AutoDeviceList created_devices; - PartitionCowCreator cow_creator{.target_metadata = target_metadata.get(), - .target_suffix = target_suffix, - .target_partition = nullptr, - .current_metadata = current_metadata.get(), - .current_suffix = current_suffix, - .operations = nullptr}; + PartitionCowCreator cow_creator{ + .target_metadata = target_metadata.get(), + .target_suffix = target_suffix, + .target_partition = nullptr, + .current_metadata = current_metadata.get(), + .current_suffix = current_suffix, + .operations = nullptr, + .extra_extents = {}, + }; if (!CreateUpdateSnapshotsInternal(lock.get(), manifest, &cow_creator, &created_devices, &all_snapshot_status)) { @@ -1937,15 +1941,24 @@ bool SnapshotManager::CreateUpdateSnapshotsInternal( } std::map*> install_operation_map; + std::map> extra_extents_map; for (const auto& partition_update : manifest.partitions()) { auto suffixed_name = partition_update.partition_name() + target_suffix; - auto&& [it, inserted] = install_operation_map.emplace(std::move(suffixed_name), - &partition_update.operations()); + auto&& [it, inserted] = + install_operation_map.emplace(suffixed_name, &partition_update.operations()); if (!inserted) { LOG(ERROR) << "Duplicated partition " << partition_update.partition_name() << " in update manifest."; return false; } + + auto& extra_extents = extra_extents_map[suffixed_name]; + if (partition_update.has_hash_tree_extent()) { + extra_extents.push_back(partition_update.hash_tree_extent()); + } + if (partition_update.has_fec_extent()) { + extra_extents.push_back(partition_update.fec_extent()); + } } for (auto* target_partition : ListPartitionsWithSuffix(target_metadata, target_suffix)) { @@ -1956,6 +1969,12 @@ bool SnapshotManager::CreateUpdateSnapshotsInternal( cow_creator->operations = operations_it->second; } + cow_creator->extra_extents.clear(); + auto extra_extents_it = extra_extents_map.find(target_partition->name()); + if (extra_extents_it != extra_extents_map.end()) { + cow_creator->extra_extents = std::move(extra_extents_it->second); + } + // Compute the device sizes for the partition. auto cow_creator_ret = cow_creator->Run(); if (!cow_creator_ret.has_value()) {