Loading fs_mgr/fs_mgr.cpp +75 −7 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; } Loading Loading @@ -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) { Loading fs_mgr/include/fs_mgr.h +2 −0 Original line number Diff line number Diff line Loading @@ -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); init/builtins.cpp +26 −0 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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 Loading Loading @@ -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())); Loading @@ -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(); Loading Loading @@ -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 {}; Loading Loading @@ -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}}}, Loading init/reboot.cpp +38 −14 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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); Loading @@ -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. Loading Loading @@ -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) { Loading rootdir/init.rc +10 −2 Original line number Diff line number Diff line Loading @@ -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 Loading Loading
fs_mgr/fs_mgr.cpp +75 −7 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; } Loading Loading @@ -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) { Loading
fs_mgr/include/fs_mgr.h +2 −0 Original line number Diff line number Diff line Loading @@ -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);
init/builtins.cpp +26 −0 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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 Loading Loading @@ -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())); Loading @@ -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(); Loading Loading @@ -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 {}; Loading Loading @@ -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}}}, Loading
init/reboot.cpp +38 −14 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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); Loading @@ -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. Loading Loading @@ -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) { Loading
rootdir/init.rc +10 −2 Original line number Diff line number Diff line Loading @@ -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 Loading