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

Commit 4243e483 authored by Nikita Ioffe's avatar Nikita Ioffe Committed by android-build-merger
Browse files

Merge "Userspace reboot: Support remounting userdata for f2fs" am: 8a603a7f

am: 38aeac4a

Change-Id: Ie7498786ad3eb3ff7ad063ff2fbba492bdf9b492
parents 5593862d 38aeac4a
Loading
Loading
Loading
Loading
+75 −7
Original line number Diff line number Diff line
@@ -888,6 +888,17 @@ class CheckpointManager {
  public:
    CheckpointManager(int needs_checkpoint = -1) : needs_checkpoint_(needs_checkpoint) {}

    bool NeedsCheckpoint() {
        if (needs_checkpoint_ != UNKNOWN) {
            return needs_checkpoint_ == YES;
        }
        if (!call_vdc({"checkpoint", "needsCheckpoint"}, &needs_checkpoint_)) {
            LERROR << "Failed to find if checkpointing is needed. Assuming no.";
            needs_checkpoint_ = NO;
        }
        return needs_checkpoint_ == YES;
    }

    bool Update(FstabEntry* entry, const std::string& block_device = std::string()) {
        if (!entry->fs_mgr_flags.checkpoint_blk && !entry->fs_mgr_flags.checkpoint_fs) {
            return true;
@@ -897,13 +908,7 @@ class CheckpointManager {
            call_vdc({"checkpoint", "restoreCheckpoint", entry->blk_device}, nullptr);
        }

        if (needs_checkpoint_ == UNKNOWN &&
            !call_vdc({"checkpoint", "needsCheckpoint"}, &needs_checkpoint_)) {
            LERROR << "Failed to find if checkpointing is needed. Assuming no.";
            needs_checkpoint_ = NO;
        }

        if (needs_checkpoint_ != YES) {
        if (!NeedsCheckpoint()) {
            return true;
        }

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

static std::string GetUserdataBlockDevice() {
    Fstab fstab;
    if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
        LERROR << "Failed to read /proc/mounts";
        return "";
    }
    auto entry = GetEntryForMountPoint(&fstab, "/data");
    if (entry == nullptr) {
        LERROR << "Didn't find /data mount point in /proc/mounts";
        return "";
    }
    return entry->blk_device;
}

int fs_mgr_remount_userdata_into_checkpointing(Fstab* fstab) {
    const std::string& block_device = GetUserdataBlockDevice();
    LINFO << "Userdata is mounted on " << block_device;
    auto entry = std::find_if(fstab->begin(), fstab->end(), [&block_device](const FstabEntry& e) {
        if (e.mount_point != "/data") {
            return false;
        }
        if (e.blk_device == block_device) {
            return true;
        }
        DeviceMapper& dm = DeviceMapper::Instance();
        std::string path;
        if (!dm.GetDmDevicePathByName("userdata", &path)) {
            return false;
        }
        return path == block_device;
    });
    if (entry == fstab->end()) {
        LERROR << "Can't find /data in fstab";
        return -1;
    }
    if (!entry->fs_mgr_flags.checkpoint_blk && !entry->fs_mgr_flags.checkpoint_fs) {
        LINFO << "Userdata doesn't support checkpointing. Nothing to do";
        return 0;
    }
    CheckpointManager checkpoint_manager;
    if (!checkpoint_manager.NeedsCheckpoint()) {
        LINFO << "Checkpointing not needed. Don't remount";
        return 0;
    }
    if (entry->fs_mgr_flags.checkpoint_fs) {
        // Userdata is f2fs, simply remount it.
        if (!checkpoint_manager.Update(&(*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) {
            LERROR << "Failed to remount userdata in checkpointing mode";
            return -1;
        }
    } else {
        // TODO(b/135984674): support remounting for ext4.
        LERROR << "Remounting in checkpointing mode is not yet supported for ext4";
        return -1;
    }
    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& mount_point) {
+2 −0
Original line number Diff line number Diff line
@@ -105,6 +105,8 @@ 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);

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);
+26 −0
Original line number Diff line number Diff line
@@ -42,6 +42,8 @@
#include <sys/wait.h>
#include <unistd.h>

#include <memory>

#include <ApexProperties.sysprop.h>
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
@@ -627,6 +629,8 @@ static Result<void> queue_fs_event(int code) {
    return Error() << "Invalid code: " << code;
}

static int initial_mount_fstab_return_code = -1;

/* mount_all <fstab> [ <path> ]* [--<options>]*
 *
 * This function might request a reboot, in which case it will
@@ -662,6 +666,7 @@ static Result<void> do_mount_all(const BuiltinArguments& args) {
    if (!ReadFstabFromFile(fstab_file, &fstab)) {
        return Error() << "Could not read fstab";
    }

    auto mount_fstab_return_code = fs_mgr_mount_all(&fstab, mount_mode);
    property_set(prop_name, std::to_string(t.duration().count()));

@@ -673,6 +678,7 @@ static Result<void> do_mount_all(const BuiltinArguments& args) {
    if (queue_event) {
        /* queue_fs_event will queue event based on mount_fstab return code
         * and return processed return code*/
        initial_mount_fstab_return_code = mount_fstab_return_code;
        auto queue_fs_result = queue_fs_event(mount_fstab_return_code);
        if (!queue_fs_result) {
            return Error() << "queue_fs_event() failed: " << queue_fs_result.error();
@@ -1132,6 +1138,25 @@ 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) {
        TriggerShutdown("reboot,mount-userdata-failed");
    }
    if (auto result = queue_fs_event(initial_mount_fstab_return_code); !result) {
        return Error() << "queue_fs_event() failed: " << result.error();
    }
    return {};
}

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

@@ -1243,6 +1268,7 @@ const BuiltinFunctionMap& GetBuiltinFunctionMap() {
        {"umount",                  {1,     1,    {false,  do_umount}}},
        {"umount_all",              {1,     1,    {false,  do_umount_all}}},
        {"readahead",               {1,     2,    {true,   do_readahead}}},
        {"remount_userdata",        {0,     0,    {false,  do_remount_userdata}}},
        {"restart",                 {1,     1,    {false,  do_restart}}},
        {"restorecon",              {1,     kMax, {true,   do_restorecon}}},
        {"restorecon_recursive",    {1,     kMax, {true,   do_restorecon_recursive}}},
+38 −14
Original line number Diff line number Diff line
@@ -181,10 +181,17 @@ static void TurnOffBacklight() {
    }
}

static void ShutdownVold() {
static Result<void> ShutdownVold() {
    const char* vdc_argv[] = {"/system/bin/vdc", "volume", "shutdown"};
    int status;
    logwrap_fork_execvp(arraysize(vdc_argv), vdc_argv, &status, false, LOG_KLOG, true, nullptr);
    if (logwrap_fork_execvp(arraysize(vdc_argv), vdc_argv, &status, false, LOG_KLOG, true,
                            nullptr) != 0) {
        return ErrnoError() << "Failed to call 'vdc volume shutdown'";
    }
    if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
        return {};
    }
    return Error() << "'vdc volume shutdown' failed : " << status;
}

static void LogShutdownTime(UmountStat stat, Timer* t) {
@@ -427,11 +434,11 @@ static UmountStat TryUmountAndFsck(unsigned int cmd, bool run_fsck,
#define ZRAM_DEVICE   "/dev/block/zram0"
#define ZRAM_RESET    "/sys/block/zram0/reset"
#define ZRAM_BACK_DEV "/sys/block/zram0/backing_dev"
static void KillZramBackingDevice() {
static Result<void> KillZramBackingDevice() {
    std::string backing_dev;
    if (!android::base::ReadFileToString(ZRAM_BACK_DEV, &backing_dev)) return;
    if (!android::base::ReadFileToString(ZRAM_BACK_DEV, &backing_dev)) return {};

    if (!android::base::StartsWith(backing_dev, "/dev/block/loop")) return;
    if (!android::base::StartsWith(backing_dev, "/dev/block/loop")) return {};

    // cut the last "\n"
    backing_dev.erase(backing_dev.length() - 1);
@@ -440,28 +447,29 @@ static void KillZramBackingDevice() {
    Timer swap_timer;
    LOG(INFO) << "swapoff() start...";
    if (swapoff(ZRAM_DEVICE) == -1) {
        LOG(ERROR) << "zram_backing_dev: swapoff (" << backing_dev << ")" << " failed";
        return;
        return ErrnoError() << "zram_backing_dev: swapoff (" << backing_dev << ")"
                            << " failed";
    }
    LOG(INFO) << "swapoff() took " << swap_timer;;

    if (!WriteStringToFile("1", ZRAM_RESET)) {
        LOG(ERROR) << "zram_backing_dev: reset (" << backing_dev << ")" << " failed";
        return;
        return Error() << "zram_backing_dev: reset (" << backing_dev << ")"
                       << " failed";
    }

    // clear loopback device
    unique_fd loop(TEMP_FAILURE_RETRY(open(backing_dev.c_str(), O_RDWR | O_CLOEXEC)));
    if (loop.get() < 0) {
        LOG(ERROR) << "zram_backing_dev: open(" << backing_dev << ")" << " failed";
        return;
        return ErrnoError() << "zram_backing_dev: open(" << backing_dev << ")"
                            << " failed";
    }

    if (ioctl(loop.get(), LOOP_CLR_FD, 0) < 0) {
        LOG(ERROR) << "zram_backing_dev: loop_clear (" << backing_dev << ")" << " failed";
        return;
        return ErrnoError() << "zram_backing_dev: loop_clear (" << backing_dev << ")"
                            << " failed";
    }
    LOG(INFO) << "zram_backing_dev: `" << backing_dev << "` is cleared successfully.";
    return {};
}

// Stops given services, waits for them to be stopped for |timeout| ms.
@@ -738,7 +746,23 @@ static Result<void> DoUserspaceReboot() {
        // TODO(b/135984674): store information about offending services for debugging.
        return Error() << r << " post-data services are still running";
    }
    // TODO(b/135984674): remount userdata
    // We only really need to restart vold if userdata is ext4 filesystem.
    // TODO(b/135984674): get userdata fs type here, and do nothing in case of f2fs.
    // First shutdown volumes managed by vold. They will be recreated by
    // system_server.
    Service* vold_service = ServiceList::GetInstance().FindService("vold");
    if (vold_service != nullptr && vold_service->IsRunning()) {
        if (auto result = ShutdownVold(); !result) {
            return result;
        }
        LOG(INFO) << "Restarting vold";
        vold_service->Restart();
    }
    // Again, we only need to kill zram backing device in case of ext4 userdata.
    // TODO(b/135984674): get userdata fs type here, and do nothing in case of f2fs.
    if (auto result = KillZramBackingDevice(); !result) {
        return result;
    }
    if (int r = StopServicesAndLogViolations(GetDebuggingServices(true /* only_post_data */), 5s,
                                             false /* SIGKILL */);
        r > 0) {
+10 −2
Original line number Diff line number Diff line
@@ -926,9 +926,17 @@ on userspace-reboot
  setprop sys.init.updatable_crashing 0
  setprop apexd.status 0

on userspace-reboot-fs-remount
  # Make sure that vold is running.
  # This is mostly a precaution measure in case vold for some reason wasn't running when
  # userspace reboot was initiated.
  start vold
  exec - system system -- /system/bin/vdc checkpoint resetCheckpoint
  exec - system system -- /system/bin/vdc checkpoint markBootAttempt
  remount_userdata

on userspace-reboot-resume
  # TODO(b/135984674): remount userdata and reset checkpointing
  trigger nonencrypted
  trigger userspace-reboot-fs-remount
  trigger post-fs-data
  trigger zygote-start
  trigger early-boot