Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 65f4f435 authored by Yo Chiang's avatar Yo Chiang Committed by Gerrit Code Review
Browse files

Merge changes from topic "dsu-overlayfs"

* changes:
  Refactor fs_mgr_overlayfs_teardown()
  Enable overlayFS on DSU system
parents 497bca09 66d0d96c
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -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");
}
+154 −23
Original line number Diff line number Diff line
@@ -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<bool(const std::set<std::string>&)>&) {}
void MapScratchPartitionIfNeeded(Fstab*, const std::function<bool(const std::set<std::string>&)>&) {
}

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

+7 −0
Original line number Diff line number Diff line
@@ -49,5 +49,12 @@ void MapScratchPartitionIfNeeded(Fstab* fstab,
                                 const std::function<bool(const std::set<std::string>&)>& 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