Merge "libsnapshot: Do not map snapshots for partitions that were reflashed."

This commit is contained in:
David Anderson 2019-08-28 02:51:43 +00:00 committed by Gerrit Code Review
commit f5960a1ac7
4 changed files with 94 additions and 5 deletions

View File

@ -86,6 +86,7 @@ cc_test {
"libcutils",
"libcrypto",
"libfs_mgr",
"libgmock",
"liblp",
"libsnapshot",
],

View File

@ -158,6 +158,7 @@ class SnapshotManager final {
FRIEND_TEST(SnapshotTest, CreateSnapshot);
FRIEND_TEST(SnapshotTest, FirstStageMountAfterRollback);
FRIEND_TEST(SnapshotTest, FirstStageMountAndMerge);
FRIEND_TEST(SnapshotTest, FlashSuperDuringUpdate);
FRIEND_TEST(SnapshotTest, MapPartialSnapshot);
FRIEND_TEST(SnapshotTest, MapSnapshot);
FRIEND_TEST(SnapshotTest, Merge);

View File

@ -1041,6 +1041,12 @@ bool SnapshotManager::CreateLogicalAndSnapshotPartitions(const std::string& supe
continue;
}
if (!(partition.attributes & LP_PARTITION_ATTR_UPDATED)) {
LOG(INFO) << "Detected re-flashing of partition, will skip snapshot: "
<< partition_name;
live_snapshots.erase(partition_name);
}
CreateLogicalPartitionParams params = {
.block_device = super_device,
.metadata = metadata.get(),

View File

@ -31,6 +31,7 @@
#include <libdm/dm.h>
#include <libfiemap/image_manager.h>
#include <liblp/builder.h>
#include <liblp/mock_property_fetcher.h>
#include "test_helpers.h"
@ -43,7 +44,10 @@ using android::dm::DmDeviceState;
using android::fiemap::IImageManager;
using android::fs_mgr::BlockDeviceInfo;
using android::fs_mgr::CreateLogicalPartitionParams;
using android::fs_mgr::DestroyLogicalPartition;
using android::fs_mgr::MetadataBuilder;
using namespace ::testing;
using namespace android::fs_mgr::testing;
using namespace std::chrono_literals;
using namespace std::string_literals;
@ -67,6 +71,7 @@ class SnapshotTest : public ::testing::Test {
protected:
void SetUp() override {
ResetMockPropertyFetcher();
InitializeState();
CleanupTestArtifacts();
FormatFakeSuper();
@ -78,6 +83,7 @@ class SnapshotTest : public ::testing::Test {
lock_ = nullptr;
CleanupTestArtifacts();
ResetMockPropertyFetcher();
}
void InitializeState() {
@ -95,7 +101,8 @@ class SnapshotTest : public ::testing::Test {
// get an accurate list to remove.
lock_ = nullptr;
std::vector<std::string> snapshots = {"test-snapshot", "test_partition_b"};
std::vector<std::string> snapshots = {"test-snapshot", "test_partition_a",
"test_partition_b"};
for (const auto& snapshot : snapshots) {
DeleteSnapshotDevice(snapshot);
DeleteBackingImage(image_manager_, snapshot + "-cow");
@ -154,11 +161,10 @@ class SnapshotTest : public ::testing::Test {
return false;
}
// Update both slots for convenience.
// Update the source slot.
auto metadata = builder->Export();
if (!metadata) return false;
if (!UpdatePartitionTable(opener, "super", *metadata.get(), 0) ||
!UpdatePartitionTable(opener, "super", *metadata.get(), 1)) {
if (!UpdatePartitionTable(opener, "super", *metadata.get(), 0)) {
return false;
}
@ -174,6 +180,35 @@ class SnapshotTest : public ::testing::Test {
return CreateLogicalPartition(params, path);
}
bool MapUpdatePartitions() {
TestPartitionOpener opener(fake_super);
auto builder = MetadataBuilder::NewForUpdate(opener, "super", 0, 1);
if (!builder) return false;
auto metadata = builder->Export();
if (!metadata) return false;
// Update the destination slot, mark it as updated.
if (!UpdatePartitionTable(opener, "super", *metadata.get(), 1)) {
return false;
}
for (const auto& partition : metadata->partitions) {
CreateLogicalPartitionParams params = {
.block_device = fake_super,
.metadata = metadata.get(),
.partition = &partition,
.force_writable = true,
.timeout_ms = 10s,
};
std::string ignore_path;
if (!CreateLogicalPartition(params, &ignore_path)) {
return false;
}
}
return true;
}
void DeleteSnapshotDevice(const std::string& snapshot) {
DeleteDevice(snapshot);
DeleteDevice(snapshot + "-inner");
@ -370,17 +405,22 @@ TEST_F(SnapshotTest, MergeCannotRemoveCow) {
}
TEST_F(SnapshotTest, FirstStageMountAndMerge) {
ON_CALL(*GetMockedPropertyFetcher(), GetBoolProperty("ro.virtual_ab.enabled", _))
.WillByDefault(Return(true));
ASSERT_TRUE(AcquireLock());
static const uint64_t kDeviceSize = 1024 * 1024;
ASSERT_TRUE(CreatePartition("test_partition_b", kDeviceSize));
ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
ASSERT_TRUE(MapUpdatePartitions());
ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b", kDeviceSize, kDeviceSize,
kDeviceSize));
// Simulate a reboot into the new slot.
lock_ = nullptr;
ASSERT_TRUE(sm->FinishedSnapshotWrites());
ASSERT_TRUE(DestroyLogicalPartition("test_partition_b"));
auto rebooted = new TestDeviceInfo(fake_super);
rebooted->set_slot_suffix("_b");
@ -403,6 +443,47 @@ TEST_F(SnapshotTest, FirstStageMountAndMerge) {
ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "snapshot");
}
TEST_F(SnapshotTest, FlashSuperDuringUpdate) {
ON_CALL(*GetMockedPropertyFetcher(), GetBoolProperty("ro.virtual_ab.enabled", _))
.WillByDefault(Return(true));
ASSERT_TRUE(AcquireLock());
static const uint64_t kDeviceSize = 1024 * 1024;
ASSERT_TRUE(CreatePartition("test_partition_a", kDeviceSize));
ASSERT_TRUE(MapUpdatePartitions());
ASSERT_TRUE(sm->CreateSnapshot(lock_.get(), "test_partition_b", kDeviceSize, kDeviceSize,
kDeviceSize));
// Simulate a reboot into the new slot.
lock_ = nullptr;
ASSERT_TRUE(sm->FinishedSnapshotWrites());
ASSERT_TRUE(DestroyLogicalPartition("test_partition_b"));
// Reflash the super partition.
FormatFakeSuper();
ASSERT_TRUE(CreatePartition("test_partition_b", kDeviceSize));
auto rebooted = new TestDeviceInfo(fake_super);
rebooted->set_slot_suffix("_b");
auto init = SnapshotManager::NewForFirstStageMount(rebooted);
ASSERT_NE(init, nullptr);
ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super"));
ASSERT_TRUE(AcquireLock());
SnapshotManager::SnapshotStatus status;
ASSERT_TRUE(init->ReadSnapshotStatus(lock_.get(), "test_partition_b", &status));
// We should not get a snapshot device now.
DeviceMapper::TargetInfo target;
auto dm_name = init->GetSnapshotDeviceName("test_partition_b", status);
ASSERT_FALSE(init->IsSnapshotDevice(dm_name, &target));
}
} // namespace snapshot
} // namespace android