diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp index 1bf4c9c9c..333ca50fb 100644 --- a/fastboot/device/flashing.cpp +++ b/fastboot/device/flashing.cpp @@ -67,7 +67,7 @@ void WipeOverlayfsForPartition(FastbootDevice* device, const std::string& partit if ((partition + device->GetCurrentSlot()) == partition_name) { mount_metadata.emplace(); - fs_mgr_overlayfs_teardown(entry.mount_point.c_str()); + android::fs_mgr::TeardownAllOverlayForMountPoint(entry.mount_point); } } } @@ -194,7 +194,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"); } - fs_mgr_overlayfs_teardown(); + android::fs_mgr::TeardownAllOverlayForMountPoint(); sync(); return device->WriteOkay("Successfully flashed partition table"); } @@ -234,7 +234,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"); } - fs_mgr_overlayfs_teardown(); + android::fs_mgr::TeardownAllOverlayForMountPoint(); 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 a7704de69..899978f2e 100644 --- a/fs_mgr/fs_mgr_overlayfs.cpp +++ b/fs_mgr/fs_mgr_overlayfs.cpp @@ -73,6 +73,25 @@ bool fs_mgr_access(const std::string& path) { return ret; } +bool fs_mgr_in_recovery() { + // Check the existence of recovery binary instead of using the compile time + // macro, because first-stage-init is compiled with __ANDROID_RECOVERY__ + // defined, albeit not in recovery. More details: system/core/init/README.md + return fs_mgr_access("/system/bin/recovery"); +} + +bool fs_mgr_is_dsu_running() { + // Since android::gsi::CanBootIntoGsi() or android::gsi::MarkSystemAsGsi() is + // never called in recovery, the return value of android::gsi::IsGsiRunning() + // is not well-defined. In this case, just return false as being in recovery + // implies not running a DSU system. + if (fs_mgr_in_recovery()) return false; + auto saved_errno = errno; + auto ret = android::gsi::IsGsiRunning(); + errno = saved_errno; + return ret; +} + // determine if a filesystem is available bool fs_mgr_overlayfs_filesystem_available(const std::string& filesystem) { std::string filesystems; @@ -113,8 +132,11 @@ bool fs_mgr_overlayfs_is_setup() { namespace android { namespace fs_mgr { -void MapScratchPartitionIfNeeded(Fstab*, - const std::function&)>&) {} +void MapScratchPartitionIfNeeded(Fstab*, const std::function&)>&) { +} + +void TeardownAllOverlayForMountPoint(const std::string&) {} + } // namespace fs_mgr } // namespace android @@ -171,6 +193,10 @@ constexpr char kScratchImageMetadata[] = "/metadata/gsi/remount/lp_metadata"; // Note: this is meant only for recovery/first-stage init. bool ScratchIsOnData() { + // The scratch partition of DSU is managed by gsid. + if (fs_mgr_is_dsu_running()) { + return false; + } return fs_mgr_access(kScratchImageMetadata); } @@ -464,6 +490,12 @@ bool fs_mgr_overlayfs_teardown_scratch(const std::string& overlay, bool* change) // umount and delete kScratchMountPoint storage if we have logical partitions if (overlay != kScratchMountPoint) return true; + // Validation check. + if (fs_mgr_is_dsu_running()) { + LERROR << "Destroying DSU scratch is not allowed."; + return false; + } + auto save_errno = errno; if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) { fs_mgr_overlayfs_umount_scratch(); @@ -512,10 +544,13 @@ bool fs_mgr_overlayfs_teardown_scratch(const std::string& overlay, bool* change) } bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string& mount_point, - bool* change) { + bool* change, bool* should_destroy_scratch = nullptr) { const auto top = overlay + kOverlayTopDir; - if (!fs_mgr_access(top)) return fs_mgr_overlayfs_teardown_scratch(overlay, change); + if (!fs_mgr_access(top)) { + if (should_destroy_scratch) *should_destroy_scratch = true; + return true; + } auto cleanup_all = mount_point.empty(); const auto partition_name = android::base::Basename(mount_point); @@ -571,7 +606,7 @@ bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string PERROR << "rmdir " << top; } } - if (cleanup_all) ret &= fs_mgr_overlayfs_teardown_scratch(overlay, change); + if (should_destroy_scratch) *should_destroy_scratch = cleanup_all; return ret; } @@ -881,12 +916,29 @@ static std::string GetPhysicalScratchDevice() { return ""; } +// Note: The scratch partition of DSU is managed by gsid, and should be initialized during +// first-stage-mount. Just check if the DM device for DSU scratch partition is created or not. +static std::string GetDsuScratchDevice() { + auto& dm = DeviceMapper::Instance(); + std::string device; + if (dm.GetState(android::gsi::kDsuScratch) != DmDeviceState::INVALID && + dm.GetDmDevicePathByName(android::gsi::kDsuScratch, &device)) { + return device; + } + return ""; +} + // This returns the scratch device that was detected during early boot (first- // stage init). If the device was created later, for example during setup for // the adb remount command, it can return an empty string since it does not // query ImageManager. (Note that ImageManager in first-stage init will always // use device-mapper, since /data is not available to use loop devices.) static std::string GetBootScratchDevice() { + // Note: fs_mgr_is_dsu_running() always returns false in recovery or fastbootd. + if (fs_mgr_is_dsu_running()) { + return GetDsuScratchDevice(); + } + auto& dm = DeviceMapper::Instance(); // If there is a scratch partition allocated in /data or on super, we @@ -1108,6 +1160,14 @@ static bool CanUseSuperPartition(const Fstab& fstab, bool* is_virtual_ab) { bool fs_mgr_overlayfs_create_scratch(const Fstab& fstab, std::string* scratch_device, bool* partition_exists, bool* change) { + // Use the DSU scratch device managed by gsid if within a DSU system. + if (fs_mgr_is_dsu_running()) { + *scratch_device = GetDsuScratchDevice(); + *partition_exists = !scratch_device->empty(); + *change = false; + return *partition_exists; + } + // Try a physical partition first. *scratch_device = GetPhysicalScratchDevice(); if (!scratch_device->empty() && fs_mgr_rw_access(*scratch_device)) { @@ -1166,12 +1226,8 @@ bool fs_mgr_overlayfs_setup_scratch(const Fstab& fstab, bool* change) { bool fs_mgr_overlayfs_invalid() { if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return true; - // in recovery, fastbootd, or gsi mode, not allowed! - if (fs_mgr_access("/system/bin/recovery")) return true; - auto save_errno = errno; - auto ret = android::gsi::IsGsiRunning(); - errno = save_errno; - return ret; + // in recovery or fastbootd, not allowed! + return fs_mgr_in_recovery(); } } // namespace @@ -1314,6 +1370,8 @@ bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* return ret; } +// 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(); @@ -1321,6 +1379,11 @@ static bool EnsureScratchMapped(std::string* device, bool* mapped) { return true; } + if (!fs_mgr_in_recovery()) { + errno = EINVAL; + return false; + } + auto partition_name = android::base::Basename(kScratchMountPoint); // Check for scratch on /data first, before looking for a modified super @@ -1362,10 +1425,27 @@ static bool EnsureScratchMapped(std::string* device, bool* mapped) { return true; } -static void UnmapScratchDevice() { - // This should only be reachable in recovery, where scratch is not - // automatically mapped and therefore can be unmapped. - DestroyLogicalPartition(android::base::Basename(kScratchMountPoint)); +// This should only be reachable in recovery, where DSU scratch is not +// automatically mapped. +static bool MapDsuScratchDevice(std::string* device) { + std::string dsu_slot; + if (!android::gsi::IsGsiInstalled() || !android::gsi::GetActiveDsu(&dsu_slot) || + dsu_slot.empty()) { + // Nothing to do if no DSU installation present. + return false; + } + + auto images = IImageManager::Open("dsu/" + dsu_slot, 10s); + if (!images || !images->BackingImageExists(android::gsi::kDsuScratch)) { + // Nothing to do if DSU scratch device doesn't exist. + return false; + } + + images->UnmapImageDevice(android::gsi::kDsuScratch); + if (!images->MapImageDevice(android::gsi::kDsuScratch, 10s, device)) { + return false; + } + return true; } // Returns false if teardown not permitted, errno set to last error. @@ -1377,21 +1457,27 @@ bool fs_mgr_overlayfs_teardown(const char* mount_point, bool* change) { // If scratch exists, but is not mounted, lets gain access to clean // specific override entries. auto mount_scratch = false; - bool unmap = false; if ((mount_point != nullptr) && !fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) { - std::string scratch_device; - if (EnsureScratchMapped(&scratch_device, &unmap)) { + std::string scratch_device = GetBootScratchDevice(); + if (!scratch_device.empty()) { mount_scratch = fs_mgr_overlayfs_mount_scratch(scratch_device, fs_mgr_overlayfs_scratch_mount_type()); } } + bool should_destroy_scratch = false; for (const auto& overlay_mount_point : kOverlayMountPoints) { ret &= fs_mgr_overlayfs_teardown_one( - overlay_mount_point, mount_point ? fs_mgr_mount_point(mount_point) : "", change); + overlay_mount_point, mount_point ? fs_mgr_mount_point(mount_point) : "", change, + overlay_mount_point == kScratchMountPoint ? &should_destroy_scratch : nullptr); + } + // Do not attempt to destroy DSU scratch if within a DSU system, + // because DSU scratch partition is managed by gsid. + if (should_destroy_scratch && !fs_mgr_is_dsu_running()) { + ret &= fs_mgr_overlayfs_teardown_scratch(kScratchMountPoint, change); } if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) { // After obligatory teardown to make sure everything is clean, but if - // we didn't want overlayfs in the the first place, we do not want to + // we didn't want overlayfs in the first place, we do not want to // waste time on a reboot (or reboot request message). if (change) *change = false; } @@ -1405,9 +1491,6 @@ bool fs_mgr_overlayfs_teardown(const char* mount_point, bool* change) { if (mount_scratch) { fs_mgr_overlayfs_umount_scratch(); } - if (unmap) { - UnmapScratchDevice(); - } return ret; } @@ -1475,6 +1558,54 @@ void CleanupOldScratchFiles() { } } +void TeardownAllOverlayForMountPoint(const std::string& mount_point) { + if (!fs_mgr_in_recovery()) { + LERROR << __FUNCTION__ << "(): must be called within recovery."; + return; + } + + // Empty string means teardown everything. + const std::string teardown_dir = mount_point.empty() ? "" : fs_mgr_mount_point(mount_point); + constexpr bool* ignore_change = nullptr; + + // Teardown legacy overlay mount points that's not backed by a scratch device. + for (const auto& overlay_mount_point : kOverlayMountPoints) { + if (overlay_mount_point == kScratchMountPoint) { + continue; + } + 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)) { + fs_mgr_overlayfs_umount_scratch(); + if (fs_mgr_overlayfs_mount_scratch(scratch_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); + 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. + if (MapDsuScratchDevice(&scratch_device)) { + fs_mgr_overlayfs_umount_scratch(); + if (fs_mgr_overlayfs_mount_scratch(scratch_device, fs_mgr_overlayfs_scratch_mount_type())) { + fs_mgr_overlayfs_teardown_one(kScratchMountPoint, teardown_dir, ignore_change); + fs_mgr_overlayfs_umount_scratch(); + } + DestroyLogicalPartition(android::gsi::kDsuScratch); + } +} + } // namespace fs_mgr } // namespace android diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h index 34aded99e..d45e2de72 100644 --- a/fs_mgr/include/fs_mgr_overlayfs.h +++ b/fs_mgr/include/fs_mgr_overlayfs.h @@ -49,5 +49,12 @@ void MapScratchPartitionIfNeeded(Fstab* fstab, const std::function&)>& init); void CleanupOldScratchFiles(); +// Teardown overlays of all sources (cache dir, scratch device, DSU) for |mount_point|. +// Teardown all overlays if |mount_point| is empty. +// +// Note: This should be called if and only if in recovery or fastbootd to teardown +// overlays if any partition is flashed or updated. +void TeardownAllOverlayForMountPoint(const std::string& mount_point = {}); + } // namespace fs_mgr } // namespace android