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

Commit d572c80a authored by Nikita Ioffe's avatar Nikita Ioffe
Browse files

userdata_checkpoint_remount: delete all devices in dm-stack under /data

This enables unmounting + remounting of metadata encrypted ext4
userdata. Also added a sysprop to force unmount+remount logic even for
f2fs userdata which comes handy for testing, since we don't have
metadata encrypted ext4 devices to test on.

Test: adb shell setprop sys.init.userdata_remount.force_umount_f2fs 1
Test: adb shell /system/bin/vdc checkpoint startCheckpoint 1
Test: adb reboot userspace
Test: adb shell dumpsys activity
Bug: 135984674
Bug: 143970043
Change-Id: Icc30f5c99f4d9ee374352610ae17b5d9814f815b
parent 8759cbd5
Loading
Loading
Loading
Loading
+46 −17
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))

using android::base::Basename;
using android::base::GetBoolProperty;
using android::base::Realpath;
using android::base::StartsWith;
using android::base::unique_fd;
@@ -1357,14 +1358,33 @@ int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab) {
    return ret;
}

static std::string GetBlockDeviceForMountPoint(const std::string& mount_point) {
    Fstab mounts;
    if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
        LERROR << "Can't read /proc/mounts";
        return "";
    }
    auto entry = GetEntryForMountPoint(&mounts, mount_point);
    if (entry == nullptr) {
        LWARNING << mount_point << " is not mounted";
        return "";
    }
    return entry->blk_device;
}

// TODO(b/143970043): return different error codes based on which step failed.
int fs_mgr_remount_userdata_into_checkpointing(Fstab* fstab) {
    auto entry = GetMountedEntryForUserdata(fstab);
    if (entry == nullptr) {
    std::string block_device = GetBlockDeviceForMountPoint("/data");
    if (block_device.empty()) {
        LERROR << "/data is not mounted";
        return -1;
    }
    auto fstab_entry = GetMountedEntryForUserdata(fstab);
    if (fstab_entry == nullptr) {
        LERROR << "Can't find /data in fstab";
        return -1;
    }
    if (!entry->fs_mgr_flags.checkpoint_blk && !entry->fs_mgr_flags.checkpoint_fs) {
    if (!fstab_entry->fs_mgr_flags.checkpoint_blk && !fstab_entry->fs_mgr_flags.checkpoint_fs) {
        LINFO << "Userdata doesn't support checkpointing. Nothing to do";
        return 0;
    }
@@ -1373,34 +1393,43 @@ int fs_mgr_remount_userdata_into_checkpointing(Fstab* fstab) {
        LINFO << "Checkpointing not needed. Don't remount";
        return 0;
    }
    if (entry->fs_mgr_flags.checkpoint_fs) {
    bool force_umount_for_f2fs =
            GetBoolProperty("sys.init.userdata_remount.force_umount_f2fs", false);
    if (fstab_entry->fs_mgr_flags.checkpoint_fs && !force_umount_for_f2fs) {
        // Userdata is f2fs, simply remount it.
        if (!checkpoint_manager.Update(&(*entry))) {
        if (!checkpoint_manager.Update(fstab_entry)) {
            LERROR << "Failed to remount userdata in checkpointing mode";
            return -1;
        }
        if (mount(entry->blk_device.c_str(), entry->mount_point.c_str(), "none",
                  MS_REMOUNT | entry->flags, entry->fs_options.c_str()) != 0) {
        if (mount(block_device.c_str(), fstab_entry->mount_point.c_str(), "none",
                  MS_REMOUNT | fstab_entry->flags, fstab_entry->fs_options.c_str()) != 0) {
            PERROR << "Failed to remount userdata in checkpointing mode";
            return -1;
        }
    } else {
        // STOPSHIP(b/143970043): support remounting for ext4 + metadata encryption.
        if (should_use_metadata_encryption(*entry)) {
            LWARNING << "Remounting into checkpointing is not supported for metadata encrypted "
                     << "ext4 userdata. Proceed with caution";
            return 0;
        }
        LINFO << "Unmounting /data before remounting into checkpointing mode";
        if (umount2("/data", UMOUNT_NOFOLLOW) != 0) {
            PERROR << "Failed to umount /data";
            return -1;
        }
        DeviceMapper& dm = DeviceMapper::Instance();
        // TODO(b/143970043): need to delete every dm-device under the one userdata is mounted on.
        if (!dm.DeleteDeviceIfExists("bow")) {
            LERROR << "Failed to delete dm-bow";
        while (dm.IsDmBlockDevice(block_device)) {
            auto next_device = dm.GetParentBlockDeviceByPath(block_device);
            auto name = dm.GetDmDeviceNameByPath(block_device);
            if (!name) {
                LERROR << "Failed to get dm-name for " << block_device;
                return -1;
            }
            LINFO << "Deleting " << block_device << " named " << *name;
            if (!dm.DeleteDevice(*name, 3s)) {
                return -1;
            }
            if (!next_device) {
                LERROR << "Failed to find parent device for " << block_device;
            }
            block_device = *next_device;
        }
        LINFO << "Remounting /data";
        // TODO(b/143970043): remove this hack after fs_mgr_mount_all is refactored.
        int result = fs_mgr_mount_all(fstab, MOUNT_MODE_ONLY_USERDATA);
        return result == FS_MGR_MNTALL_FAIL ? -1 : 0;