Loading fs_mgr/libsnapshot/Android.bp +8 −1 Original line number Diff line number Diff line Loading @@ -49,11 +49,17 @@ cc_defaults { "libfiemap_headers", ], export_include_dirs: ["include"], proto: { type: "lite", export_proto_headers: true, canonical_path_from_root: false, }, } filegroup { name: "libsnapshot_sources", srcs: [ "android/snapshot/snapshot.proto", "snapshot.cpp", "snapshot_metadata_updater.cpp", "partition_cow_creator.cpp", Loading Loading @@ -132,9 +138,10 @@ cc_binary { "libbinder", "libext4_utils", "libfs_mgr", "libutils", "liblog", "liblp", "libprotobuf-cpp-lite", "libutils", ], init_rc: [ "snapshotctl.rc", Loading fs_mgr/libsnapshot/android/snapshot/snapshot.proto 0 → 100644 +87 −0 Original line number Diff line number Diff line // Copyright (C) 2019 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. syntax = "proto3"; package android.snapshot; option optimize_for = LITE_RUNTIME; // Next: 4 enum SnapshotState { // No snapshot is found. NONE = 0; // The snapshot has been created and possibly written to. Rollbacks are // possible by destroying the snapshot. CREATED = 1; // Changes are being merged. No rollbacks are possible beyond this point. MERGING = 2; // Changes have been merged, Future reboots may map the base device // directly. MERGE_COMPLETED = 3; } // Next: 9 message SnapshotStatus { // Name of the snapshot. This is usually the name of the snapshotted // logical partition; for example, "system_b". string name = 1; SnapshotState state = 2; // Size of the full (base) device. uint64 device_size = 3; // Size of the snapshot. This is the sum of lengths of ranges in the base // device that needs to be snapshotted during the update. // This must be less than or equal to |device_size|. // This value is 0 if no snapshot is needed for this device because // no changes uint64 snapshot_size = 4; // Size of the "COW partition". A COW partition is a special logical // partition represented in the super partition metadata. This partition and // the "COW image" form the "COW device" that supports the snapshot device. // // When SnapshotManager creates a COW device, it first searches for unused // blocks in the super partition, and use those before creating the COW // image if the COW partition is not big enough. // // This value is 0 if no space in super is left for the COW partition. // |cow_partition_size + cow_file_size| must not be zero if |snapshot_size| // is non-zero. uint64 cow_partition_size = 5; // Size of the "COW file", or "COW image". A COW file / image is created // when the "COW partition" is not big enough to store changes to the // snapshot device. // // This value is 0 if |cow_partition_size| is big enough to hold all changes // to the snapshot device. uint64 cow_file_size = 6; // Sectors allocated for the COW device. Recording this value right after // the update and before the merge allows us to infer the progress of the // merge process. // This is non-zero when |state| == MERGING or MERGE_COMPLETED. uint64 sectors_allocated = 7; // Metadata sectors allocated for the COW device. Recording this value right // before the update and before the merge allows us to infer the progress of // the merge process. // This is non-zero when |state| == MERGING or MERGE_COMPLETED. uint64 metadata_sectors = 8; } fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +4 −20 Original line number Diff line number Diff line Loading @@ -53,8 +53,9 @@ namespace snapshot { struct AutoDeleteCowImage; struct AutoDeleteSnapshot; struct PartitionCowCreator; struct AutoDeviceList; struct PartitionCowCreator; class SnapshotStatus; static constexpr const std::string_view kCowGroupName = "cow"; Loading Loading @@ -250,22 +251,6 @@ class SnapshotManager final { std::unique_ptr<LockedFile> OpenFile(const std::string& file, int open_flags, int lock_flags); bool Truncate(LockedFile* file); enum class SnapshotState : int { None, Created, Merging, MergeCompleted }; static std::string to_string(SnapshotState state); // This state is persisted per-snapshot in /metadata/ota/snapshots/. struct SnapshotStatus { SnapshotState state = SnapshotState::None; uint64_t device_size = 0; uint64_t snapshot_size = 0; uint64_t cow_partition_size = 0; uint64_t cow_file_size = 0; // These are non-zero when merging. uint64_t sectors_allocated = 0; uint64_t metadata_sectors = 0; }; // Create a new snapshot record. This creates the backing COW store and // persists information needed to map the device. The device can be mapped // with MapSnapshot(). Loading @@ -282,7 +267,7 @@ class SnapshotManager final { // // All sizes are specified in bytes, and the device, snapshot, COW partition and COW file sizes // must be a multiple of the sector size (512 bytes). bool CreateSnapshot(LockedFile* lock, const std::string& name, SnapshotStatus status); bool CreateSnapshot(LockedFile* lock, SnapshotStatus* status); // |name| should be the base partition name (e.g. "system_a"). Create the // backing COW image using the size previously passed to CreateSnapshot(). Loading Loading @@ -363,8 +348,7 @@ class SnapshotManager final { UpdateState CheckTargetMergeState(LockedFile* lock, const std::string& name); // Interact with status files under /metadata/ota/snapshots. bool WriteSnapshotStatus(LockedFile* lock, const std::string& name, const SnapshotStatus& status); bool WriteSnapshotStatus(LockedFile* lock, const SnapshotStatus& status); bool ReadSnapshotStatus(LockedFile* lock, const std::string& name, SnapshotStatus* status); std::string GetSnapshotStatusFilePath(const std::string& name); Loading fs_mgr/libsnapshot/partition_cow_creator.cpp +12 −8 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <android-base/logging.h> #include <android/snapshot/snapshot.pb.h> #include "utility.h" using android::dm::kSectorSize; Loading Loading @@ -84,13 +85,14 @@ std::optional<PartitionCowCreator::Return> PartitionCowCreator::Run() { << "logical_block_size is not power of 2"; Return ret; ret.snapshot_status.device_size = target_partition->size(); ret.snapshot_status.set_name(target_partition->name()); ret.snapshot_status.set_device_size(target_partition->size()); // TODO(b/141889746): Optimize by using a smaller snapshot. Some ranges in target_partition // may be written directly. ret.snapshot_status.snapshot_size = target_partition->size(); ret.snapshot_status.set_snapshot_size(target_partition->size()); auto cow_size = GetCowSize(ret.snapshot_status.snapshot_size); auto cow_size = GetCowSize(ret.snapshot_status.snapshot_size()); if (!cow_size.has_value()) return std::nullopt; // Compute regions that are free in both current and target metadata. These are the regions Loading @@ -106,18 +108,20 @@ std::optional<PartitionCowCreator::Return> PartitionCowCreator::Run() { LOG(INFO) << "Remaining free space for COW: " << free_region_length << " bytes"; // Compute the COW partition size. ret.snapshot_status.cow_partition_size = std::min(*cow_size, free_region_length); uint64_t cow_partition_size = std::min(*cow_size, free_region_length); // Round it down to the nearest logical block. Logical partitions must be a multiple // of logical blocks. ret.snapshot_status.cow_partition_size &= ~(logical_block_size - 1); cow_partition_size &= ~(logical_block_size - 1); ret.snapshot_status.set_cow_partition_size(cow_partition_size); // Assign cow_partition_usable_regions to indicate what regions should the COW partition uses. ret.cow_partition_usable_regions = std::move(free_regions); // The rest of the COW space is allocated on ImageManager. ret.snapshot_status.cow_file_size = (*cow_size) - ret.snapshot_status.cow_partition_size; uint64_t cow_file_size = (*cow_size) - ret.snapshot_status.cow_partition_size(); // Round it up to the nearest sector. ret.snapshot_status.cow_file_size += kSectorSize - 1; ret.snapshot_status.cow_file_size &= ~(kSectorSize - 1); cow_file_size += kSectorSize - 1; cow_file_size &= ~(kSectorSize - 1); ret.snapshot_status.set_cow_file_size(cow_file_size); return ret; } Loading fs_mgr/libsnapshot/partition_cow_creator.h +3 −2 Original line number Diff line number Diff line Loading @@ -20,8 +20,9 @@ #include <string> #include <liblp/builder.h> #include <update_engine/update_metadata.pb.h> #include <libsnapshot/snapshot.h> #include <android/snapshot/snapshot.pb.h> namespace android { namespace snapshot { Loading Loading @@ -51,7 +52,7 @@ struct PartitionCowCreator { const RepeatedPtrField<InstallOperation>* operations = nullptr; struct Return { SnapshotManager::SnapshotStatus snapshot_status; SnapshotStatus snapshot_status; std::vector<Interval> cow_partition_usable_regions; }; Loading Loading
fs_mgr/libsnapshot/Android.bp +8 −1 Original line number Diff line number Diff line Loading @@ -49,11 +49,17 @@ cc_defaults { "libfiemap_headers", ], export_include_dirs: ["include"], proto: { type: "lite", export_proto_headers: true, canonical_path_from_root: false, }, } filegroup { name: "libsnapshot_sources", srcs: [ "android/snapshot/snapshot.proto", "snapshot.cpp", "snapshot_metadata_updater.cpp", "partition_cow_creator.cpp", Loading Loading @@ -132,9 +138,10 @@ cc_binary { "libbinder", "libext4_utils", "libfs_mgr", "libutils", "liblog", "liblp", "libprotobuf-cpp-lite", "libutils", ], init_rc: [ "snapshotctl.rc", Loading
fs_mgr/libsnapshot/android/snapshot/snapshot.proto 0 → 100644 +87 −0 Original line number Diff line number Diff line // Copyright (C) 2019 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. syntax = "proto3"; package android.snapshot; option optimize_for = LITE_RUNTIME; // Next: 4 enum SnapshotState { // No snapshot is found. NONE = 0; // The snapshot has been created and possibly written to. Rollbacks are // possible by destroying the snapshot. CREATED = 1; // Changes are being merged. No rollbacks are possible beyond this point. MERGING = 2; // Changes have been merged, Future reboots may map the base device // directly. MERGE_COMPLETED = 3; } // Next: 9 message SnapshotStatus { // Name of the snapshot. This is usually the name of the snapshotted // logical partition; for example, "system_b". string name = 1; SnapshotState state = 2; // Size of the full (base) device. uint64 device_size = 3; // Size of the snapshot. This is the sum of lengths of ranges in the base // device that needs to be snapshotted during the update. // This must be less than or equal to |device_size|. // This value is 0 if no snapshot is needed for this device because // no changes uint64 snapshot_size = 4; // Size of the "COW partition". A COW partition is a special logical // partition represented in the super partition metadata. This partition and // the "COW image" form the "COW device" that supports the snapshot device. // // When SnapshotManager creates a COW device, it first searches for unused // blocks in the super partition, and use those before creating the COW // image if the COW partition is not big enough. // // This value is 0 if no space in super is left for the COW partition. // |cow_partition_size + cow_file_size| must not be zero if |snapshot_size| // is non-zero. uint64 cow_partition_size = 5; // Size of the "COW file", or "COW image". A COW file / image is created // when the "COW partition" is not big enough to store changes to the // snapshot device. // // This value is 0 if |cow_partition_size| is big enough to hold all changes // to the snapshot device. uint64 cow_file_size = 6; // Sectors allocated for the COW device. Recording this value right after // the update and before the merge allows us to infer the progress of the // merge process. // This is non-zero when |state| == MERGING or MERGE_COMPLETED. uint64 sectors_allocated = 7; // Metadata sectors allocated for the COW device. Recording this value right // before the update and before the merge allows us to infer the progress of // the merge process. // This is non-zero when |state| == MERGING or MERGE_COMPLETED. uint64 metadata_sectors = 8; }
fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +4 −20 Original line number Diff line number Diff line Loading @@ -53,8 +53,9 @@ namespace snapshot { struct AutoDeleteCowImage; struct AutoDeleteSnapshot; struct PartitionCowCreator; struct AutoDeviceList; struct PartitionCowCreator; class SnapshotStatus; static constexpr const std::string_view kCowGroupName = "cow"; Loading Loading @@ -250,22 +251,6 @@ class SnapshotManager final { std::unique_ptr<LockedFile> OpenFile(const std::string& file, int open_flags, int lock_flags); bool Truncate(LockedFile* file); enum class SnapshotState : int { None, Created, Merging, MergeCompleted }; static std::string to_string(SnapshotState state); // This state is persisted per-snapshot in /metadata/ota/snapshots/. struct SnapshotStatus { SnapshotState state = SnapshotState::None; uint64_t device_size = 0; uint64_t snapshot_size = 0; uint64_t cow_partition_size = 0; uint64_t cow_file_size = 0; // These are non-zero when merging. uint64_t sectors_allocated = 0; uint64_t metadata_sectors = 0; }; // Create a new snapshot record. This creates the backing COW store and // persists information needed to map the device. The device can be mapped // with MapSnapshot(). Loading @@ -282,7 +267,7 @@ class SnapshotManager final { // // All sizes are specified in bytes, and the device, snapshot, COW partition and COW file sizes // must be a multiple of the sector size (512 bytes). bool CreateSnapshot(LockedFile* lock, const std::string& name, SnapshotStatus status); bool CreateSnapshot(LockedFile* lock, SnapshotStatus* status); // |name| should be the base partition name (e.g. "system_a"). Create the // backing COW image using the size previously passed to CreateSnapshot(). Loading Loading @@ -363,8 +348,7 @@ class SnapshotManager final { UpdateState CheckTargetMergeState(LockedFile* lock, const std::string& name); // Interact with status files under /metadata/ota/snapshots. bool WriteSnapshotStatus(LockedFile* lock, const std::string& name, const SnapshotStatus& status); bool WriteSnapshotStatus(LockedFile* lock, const SnapshotStatus& status); bool ReadSnapshotStatus(LockedFile* lock, const std::string& name, SnapshotStatus* status); std::string GetSnapshotStatusFilePath(const std::string& name); Loading
fs_mgr/libsnapshot/partition_cow_creator.cpp +12 −8 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <android-base/logging.h> #include <android/snapshot/snapshot.pb.h> #include "utility.h" using android::dm::kSectorSize; Loading Loading @@ -84,13 +85,14 @@ std::optional<PartitionCowCreator::Return> PartitionCowCreator::Run() { << "logical_block_size is not power of 2"; Return ret; ret.snapshot_status.device_size = target_partition->size(); ret.snapshot_status.set_name(target_partition->name()); ret.snapshot_status.set_device_size(target_partition->size()); // TODO(b/141889746): Optimize by using a smaller snapshot. Some ranges in target_partition // may be written directly. ret.snapshot_status.snapshot_size = target_partition->size(); ret.snapshot_status.set_snapshot_size(target_partition->size()); auto cow_size = GetCowSize(ret.snapshot_status.snapshot_size); auto cow_size = GetCowSize(ret.snapshot_status.snapshot_size()); if (!cow_size.has_value()) return std::nullopt; // Compute regions that are free in both current and target metadata. These are the regions Loading @@ -106,18 +108,20 @@ std::optional<PartitionCowCreator::Return> PartitionCowCreator::Run() { LOG(INFO) << "Remaining free space for COW: " << free_region_length << " bytes"; // Compute the COW partition size. ret.snapshot_status.cow_partition_size = std::min(*cow_size, free_region_length); uint64_t cow_partition_size = std::min(*cow_size, free_region_length); // Round it down to the nearest logical block. Logical partitions must be a multiple // of logical blocks. ret.snapshot_status.cow_partition_size &= ~(logical_block_size - 1); cow_partition_size &= ~(logical_block_size - 1); ret.snapshot_status.set_cow_partition_size(cow_partition_size); // Assign cow_partition_usable_regions to indicate what regions should the COW partition uses. ret.cow_partition_usable_regions = std::move(free_regions); // The rest of the COW space is allocated on ImageManager. ret.snapshot_status.cow_file_size = (*cow_size) - ret.snapshot_status.cow_partition_size; uint64_t cow_file_size = (*cow_size) - ret.snapshot_status.cow_partition_size(); // Round it up to the nearest sector. ret.snapshot_status.cow_file_size += kSectorSize - 1; ret.snapshot_status.cow_file_size &= ~(kSectorSize - 1); cow_file_size += kSectorSize - 1; cow_file_size &= ~(kSectorSize - 1); ret.snapshot_status.set_cow_file_size(cow_file_size); return ret; } Loading
fs_mgr/libsnapshot/partition_cow_creator.h +3 −2 Original line number Diff line number Diff line Loading @@ -20,8 +20,9 @@ #include <string> #include <liblp/builder.h> #include <update_engine/update_metadata.pb.h> #include <libsnapshot/snapshot.h> #include <android/snapshot/snapshot.pb.h> namespace android { namespace snapshot { Loading Loading @@ -51,7 +52,7 @@ struct PartitionCowCreator { const RepeatedPtrField<InstallOperation>* operations = nullptr; struct Return { SnapshotManager::SnapshotStatus snapshot_status; SnapshotStatus snapshot_status; std::vector<Interval> cow_partition_usable_regions; }; Loading