libsnapshot: Ensure we can remove bad snapshots when beginning an update.

If somehow we wind up with snapshots with a source suffix, we could wind
up trying to unmap an in-use partition. Detect this case and allow the
snapshot to be deleted without the unmap.

Bug: 183567503
Test: vts_libsnapshot_test
Change-Id: I87dd5bb3a7b9be59dede624924374ccc47b563c2
This commit is contained in:
David Anderson 2021-03-23 22:02:13 -07:00
parent 4f898d4e33
commit bcd19ed73e
2 changed files with 40 additions and 0 deletions

View file

@ -1619,6 +1619,18 @@ bool SnapshotManager::RemoveAllSnapshots(LockedFile* lock) {
// as dm-snapshot (for example, after merge completes).
bool should_unmap = current_slot != Slot::Target;
bool should_delete = ShouldDeleteSnapshot(flashing_status, current_slot, name);
if (should_unmap && android::base::EndsWith(name, device_->GetSlotSuffix())) {
// Something very unexpected has happened - we want to unmap this
// snapshot, but it's on the wrong slot. We can't unmap an active
// partition. If this is not really a snapshot, skip the unmap
// step.
auto& dm = DeviceMapper::Instance();
if (dm.GetState(name) == DmDeviceState::INVALID || !IsSnapshotDevice(name)) {
LOG(ERROR) << "Detected snapshot " << name << " on " << current_slot << " slot"
<< " for source partition; removing without unmap.";
should_unmap = false;
}
}
bool partition_ok = true;
if (should_unmap && !UnmapPartitionWithSnapshot(lock, name)) {

View file

@ -2021,6 +2021,34 @@ TEST_F(SnapshotUpdateTest, MapAllSnapshots) {
ASSERT_TRUE(IsPartitionUnchanged("sys_b"));
}
TEST_F(SnapshotUpdateTest, CancelOnTargetSlot) {
AddOperationForPartitions();
// Execute the update from B->A.
test_device->set_slot_suffix("_b");
ASSERT_TRUE(sm->BeginUpdate());
ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
std::string path;
ASSERT_TRUE(CreateLogicalPartition(
CreateLogicalPartitionParams{
.block_device = fake_super,
.metadata_slot = 0,
.partition_name = "sys_a",
.timeout_ms = 1s,
.partition_opener = opener_.get(),
},
&path));
// Hold sys_a open so it can't be unmapped.
unique_fd fd(open(path.c_str(), O_RDONLY));
// Switch back to "A", make sure we can cancel. Instead of unmapping sys_a
// we should simply delete the old snapshots.
test_device->set_slot_suffix("_a");
ASSERT_TRUE(sm->BeginUpdate());
}
class FlashAfterUpdateTest : public SnapshotUpdateTest,
public WithParamInterface<std::tuple<uint32_t, bool>> {
public: