Loading fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +7 −1 Original line number Diff line number Diff line Loading @@ -559,6 +559,9 @@ class SnapshotManager final : public ISnapshotManager { std::string GetSnapshotDeviceName(const std::string& snapshot_name, const SnapshotStatus& status); bool MapAllPartitions(LockedFile* lock, const std::string& super_device, uint32_t slot, const std::chrono::milliseconds& timeout_ms); // Reason for calling MapPartitionWithSnapshot. enum class SnapshotContext { // For writing or verification (during update_engine). Loading Loading @@ -632,9 +635,12 @@ class SnapshotManager final : public ISnapshotManager { const LpMetadata* exported_target_metadata, const std::string& target_suffix, const std::map<std::string, SnapshotStatus>& all_snapshot_status); // Implementation of UnmapAllSnapshots(), with the lock provided. bool UnmapAllSnapshots(LockedFile* lock); // Unmap all partitions that were mapped by CreateLogicalAndSnapshotPartitions. // This should only be called in recovery. bool UnmapAllPartitions(); bool UnmapAllPartitionsInRecovery(); // Check no snapshot overflows. Note that this returns false negatives if the snapshot // overflows, then is remapped and not written afterwards. Loading fs_mgr/libsnapshot/snapshot.cpp +50 −11 Original line number Diff line number Diff line Loading @@ -1709,8 +1709,13 @@ bool SnapshotManager::CreateLogicalAndSnapshotPartitions( auto lock = LockExclusive(); if (!lock) return false; const auto& opener = device_->GetPartitionOpener(); uint32_t slot = SlotNumberForSlotSuffix(device_->GetSlotSuffix()); return MapAllPartitions(lock.get(), super_device, slot, timeout_ms); } bool SnapshotManager::MapAllPartitions(LockedFile* lock, const std::string& super_device, uint32_t slot, const std::chrono::milliseconds& timeout_ms) { const auto& opener = device_->GetPartitionOpener(); auto metadata = android::fs_mgr::ReadMetadata(opener, super_device, slot); if (!metadata) { LOG(ERROR) << "Could not read dynamic partition metadata for device: " << super_device; Loading @@ -1731,8 +1736,7 @@ bool SnapshotManager::CreateLogicalAndSnapshotPartitions( .partition_opener = &opener, .timeout_ms = timeout_ms, }; if (!MapPartitionWithSnapshot(lock.get(), std::move(params), SnapshotContext::Mount, nullptr)) { if (!MapPartitionWithSnapshot(lock, std::move(params), SnapshotContext::Mount, nullptr)) { return false; } } Loading Loading @@ -2078,16 +2082,51 @@ bool SnapshotManager::UnmapCowDevices(LockedFile* lock, const std::string& name) return true; } bool SnapshotManager::MapAllSnapshots(const std::chrono::milliseconds&) { LOG(ERROR) << "Not yet implemented."; bool SnapshotManager::MapAllSnapshots(const std::chrono::milliseconds& timeout_ms) { auto lock = LockExclusive(); if (!lock) return false; auto state = ReadUpdateState(lock.get()); if (state == UpdateState::Unverified) { if (GetCurrentSlot() == Slot::Target) { LOG(ERROR) << "Cannot call MapAllSnapshots when booting from the target slot."; return false; } } else if (state != UpdateState::Initiated) { LOG(ERROR) << "Cannot call MapAllSnapshots from update state: " << state; return false; } if (!UnmapAllSnapshots(lock.get())) { return false; } uint32_t slot = SlotNumberForSlotSuffix(device_->GetOtherSlotSuffix()); return MapAllPartitions(lock.get(), device_->GetSuperDevice(slot), slot, timeout_ms); } bool SnapshotManager::UnmapAllSnapshots() { LOG(ERROR) << "Not yet implemented."; auto lock = LockExclusive(); if (!lock) return false; return UnmapAllSnapshots(lock.get()); } bool SnapshotManager::UnmapAllSnapshots(LockedFile* lock) { std::vector<std::string> snapshots; if (!ListSnapshots(lock, &snapshots)) { return false; } for (const auto& snapshot : snapshots) { if (!UnmapPartitionWithSnapshot(lock, snapshot)) { LOG(ERROR) << "Failed to unmap snapshot: " << snapshot; return false; } } return true; } auto SnapshotManager::OpenFile(const std::string& file, int lock_flags) -> std::unique_ptr<LockedFile> { unique_fd fd(open(file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW)); Loading Loading @@ -2868,7 +2907,7 @@ bool SnapshotManager::UnmapUpdateSnapshot(const std::string& target_partition_na return UnmapPartitionWithSnapshot(lock.get(), target_partition_name); } bool SnapshotManager::UnmapAllPartitions() { bool SnapshotManager::UnmapAllPartitionsInRecovery() { auto lock = LockExclusive(); if (!lock) return false; Loading Loading @@ -3012,7 +3051,7 @@ bool SnapshotManager::HandleImminentDataWipe(const std::function<void()>& callba } // Nothing should be depending on partitions now, so unmap them all. if (!UnmapAllPartitions()) { if (!UnmapAllPartitionsInRecovery()) { LOG(ERROR) << "Unable to unmap all partitions; fastboot may fail to flash."; } return true; Loading Loading @@ -3043,7 +3082,7 @@ bool SnapshotManager::FinishMergeInRecovery() { } // Nothing should be depending on partitions now, so unmap them all. if (!UnmapAllPartitions()) { if (!UnmapAllPartitionsInRecovery()) { LOG(ERROR) << "Unable to unmap all partitions; fastboot may fail to flash."; } return true; Loading fs_mgr/libsnapshot/snapshot_test.cpp +15 −0 Original line number Diff line number Diff line Loading @@ -1793,6 +1793,21 @@ TEST_F(SnapshotUpdateTest, DaemonTransition) { ASSERT_EQ(access("/dev/dm-user/sys_b-user-cow", F_OK), 0); } TEST_F(SnapshotUpdateTest, MapAllSnapshots) { AddOperationForPartitions(); // Execute the update. ASSERT_TRUE(sm->BeginUpdate()); ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_)); for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) { ASSERT_TRUE(WriteSnapshotAndHash(name)); } ASSERT_TRUE(sm->FinishedSnapshotWrites(false)); ASSERT_TRUE(sm->MapAllSnapshots(10s)); // Read bytes back and verify they match the cache. ASSERT_TRUE(IsPartitionUnchanged("sys_b")); } class FlashAfterUpdateTest : public SnapshotUpdateTest, public WithParamInterface<std::tuple<uint32_t, bool>> { public: Loading Loading
fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +7 −1 Original line number Diff line number Diff line Loading @@ -559,6 +559,9 @@ class SnapshotManager final : public ISnapshotManager { std::string GetSnapshotDeviceName(const std::string& snapshot_name, const SnapshotStatus& status); bool MapAllPartitions(LockedFile* lock, const std::string& super_device, uint32_t slot, const std::chrono::milliseconds& timeout_ms); // Reason for calling MapPartitionWithSnapshot. enum class SnapshotContext { // For writing or verification (during update_engine). Loading Loading @@ -632,9 +635,12 @@ class SnapshotManager final : public ISnapshotManager { const LpMetadata* exported_target_metadata, const std::string& target_suffix, const std::map<std::string, SnapshotStatus>& all_snapshot_status); // Implementation of UnmapAllSnapshots(), with the lock provided. bool UnmapAllSnapshots(LockedFile* lock); // Unmap all partitions that were mapped by CreateLogicalAndSnapshotPartitions. // This should only be called in recovery. bool UnmapAllPartitions(); bool UnmapAllPartitionsInRecovery(); // Check no snapshot overflows. Note that this returns false negatives if the snapshot // overflows, then is remapped and not written afterwards. Loading
fs_mgr/libsnapshot/snapshot.cpp +50 −11 Original line number Diff line number Diff line Loading @@ -1709,8 +1709,13 @@ bool SnapshotManager::CreateLogicalAndSnapshotPartitions( auto lock = LockExclusive(); if (!lock) return false; const auto& opener = device_->GetPartitionOpener(); uint32_t slot = SlotNumberForSlotSuffix(device_->GetSlotSuffix()); return MapAllPartitions(lock.get(), super_device, slot, timeout_ms); } bool SnapshotManager::MapAllPartitions(LockedFile* lock, const std::string& super_device, uint32_t slot, const std::chrono::milliseconds& timeout_ms) { const auto& opener = device_->GetPartitionOpener(); auto metadata = android::fs_mgr::ReadMetadata(opener, super_device, slot); if (!metadata) { LOG(ERROR) << "Could not read dynamic partition metadata for device: " << super_device; Loading @@ -1731,8 +1736,7 @@ bool SnapshotManager::CreateLogicalAndSnapshotPartitions( .partition_opener = &opener, .timeout_ms = timeout_ms, }; if (!MapPartitionWithSnapshot(lock.get(), std::move(params), SnapshotContext::Mount, nullptr)) { if (!MapPartitionWithSnapshot(lock, std::move(params), SnapshotContext::Mount, nullptr)) { return false; } } Loading Loading @@ -2078,16 +2082,51 @@ bool SnapshotManager::UnmapCowDevices(LockedFile* lock, const std::string& name) return true; } bool SnapshotManager::MapAllSnapshots(const std::chrono::milliseconds&) { LOG(ERROR) << "Not yet implemented."; bool SnapshotManager::MapAllSnapshots(const std::chrono::milliseconds& timeout_ms) { auto lock = LockExclusive(); if (!lock) return false; auto state = ReadUpdateState(lock.get()); if (state == UpdateState::Unverified) { if (GetCurrentSlot() == Slot::Target) { LOG(ERROR) << "Cannot call MapAllSnapshots when booting from the target slot."; return false; } } else if (state != UpdateState::Initiated) { LOG(ERROR) << "Cannot call MapAllSnapshots from update state: " << state; return false; } if (!UnmapAllSnapshots(lock.get())) { return false; } uint32_t slot = SlotNumberForSlotSuffix(device_->GetOtherSlotSuffix()); return MapAllPartitions(lock.get(), device_->GetSuperDevice(slot), slot, timeout_ms); } bool SnapshotManager::UnmapAllSnapshots() { LOG(ERROR) << "Not yet implemented."; auto lock = LockExclusive(); if (!lock) return false; return UnmapAllSnapshots(lock.get()); } bool SnapshotManager::UnmapAllSnapshots(LockedFile* lock) { std::vector<std::string> snapshots; if (!ListSnapshots(lock, &snapshots)) { return false; } for (const auto& snapshot : snapshots) { if (!UnmapPartitionWithSnapshot(lock, snapshot)) { LOG(ERROR) << "Failed to unmap snapshot: " << snapshot; return false; } } return true; } auto SnapshotManager::OpenFile(const std::string& file, int lock_flags) -> std::unique_ptr<LockedFile> { unique_fd fd(open(file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW)); Loading Loading @@ -2868,7 +2907,7 @@ bool SnapshotManager::UnmapUpdateSnapshot(const std::string& target_partition_na return UnmapPartitionWithSnapshot(lock.get(), target_partition_name); } bool SnapshotManager::UnmapAllPartitions() { bool SnapshotManager::UnmapAllPartitionsInRecovery() { auto lock = LockExclusive(); if (!lock) return false; Loading Loading @@ -3012,7 +3051,7 @@ bool SnapshotManager::HandleImminentDataWipe(const std::function<void()>& callba } // Nothing should be depending on partitions now, so unmap them all. if (!UnmapAllPartitions()) { if (!UnmapAllPartitionsInRecovery()) { LOG(ERROR) << "Unable to unmap all partitions; fastboot may fail to flash."; } return true; Loading Loading @@ -3043,7 +3082,7 @@ bool SnapshotManager::FinishMergeInRecovery() { } // Nothing should be depending on partitions now, so unmap them all. if (!UnmapAllPartitions()) { if (!UnmapAllPartitionsInRecovery()) { LOG(ERROR) << "Unable to unmap all partitions; fastboot may fail to flash."; } return true; Loading
fs_mgr/libsnapshot/snapshot_test.cpp +15 −0 Original line number Diff line number Diff line Loading @@ -1793,6 +1793,21 @@ TEST_F(SnapshotUpdateTest, DaemonTransition) { ASSERT_EQ(access("/dev/dm-user/sys_b-user-cow", F_OK), 0); } TEST_F(SnapshotUpdateTest, MapAllSnapshots) { AddOperationForPartitions(); // Execute the update. ASSERT_TRUE(sm->BeginUpdate()); ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_)); for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) { ASSERT_TRUE(WriteSnapshotAndHash(name)); } ASSERT_TRUE(sm->FinishedSnapshotWrites(false)); ASSERT_TRUE(sm->MapAllSnapshots(10s)); // Read bytes back and verify they match the cache. ASSERT_TRUE(IsPartitionUnchanged("sys_b")); } class FlashAfterUpdateTest : public SnapshotUpdateTest, public WithParamInterface<std::tuple<uint32_t, bool>> { public: Loading