Loading fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +14 −0 Original line number Diff line number Diff line Loading @@ -384,6 +384,15 @@ class SnapshotManager final { // Helper for HandleCancelledUpdate. Assumes booting from new slot. bool AreAllSnapshotsCancelled(LockedFile* lock); // Determine whether partition names in |snapshots| have been flashed and // store result to |out|. // Return true if values are successfully retrieved and false on error // (e.g. super partition metadata cannot be read). When it returns true, // |out| stores true for partitions that have been flashed and false for // partitions that have not been flashed. bool GetSnapshotFlashingStatus(LockedFile* lock, const std::vector<std::string>& snapshots, std::map<std::string, bool>* out); // Remove artifacts created by the update process, such as snapshots, and // set the update state to None. bool RemoveAllUpdateState(LockedFile* lock, const std::function<bool()>& prolog = {}); Loading Loading @@ -517,6 +526,11 @@ class SnapshotManager final { std::string ReadUpdateSourceSlotSuffix(); // Helper for RemoveAllSnapshots. // Check whether |name| should be deleted as a snapshot name. bool ShouldDeleteSnapshot(LockedFile* lock, const std::map<std::string, bool>& flashing_status, Slot current_slot, const std::string& name); std::string gsid_dir_; std::string metadata_dir_; std::unique_ptr<IDeviceInfo> device_; Loading fs_mgr/libsnapshot/snapshot.cpp +85 −10 Original line number Diff line number Diff line Loading @@ -1244,6 +1244,28 @@ bool SnapshotManager::AreAllSnapshotsCancelled(LockedFile* lock) { return true; } std::map<std::string, bool> flashing_status; if (!GetSnapshotFlashingStatus(lock, snapshots, &flashing_status)) { LOG(WARNING) << "Failed to determine whether partitions have been flashed. Not" << "removing update states."; return false; } bool all_snapshots_cancelled = std::all_of(flashing_status.begin(), flashing_status.end(), [](const auto& pair) { return pair.second; }); if (all_snapshots_cancelled) { LOG(WARNING) << "All partitions are re-flashed after update, removing all update states."; } return all_snapshots_cancelled; } bool SnapshotManager::GetSnapshotFlashingStatus(LockedFile* lock, const std::vector<std::string>& snapshots, std::map<std::string, bool>* out) { CHECK(lock); auto source_slot_suffix = ReadUpdateSourceSlotSuffix(); if (source_slot_suffix.empty()) { return false; Loading @@ -1269,20 +1291,17 @@ bool SnapshotManager::AreAllSnapshotsCancelled(LockedFile* lock) { return false; } bool all_snapshots_cancelled = true; for (const auto& snapshot_name : snapshots) { if (GetMetadataPartitionState(*metadata, snapshot_name) == MetadataPartitionState::Updated) { all_snapshots_cancelled = false; continue; } out->emplace(snapshot_name, false); } else { // Delete snapshots for partitions that are re-flashed after the update. LOG(WARNING) << "Detected re-flashing of partition " << snapshot_name << "."; out->emplace(snapshot_name, true); } if (all_snapshots_cancelled) { LOG(WARNING) << "All partitions are re-flashed after update, removing all update states."; } return all_snapshots_cancelled; return true; } bool SnapshotManager::RemoveAllSnapshots(LockedFile* lock) { Loading @@ -1292,10 +1311,38 @@ bool SnapshotManager::RemoveAllSnapshots(LockedFile* lock) { return false; } std::map<std::string, bool> flashing_status; if (!GetSnapshotFlashingStatus(lock, snapshots, &flashing_status)) { LOG(WARNING) << "Failed to get flashing status"; } auto current_slot = GetCurrentSlot(); bool ok = true; bool has_mapped_cow_images = false; for (const auto& name : snapshots) { if (!UnmapPartitionWithSnapshot(lock, name) || !DeleteSnapshot(lock, name)) { // If booting off source slot, it is okay to unmap and delete all the snapshots. // If boot indicator is missing, update state is None or Initiated, so // it is also okay to unmap and delete all the snapshots. // If booting off target slot, // - should not unmap because: // - In Android mode, snapshots are not mapped, but // filesystems are mounting off dm-linear targets directly. // - In recovery mode, assume nothing is mapped, so it is optional to unmap. // - If partition is flashed or unknown, it is okay to delete snapshots. // Otherwise (UPDATED flag), only delete snapshots if they are not mapped // as dm-snapshot (for example, after merge completes). bool should_unmap = current_slot != Slot::Target; bool should_delete = ShouldDeleteSnapshot(lock, flashing_status, current_slot, name); bool partition_ok = true; if (should_unmap && !UnmapPartitionWithSnapshot(lock, name)) { partition_ok = false; } if (partition_ok && should_delete && !DeleteSnapshot(lock, name)) { partition_ok = false; } if (!partition_ok) { // Remember whether or not we were able to unmap the cow image. auto cow_image_device = GetCowImageDeviceName(name); has_mapped_cow_images |= Loading @@ -1318,6 +1365,34 @@ bool SnapshotManager::RemoveAllSnapshots(LockedFile* lock) { return ok; } // See comments in RemoveAllSnapshots(). bool SnapshotManager::ShouldDeleteSnapshot(LockedFile* lock, const std::map<std::string, bool>& flashing_status, Slot current_slot, const std::string& name) { if (current_slot != Slot::Target) { return true; } auto it = flashing_status.find(name); if (it == flashing_status.end()) { LOG(WARNING) << "Can't determine flashing status for " << name; return true; } if (it->second) { // partition flashed, okay to delete obsolete snapshots return true; } // partition updated, only delete if not dm-snapshot SnapshotStatus status; if (!ReadSnapshotStatus(lock, name, &status)) { LOG(WARNING) << "Unable to read snapshot status for " << name << ", guessing snapshot device name"; auto extra_name = GetSnapshotExtraDeviceName(name); return !IsSnapshotDevice(name) && !IsSnapshotDevice(extra_name); } auto dm_name = GetSnapshotDeviceName(name, status); return !IsSnapshotDevice(dm_name); } UpdateState SnapshotManager::GetUpdateState(double* progress) { // If we've never started an update, the state file won't exist. auto state_file = GetStateFilePath(); Loading Loading
fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +14 −0 Original line number Diff line number Diff line Loading @@ -384,6 +384,15 @@ class SnapshotManager final { // Helper for HandleCancelledUpdate. Assumes booting from new slot. bool AreAllSnapshotsCancelled(LockedFile* lock); // Determine whether partition names in |snapshots| have been flashed and // store result to |out|. // Return true if values are successfully retrieved and false on error // (e.g. super partition metadata cannot be read). When it returns true, // |out| stores true for partitions that have been flashed and false for // partitions that have not been flashed. bool GetSnapshotFlashingStatus(LockedFile* lock, const std::vector<std::string>& snapshots, std::map<std::string, bool>* out); // Remove artifacts created by the update process, such as snapshots, and // set the update state to None. bool RemoveAllUpdateState(LockedFile* lock, const std::function<bool()>& prolog = {}); Loading Loading @@ -517,6 +526,11 @@ class SnapshotManager final { std::string ReadUpdateSourceSlotSuffix(); // Helper for RemoveAllSnapshots. // Check whether |name| should be deleted as a snapshot name. bool ShouldDeleteSnapshot(LockedFile* lock, const std::map<std::string, bool>& flashing_status, Slot current_slot, const std::string& name); std::string gsid_dir_; std::string metadata_dir_; std::unique_ptr<IDeviceInfo> device_; Loading
fs_mgr/libsnapshot/snapshot.cpp +85 −10 Original line number Diff line number Diff line Loading @@ -1244,6 +1244,28 @@ bool SnapshotManager::AreAllSnapshotsCancelled(LockedFile* lock) { return true; } std::map<std::string, bool> flashing_status; if (!GetSnapshotFlashingStatus(lock, snapshots, &flashing_status)) { LOG(WARNING) << "Failed to determine whether partitions have been flashed. Not" << "removing update states."; return false; } bool all_snapshots_cancelled = std::all_of(flashing_status.begin(), flashing_status.end(), [](const auto& pair) { return pair.second; }); if (all_snapshots_cancelled) { LOG(WARNING) << "All partitions are re-flashed after update, removing all update states."; } return all_snapshots_cancelled; } bool SnapshotManager::GetSnapshotFlashingStatus(LockedFile* lock, const std::vector<std::string>& snapshots, std::map<std::string, bool>* out) { CHECK(lock); auto source_slot_suffix = ReadUpdateSourceSlotSuffix(); if (source_slot_suffix.empty()) { return false; Loading @@ -1269,20 +1291,17 @@ bool SnapshotManager::AreAllSnapshotsCancelled(LockedFile* lock) { return false; } bool all_snapshots_cancelled = true; for (const auto& snapshot_name : snapshots) { if (GetMetadataPartitionState(*metadata, snapshot_name) == MetadataPartitionState::Updated) { all_snapshots_cancelled = false; continue; } out->emplace(snapshot_name, false); } else { // Delete snapshots for partitions that are re-flashed after the update. LOG(WARNING) << "Detected re-flashing of partition " << snapshot_name << "."; out->emplace(snapshot_name, true); } if (all_snapshots_cancelled) { LOG(WARNING) << "All partitions are re-flashed after update, removing all update states."; } return all_snapshots_cancelled; return true; } bool SnapshotManager::RemoveAllSnapshots(LockedFile* lock) { Loading @@ -1292,10 +1311,38 @@ bool SnapshotManager::RemoveAllSnapshots(LockedFile* lock) { return false; } std::map<std::string, bool> flashing_status; if (!GetSnapshotFlashingStatus(lock, snapshots, &flashing_status)) { LOG(WARNING) << "Failed to get flashing status"; } auto current_slot = GetCurrentSlot(); bool ok = true; bool has_mapped_cow_images = false; for (const auto& name : snapshots) { if (!UnmapPartitionWithSnapshot(lock, name) || !DeleteSnapshot(lock, name)) { // If booting off source slot, it is okay to unmap and delete all the snapshots. // If boot indicator is missing, update state is None or Initiated, so // it is also okay to unmap and delete all the snapshots. // If booting off target slot, // - should not unmap because: // - In Android mode, snapshots are not mapped, but // filesystems are mounting off dm-linear targets directly. // - In recovery mode, assume nothing is mapped, so it is optional to unmap. // - If partition is flashed or unknown, it is okay to delete snapshots. // Otherwise (UPDATED flag), only delete snapshots if they are not mapped // as dm-snapshot (for example, after merge completes). bool should_unmap = current_slot != Slot::Target; bool should_delete = ShouldDeleteSnapshot(lock, flashing_status, current_slot, name); bool partition_ok = true; if (should_unmap && !UnmapPartitionWithSnapshot(lock, name)) { partition_ok = false; } if (partition_ok && should_delete && !DeleteSnapshot(lock, name)) { partition_ok = false; } if (!partition_ok) { // Remember whether or not we were able to unmap the cow image. auto cow_image_device = GetCowImageDeviceName(name); has_mapped_cow_images |= Loading @@ -1318,6 +1365,34 @@ bool SnapshotManager::RemoveAllSnapshots(LockedFile* lock) { return ok; } // See comments in RemoveAllSnapshots(). bool SnapshotManager::ShouldDeleteSnapshot(LockedFile* lock, const std::map<std::string, bool>& flashing_status, Slot current_slot, const std::string& name) { if (current_slot != Slot::Target) { return true; } auto it = flashing_status.find(name); if (it == flashing_status.end()) { LOG(WARNING) << "Can't determine flashing status for " << name; return true; } if (it->second) { // partition flashed, okay to delete obsolete snapshots return true; } // partition updated, only delete if not dm-snapshot SnapshotStatus status; if (!ReadSnapshotStatus(lock, name, &status)) { LOG(WARNING) << "Unable to read snapshot status for " << name << ", guessing snapshot device name"; auto extra_name = GetSnapshotExtraDeviceName(name); return !IsSnapshotDevice(name) && !IsSnapshotDevice(extra_name); } auto dm_name = GetSnapshotDeviceName(name, status); return !IsSnapshotDevice(dm_name); } UpdateState SnapshotManager::GetUpdateState(double* progress) { // If we've never started an update, the state file won't exist. auto state_file = GetStateFilePath(); Loading