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

Commit e34549af authored by Jooyung Han's avatar Jooyung Han
Browse files

Clean up userspace-reboot

The feature was deprecated last year.

Bug: 292469129
Test: atest CtsInitTestCases
Change-Id: I826502770ab3fa566be57a33829f1103efa893fb
parent 6d85bb3e
Loading
Loading
Loading
Loading
+8 −192
Original line number Diff line number Diff line
@@ -1433,16 +1433,16 @@ bool WasMetadataEncryptionInterrupted(const FstabEntry& entry) {
// When multiple fstab records share the same mount_point, it will try to mount each
// one in turn, and ignore any duplicates after a first successful mount.
// Returns -1 on error, and  FS_MGR_MNTALL_* otherwise.
MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
int fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
    int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
    int error_count = 0;
    CheckpointManager checkpoint_manager;
    AvbUniquePtr avb_handle(nullptr);
    bool wiped = false;

    bool userdata_mounted = false;

    if (fstab->empty()) {
        return {FS_MGR_MNTALL_FAIL, userdata_mounted};
        return FS_MGR_MNTALL_FAIL;
    }

    bool scratch_can_be_mounted = true;
@@ -1521,7 +1521,7 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
                if (!avb_handle) {
                    LERROR << "Failed to open AvbHandle";
                    set_type_property(encryptable);
                    return {FS_MGR_MNTALL_FAIL, userdata_mounted};
                    return FS_MGR_MNTALL_FAIL;
                }
            }
            if (avb_handle->SetUpAvbHashtree(&current_entry, true /* wait_for_verity_dev */) ==
@@ -1557,7 +1557,7 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {

            if (status == FS_MGR_MNTALL_FAIL) {
                // Fatal error - no point continuing.
                return {status, userdata_mounted};
                return status;
            }

            if (status != FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
@@ -1577,7 +1577,7 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
                                  nullptr)) {
                        LERROR << "Encryption failed";
                        set_type_property(encryptable);
                        return {FS_MGR_MNTALL_FAIL, userdata_mounted};
                        return FS_MGR_MNTALL_FAIL;
                    }
                }
            }
@@ -1696,9 +1696,9 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
    set_type_property(encryptable);

    if (error_count) {
        return {FS_MGR_MNTALL_FAIL, userdata_mounted};
        return FS_MGR_MNTALL_FAIL;
    } else {
        return {encryptable, userdata_mounted};
        return encryptable;
    }
}

@@ -1735,190 +1735,6 @@ int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab) {
    return ret;
}

static std::chrono::milliseconds GetMillisProperty(const std::string& name,
                                                   std::chrono::milliseconds default_value) {
    auto value = GetUintProperty(name, static_cast<uint64_t>(default_value.count()));
    return std::chrono::milliseconds(std::move(value));
}

static bool fs_mgr_unmount_all_data_mounts(const std::string& data_block_device) {
    LINFO << __FUNCTION__ << "(): about to umount everything on top of " << data_block_device;
    Timer t;
    auto timeout = GetMillisProperty("init.userspace_reboot.userdata_remount.timeoutmillis", 5s);
    while (true) {
        bool umount_done = true;
        Fstab proc_mounts;
        if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
            LERROR << __FUNCTION__ << "(): Can't read /proc/mounts";
            return false;
        }
        // Now proceed with other bind mounts on top of /data.
        for (const auto& entry : proc_mounts) {
            std::string block_device;
            if (StartsWith(entry.blk_device, "/dev/block") &&
                !Realpath(entry.blk_device, &block_device)) {
                PWARNING << __FUNCTION__ << "(): failed to realpath " << entry.blk_device;
                block_device = entry.blk_device;
            }
            if (data_block_device == block_device) {
                if (umount2(entry.mount_point.c_str(), 0) != 0) {
                    PERROR << __FUNCTION__ << "(): Failed to umount " << entry.mount_point;
                    umount_done = false;
                }
            }
        }
        if (umount_done) {
            LINFO << __FUNCTION__ << "(): Unmounting /data took " << t;
            return true;
        }
        if (t.duration() > timeout) {
            LERROR << __FUNCTION__ << "(): Timed out unmounting all mounts on "
                   << data_block_device;
            Fstab remaining_mounts;
            if (!ReadFstabFromFile("/proc/mounts", &remaining_mounts)) {
                LERROR << __FUNCTION__ << "(): Can't read /proc/mounts";
            } else {
                LERROR << __FUNCTION__ << "(): Following mounts remaining";
                for (const auto& e : remaining_mounts) {
                    LERROR << __FUNCTION__ << "(): mount point: " << e.mount_point
                           << " block device: " << e.blk_device;
                }
            }
            return false;
        }
        std::this_thread::sleep_for(50ms);
    }
}

static bool UnwindDmDeviceStack(const std::string& block_device,
                                std::vector<std::string>* dm_stack) {
    if (!StartsWith(block_device, "/dev/block/")) {
        LWARNING << block_device << " is not a block device";
        return false;
    }
    std::string current = block_device;
    DeviceMapper& dm = DeviceMapper::Instance();
    while (true) {
        dm_stack->push_back(current);
        if (!dm.IsDmBlockDevice(current)) {
            break;
        }
        auto parent = dm.GetParentBlockDeviceByPath(current);
        if (!parent) {
            return false;
        }
        current = *parent;
    }
    return true;
}

FstabEntry* fs_mgr_get_mounted_entry_for_userdata(Fstab* fstab,
                                                  const std::string& data_block_device) {
    std::vector<std::string> dm_stack;
    if (!UnwindDmDeviceStack(data_block_device, &dm_stack)) {
        LERROR << "Failed to unwind dm-device stack for " << data_block_device;
        return nullptr;
    }
    for (auto& entry : *fstab) {
        if (entry.mount_point != "/data") {
            continue;
        }
        std::string block_device;
        if (entry.fs_mgr_flags.logical) {
            if (!fs_mgr_update_logical_partition(&entry)) {
                LERROR << "Failed to update logic partition " << entry.blk_device;
                continue;
            }
            block_device = entry.blk_device;
        } else if (!Realpath(entry.blk_device, &block_device)) {
            PWARNING << "Failed to realpath " << entry.blk_device;
            block_device = entry.blk_device;
        }
        if (std::find(dm_stack.begin(), dm_stack.end(), block_device) != dm_stack.end()) {
            return &entry;
        }
    }
    LERROR << "Didn't find entry that was used to mount /data onto " << data_block_device;
    return nullptr;
}

// TODO(b/143970043): return different error codes based on which step failed.
int fs_mgr_remount_userdata_into_checkpointing(Fstab* fstab) {
    Fstab proc_mounts;
    if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
        LERROR << "Can't read /proc/mounts";
        return -1;
    }
    auto mounted_entry = GetEntryForMountPoint(&proc_mounts, "/data");
    if (mounted_entry == nullptr) {
        LERROR << "/data is not mounted";
        return -1;
    }
    std::string block_device;
    if (!Realpath(mounted_entry->blk_device, &block_device)) {
        PERROR << "Failed to realpath " << mounted_entry->blk_device;
        return -1;
    }
    auto fstab_entry = fs_mgr_get_mounted_entry_for_userdata(fstab, block_device);
    if (fstab_entry == nullptr) {
        LERROR << "Can't find /data in fstab";
        return -1;
    }
    bool force_umount = GetBoolProperty("sys.init.userdata_remount.force_umount", false);
    if (force_umount) {
        LINFO << "Will force an umount of userdata even if it's not required";
    }
    if (!force_umount && !SupportsCheckpoint(fstab_entry)) {
        LINFO << "Userdata doesn't support checkpointing. Nothing to do";
        return 0;
    }
    CheckpointManager checkpoint_manager;
    if (!force_umount && !checkpoint_manager.NeedsCheckpoint()) {
        LINFO << "Checkpointing not needed. Don't remount";
        return 0;
    }
    if (!force_umount && fstab_entry->fs_mgr_flags.checkpoint_fs) {
        // Userdata is f2fs, simply remount it.
        if (!checkpoint_manager.Update(fstab_entry)) {
            LERROR << "Failed to remount userdata in checkpointing mode";
            return -1;
        }
        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 {
        LINFO << "Unmounting /data before remounting into checkpointing mode";
        if (!fs_mgr_unmount_all_data_mounts(block_device)) {
            LERROR << "Failed to umount /data";
            return -1;
        }
        DeviceMapper& dm = DeviceMapper::Instance();
        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.
        auto result = fs_mgr_mount_all(fstab, MOUNT_MODE_ONLY_USERDATA);
        return result.code == FS_MGR_MNTALL_FAIL ? -1 : 0;
    }
    return 0;
}

// wrapper to __mount() and expects a fully prepared fstab_rec,
// unlike fs_mgr_do_mount which does more things with avb / verity etc.
int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& alt_mount_point) {
+2 −19
Original line number Diff line number Diff line
@@ -58,13 +58,8 @@ enum mount_mode {
#define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 4
#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
#define FS_MGR_MNTALL_FAIL (-1)

struct MountAllResult {
    // One of the FS_MGR_MNTALL_* returned code defined above.
    int code;
    // Whether userdata was mounted as a result of |fs_mgr_mount_all| call.
    bool userdata_mounted;
};
// fs_mgr_mount_all() updates fstab entries that reference device-mapper.
int fs_mgr_mount_all(android::fs_mgr::Fstab* fstab, int mount_mode);

struct HashtreeInfo {
    // The hash algorithm used to build the merkle tree.
@@ -75,13 +70,6 @@ struct HashtreeInfo {
    bool check_at_most_once;
};

// fs_mgr_mount_all() updates fstab entries that reference device-mapper.
// Returns a |MountAllResult|. The first element is one of the FS_MNG_MNTALL_* return codes
// defined above, and the second element tells whether this call to fs_mgr_mount_all was responsible
// for mounting userdata. Later is required for init to correctly enqueue fs-related events as part
// of userdata remount during userspace reboot.
MountAllResult fs_mgr_mount_all(android::fs_mgr::Fstab* fstab, int mount_mode);

#define FS_MGR_DOMNT_FAILED (-1)
#define FS_MGR_DOMNT_BUSY (-2)
#define FS_MGR_DOMNT_SUCCESS 0
@@ -127,11 +115,6 @@ enum FsMgrUmountStatus : int {
// it destroys verity devices from device mapper after the device is unmounted.
int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab);

// Finds a entry in |fstab| that was used to mount a /data on |data_block_device|.
android::fs_mgr::FstabEntry* fs_mgr_get_mounted_entry_for_userdata(
        android::fs_mgr::Fstab* fstab, const std::string& data_block_device);
int fs_mgr_remount_userdata_into_checkpointing(android::fs_mgr::Fstab* fstab);

// Finds the dm_bow device on which this block device is stacked, or returns
// empty string
std::string fs_mgr_find_bow_device(const std::string& block_device);
+0 −17
Original line number Diff line number Diff line
@@ -1062,23 +1062,6 @@ TEST(fs_mgr, DefaultFstabContainsUserdata) {
            << "Default fstab doesn't contain /data entry";
}

TEST(fs_mgr, UserdataMountedFromDefaultFstab) {
    if (getuid() != 0) {
        GTEST_SKIP() << "Must be run as root.";
        return;
    }
    Fstab fstab;
    ASSERT_TRUE(ReadDefaultFstab(&fstab)) << "Failed to read default fstab";
    Fstab proc_mounts;
    ASSERT_TRUE(ReadFstabFromFile("/proc/mounts", &proc_mounts)) << "Failed to read /proc/mounts";
    auto mounted_entry = GetEntryForMountPoint(&proc_mounts, "/data");
    ASSERT_NE(mounted_entry, nullptr) << "/data is not mounted";
    std::string block_device;
    ASSERT_TRUE(android::base::Realpath(mounted_entry->blk_device, &block_device));
    ASSERT_NE(nullptr, fs_mgr_get_mounted_entry_for_userdata(&fstab, block_device))
            << "/data wasn't mounted from default fstab";
}

TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Readahead_Size_KB) {
    TemporaryFile tf;
    ASSERT_TRUE(tf.fd != -1);
+1 −36
Original line number Diff line number Diff line
@@ -606,8 +606,6 @@ static Result<void> queue_fs_event(int code) {
    return Error() << "Invalid code: " << code;
}

static int initial_mount_fstab_return_code = -1;

/* <= Q: mount_all <fstab> [ <path> ]* [--<options>]*
 * >= R: mount_all [ <fstab> ] [--<options>]*
 *
@@ -648,19 +646,10 @@ static Result<void> do_mount_all(const BuiltinArguments& args) {
        import_late(mount_all->rc_paths);
    }

    if (mount_fstab_result.userdata_mounted) {
        // This call to fs_mgr_mount_all mounted userdata. Keep the result in
        // order for userspace reboot to correctly remount userdata.
        LOG(INFO) << "Userdata mounted using "
                  << (mount_all->fstab_path.empty() ? "(default fstab)" : mount_all->fstab_path)
                  << " result : " << mount_fstab_result.code;
        initial_mount_fstab_return_code = mount_fstab_result.code;
    }

    if (queue_event) {
        /* queue_fs_event will queue event based on mount_fstab return code
         * and return processed return code*/
        auto queue_fs_result = queue_fs_event(mount_fstab_result.code);
        auto queue_fs_result = queue_fs_event(mount_fstab_result);
        if (!queue_fs_result.ok()) {
            return Error() << "queue_fs_event() failed: " << queue_fs_result.error();
        }
@@ -1178,29 +1167,6 @@ static Result<void> ExecVdcRebootOnFailure(const std::string& vdc_arg) {
    return ExecWithFunctionOnFailure(args, reboot);
}

static Result<void> do_remount_userdata(const BuiltinArguments& args) {
    if (initial_mount_fstab_return_code == -1) {
        return Error() << "Calling remount_userdata too early";
    }
    Fstab fstab;
    if (!ReadDefaultFstab(&fstab)) {
        // TODO(b/135984674): should we reboot here?
        return Error() << "Failed to read fstab";
    }
    // TODO(b/135984674): check that fstab contains /data.
    if (auto rc = fs_mgr_remount_userdata_into_checkpointing(&fstab); rc < 0) {
        std::string proc_mounts_output;
        android::base::ReadFileToString("/proc/mounts", &proc_mounts_output, true);
        android::base::WriteStringToFile(proc_mounts_output,
                                         "/metadata/userspacereboot/mount_info.txt");
        trigger_shutdown("reboot,mount_userdata_failed");
    }
    if (auto result = queue_fs_event(initial_mount_fstab_return_code); !result.ok()) {
        return Error() << "queue_fs_event() failed: " << result.error();
    }
    return {};
}

static Result<void> do_installkey(const BuiltinArguments& args) {
    if (!is_file_crypto()) return {};

@@ -1361,7 +1327,6 @@ const BuiltinFunctionMap& GetBuiltinFunctionMap() {
        {"umount_all",              {0,     1,    {false,  do_umount_all}}},
        {"update_linker_config",    {0,     0,    {false,  do_update_linker_config}}},
        {"readahead",               {1,     2,    {true,   do_readahead}}},
        {"remount_userdata",        {0,     0,    {false,  do_remount_userdata}}},
        {"restart",                 {1,     2,    {false,  do_restart}}},
        {"restorecon",              {1,     kMax, {true,   do_restorecon}}},
        {"restorecon_recursive",    {1,     kMax, {true,   do_restorecon_recursive}}},
+2 −3
Original line number Diff line number Diff line
@@ -102,7 +102,6 @@ using android::properties::BuildTrie;
using android::properties::ParsePropertyInfoFile;
using android::properties::PropertyInfoAreaFile;
using android::properties::PropertyInfoEntry;
using android::sysprop::InitProperties::is_userspace_reboot_supported;

namespace android {
namespace init {
@@ -569,8 +568,8 @@ std::optional<uint32_t> HandlePropertySet(const std::string& name, const std::st
        }
        LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
                  << process_log_string;
        if (value == "reboot,userspace" && !is_userspace_reboot_supported().value_or(false)) {
            *error = "Userspace reboot is not supported by this device";
        if (value == "reboot,userspace") {
            *error = "Userspace reboot is deprecated.";
            return {PROP_ERROR_INVALID_VALUE};
        }
    }
Loading