Merge "PartitionCowCreator accounts for extra extents"
am: adb98df120

Change-Id: I0df9eb0def72ea3fdcb1fa8b9c034010cabf21b5
diff --git a/fs_mgr/libsnapshot/partition_cow_creator.cpp b/fs_mgr/libsnapshot/partition_cow_creator.cpp
index 77315b4..0ba2a88 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator.cpp
@@ -62,27 +62,34 @@
     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 d3d186b..699f9a1 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator.h
+++ b/fs_mgr/libsnapshot/partition_cow_creator.h
@@ -18,6 +18,7 @@
 
 #include <optional>
 #include <string>
+#include <vector>
 
 #include <liblp/builder.h>
 #include <update_engine/update_metadata.pb.h>
@@ -30,6 +31,7 @@
 // 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 @@
     std::string current_suffix;
     // List of operations to be applied on the partition.
     const RepeatedPtrField<InstallOperation>* operations = nullptr;
+    // Extra extents that are going to be invalidated during the update
+    // process.
+    std::vector<ChromeOSExtent> extra_extents = {};
 
     struct Return {
         SnapshotStatus snapshot_status;
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 0fb4af9..5573abc 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -65,6 +65,7 @@
 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 <typename T>
 using RepeatedPtrField = google::protobuf::RepeatedPtrField<T>;
@@ -1886,12 +1887,15 @@
     // 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 @@
     }
 
     std::map<std::string, const RepeatedPtrField<InstallOperation>*> install_operation_map;
+    std::map<std::string, std::vector<Extent>> 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 @@
             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()) {