From 982c3410c7ac63b51567a97ccde421eae745537d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 8 Feb 2022 22:06:44 -0800 Subject: [PATCH] fastbootd: Remove all scratch partitions on update-super. This ensures that the dynamic "scratch" partition is removed when doing a flashall operation. If "scratch" is on /data, disable the partition. Add IsImageDisabled to ImageManager so EnsureScratchMapped can skip mapping it. Also, fix "scratch" not getting unmapped if on /data. Bug: 205987817 Test: adb remount adb sync adb reboot fastboot fastboot flashall --skip-reboot # no errors Test: adb-remount-test.sh Change-Id: I4b9702e1dac15fb663635506fb50a8274e1e10d1 --- fastboot/device/flashing.cpp | 9 +- fs_mgr/fs_mgr_overlayfs.cpp | 85 +++++++++++++------ fs_mgr/libfiemap/binder.cpp | 12 +++ fs_mgr/libfiemap/image_manager.cpp | 18 ++++ fs_mgr/libfiemap/image_test.cpp | 1 + .../include/libfiemap/image_manager.h | 4 + fs_mgr/libsnapshot/snapshot_fuzz_utils.h | 1 + 7 files changed, 101 insertions(+), 29 deletions(-) diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp index 44dc81f4f..22f8363b2 100644 --- a/fastboot/device/flashing.cpp +++ b/fastboot/device/flashing.cpp @@ -186,6 +186,11 @@ int Flash(FastbootDevice* device, const std::string& partition_name) { return result; } +static void RemoveScratchPartition() { + AutoMountMetadata mount_metadata; + android::fs_mgr::TeardownAllOverlayForMountPoint(); +} + bool UpdateSuper(FastbootDevice* device, const std::string& super_name, bool wipe) { std::vector data = std::move(device->download_data()); if (data.empty()) { @@ -218,7 +223,7 @@ bool UpdateSuper(FastbootDevice* device, const std::string& super_name, bool wip if (!FlashPartitionTable(super_name, *new_metadata.get())) { return device->WriteFail("Unable to flash new partition table"); } - android::fs_mgr::TeardownAllOverlayForMountPoint(); + RemoveScratchPartition(); sync(); return device->WriteOkay("Successfully flashed partition table"); } @@ -262,7 +267,7 @@ bool UpdateSuper(FastbootDevice* device, const std::string& super_name, bool wip if (!UpdateAllPartitionMetadata(device, super_name, *new_metadata.get())) { return device->WriteFail("Unable to write new partition table"); } - android::fs_mgr::TeardownAllOverlayForMountPoint(); + RemoveScratchPartition(); sync(); return device->WriteOkay("Successfully updated partition table"); } diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp index 2da5b0f43..7deb76392 100644 --- a/fs_mgr/fs_mgr_overlayfs.cpp +++ b/fs_mgr/fs_mgr_overlayfs.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -1396,18 +1397,35 @@ bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* return ret; } +struct MapInfo { + // If set, partition is owned by ImageManager. + std::unique_ptr images; + // If set, and images is null, this is a DAP partition. + std::string name; + // If set, and images and name are empty, this is a non-dynamic partition. + std::string device; + + MapInfo() = default; + MapInfo(MapInfo&&) = default; + ~MapInfo() { + if (images) { + images->UnmapImageDevice(name); + } else if (!name.empty()) { + DestroyLogicalPartition(name); + } + } +}; + // Note: This function never returns the DSU scratch device in recovery or fastbootd, // because the DSU scratch is created in the first-stage-mount, which is not run in recovery. -static bool EnsureScratchMapped(std::string* device, bool* mapped) { - *mapped = false; - *device = GetBootScratchDevice(); - if (!device->empty()) { - return true; +static std::optional EnsureScratchMapped() { + MapInfo info; + info.device = GetBootScratchDevice(); + if (!info.device.empty()) { + return {std::move(info)}; } - if (!fs_mgr_in_recovery()) { - errno = EINVAL; - return false; + return {}; } auto partition_name = android::base::Basename(kScratchMountPoint); @@ -1417,11 +1435,15 @@ static bool EnsureScratchMapped(std::string* device, bool* mapped) { // would otherwise always be mapped. auto images = IImageManager::Open("remount", 10s); if (images && images->BackingImageExists(partition_name)) { - if (!images->MapImageDevice(partition_name, 10s, device)) { - return false; + if (images->IsImageDisabled(partition_name)) { + return {}; } - *mapped = true; - return true; + if (!images->MapImageDevice(partition_name, 10s, &info.device)) { + return {}; + } + info.name = partition_name; + info.images = std::move(images); + return {std::move(info)}; } // Avoid uart spam by first checking for a scratch partition. @@ -1429,12 +1451,12 @@ static bool EnsureScratchMapped(std::string* device, bool* mapped) { auto super_device = fs_mgr_overlayfs_super_device(metadata_slot); auto metadata = ReadCurrentMetadata(super_device); if (!metadata) { - return false; + return {}; } auto partition = FindPartition(*metadata.get(), partition_name); if (!partition) { - return false; + return {}; } CreateLogicalPartitionParams params = { @@ -1444,11 +1466,11 @@ static bool EnsureScratchMapped(std::string* device, bool* mapped) { .force_writable = true, .timeout_ms = 10s, }; - if (!CreateLogicalPartition(params, device)) { - return false; + if (!CreateLogicalPartition(params, &info.device)) { + return {}; } - *mapped = true; - return true; + info.name = partition_name; + return {std::move(info)}; } // This should only be reachable in recovery, where DSU scratch is not @@ -1602,26 +1624,35 @@ void TeardownAllOverlayForMountPoint(const std::string& mount_point) { fs_mgr_overlayfs_teardown_one(overlay_mount_point, teardown_dir, ignore_change); } - // Map scratch device, mount kScratchMountPoint and teardown kScratchMountPoint. - bool mapped = false; - std::string scratch_device; - if (EnsureScratchMapped(&scratch_device, &mapped)) { + if (mount_point.empty()) { + // Throw away the entire partition. + auto partition_name = android::base::Basename(kScratchMountPoint); + auto images = IImageManager::Open("remount", 10s); + if (images && images->BackingImageExists(partition_name)) { + if (images->DisableImage(partition_name)) { + LOG(INFO) << "Disabled scratch partition for: " << kScratchMountPoint; + } else { + LOG(ERROR) << "Unable to disable scratch partition for " << kScratchMountPoint; + } + } + } + + if (auto info = EnsureScratchMapped(); info.has_value()) { + // Map scratch device, mount kScratchMountPoint and teardown kScratchMountPoint. fs_mgr_overlayfs_umount_scratch(); - if (fs_mgr_overlayfs_mount_scratch(scratch_device, fs_mgr_overlayfs_scratch_mount_type())) { + if (fs_mgr_overlayfs_mount_scratch(info->device, fs_mgr_overlayfs_scratch_mount_type())) { bool should_destroy_scratch = false; fs_mgr_overlayfs_teardown_one(kScratchMountPoint, teardown_dir, ignore_change, &should_destroy_scratch); + fs_mgr_overlayfs_umount_scratch(); if (should_destroy_scratch) { fs_mgr_overlayfs_teardown_scratch(kScratchMountPoint, nullptr); } - fs_mgr_overlayfs_umount_scratch(); - } - if (mapped) { - DestroyLogicalPartition(android::base::Basename(kScratchMountPoint)); } } // Teardown DSU overlay if present. + std::string scratch_device; if (MapDsuScratchDevice(&scratch_device)) { fs_mgr_overlayfs_umount_scratch(); if (fs_mgr_overlayfs_mount_scratch(scratch_device, fs_mgr_overlayfs_scratch_mount_type())) { diff --git a/fs_mgr/libfiemap/binder.cpp b/fs_mgr/libfiemap/binder.cpp index 31a57a800..003e6edb2 100644 --- a/fs_mgr/libfiemap/binder.cpp +++ b/fs_mgr/libfiemap/binder.cpp @@ -66,6 +66,7 @@ class ImageManagerBinder final : public IImageManager { bool RemoveDisabledImages() override; bool GetMappedImageDevice(const std::string& name, std::string* device) override; bool MapAllImages(const std::function)>& init) override; + bool IsImageDisabled(const std::string& name) override; std::vector GetAllBackingImages() override; @@ -219,6 +220,17 @@ bool ImageManagerBinder::GetMappedImageDevice(const std::string& name, std::stri return !device->empty(); } +bool ImageManagerBinder::IsImageDisabled(const std::string& name) { + bool retval; + auto status = manager_->isImageDisabled(name, &retval); + if (!status.isOk()) { + LOG(ERROR) << __PRETTY_FUNCTION__ + << " binder returned: " << status.exceptionMessage().string(); + return false; + } + return retval; +} + bool ImageManagerBinder::MapAllImages(const std::function)>&) { LOG(ERROR) << __PRETTY_FUNCTION__ << " not available over binder"; return false; diff --git a/fs_mgr/libfiemap/image_manager.cpp b/fs_mgr/libfiemap/image_manager.cpp index e3f5716c0..7ccdbf9ff 100644 --- a/fs_mgr/libfiemap/image_manager.cpp +++ b/fs_mgr/libfiemap/image_manager.cpp @@ -854,6 +854,24 @@ bool ImageManager::ValidateImageMaps() { return true; } +bool ImageManager::IsImageDisabled(const std::string& name) { + if (!MetadataExists(metadata_dir_)) { + return true; + } + + auto metadata = OpenMetadata(metadata_dir_); + if (!metadata) { + return false; + } + + auto partition = FindPartition(*metadata.get(), name); + if (!partition) { + return false; + } + + return !!(partition->attributes & LP_PARTITION_ATTR_DISABLED); +} + std::unique_ptr MappedDevice::Open(IImageManager* manager, const std::chrono::milliseconds& timeout_ms, const std::string& name) { diff --git a/fs_mgr/libfiemap/image_test.cpp b/fs_mgr/libfiemap/image_test.cpp index 6d0975150..74729494b 100644 --- a/fs_mgr/libfiemap/image_test.cpp +++ b/fs_mgr/libfiemap/image_test.cpp @@ -119,6 +119,7 @@ TEST_F(NativeTest, DisableImage) { ASSERT_TRUE(manager_->CreateBackingImage(base_name_, kTestImageSize, false, nullptr)); ASSERT_TRUE(manager_->BackingImageExists(base_name_)); ASSERT_TRUE(manager_->DisableImage(base_name_)); + ASSERT_TRUE(manager_->IsImageDisabled(base_name_)); ASSERT_TRUE(manager_->RemoveDisabledImages()); ASSERT_TRUE(!manager_->BackingImageExists(base_name_)); } diff --git a/fs_mgr/libfiemap/include/libfiemap/image_manager.h b/fs_mgr/libfiemap/include/libfiemap/image_manager.h index b23a7f79d..00dd661e9 100644 --- a/fs_mgr/libfiemap/include/libfiemap/image_manager.h +++ b/fs_mgr/libfiemap/include/libfiemap/image_manager.h @@ -131,6 +131,9 @@ class IImageManager { virtual bool RemoveAllImages() = 0; virtual bool UnmapImageIfExists(const std::string& name); + + // Returns whether DisableImage() was called. + virtual bool IsImageDisabled(const std::string& name) = 0; }; class ImageManager final : public IImageManager { @@ -162,6 +165,7 @@ class ImageManager final : public IImageManager { bool RemoveDisabledImages() override; bool GetMappedImageDevice(const std::string& name, std::string* device) override; bool MapAllImages(const std::function)>& init) override; + bool IsImageDisabled(const std::string& name) override; std::vector GetAllBackingImages(); diff --git a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h index c1a5af77d..a648384ce 100644 --- a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h +++ b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h @@ -199,6 +199,7 @@ class SnapshotFuzzImageManager : public android::fiemap::IImageManager { bool UnmapImageIfExists(const std::string& name) override { return impl_->UnmapImageIfExists(name); } + bool IsImageDisabled(const std::string& name) override { return impl_->IsImageDisabled(name); } private: std::unique_ptr impl_;