From 784c22c8388e50db243ac4ca3871747cd3eefadc Mon Sep 17 00:00:00 2001 From: Yusuke Sato Date: Wed, 8 Jul 2015 14:57:07 -0700 Subject: Use fsck.f2fs -a instead of -f for faster boot and run fsck with -f on clean shutdown instead. With -f, fsck.f2fs always performs a full scan of the /data partition regardless of whether the partition is clean or not. The full scan takes more than 2 seconds on volantis-userdebug and delays the OS boot. With -a, the command does almost nothing when the partition is clean and finishes within 20-30ms on volantis-userdebug. When the partition has an error or its check point has CP_FSCK_FLAG (aka "need_fsck"), the command does exactly the same full scan as -f to fix it. Bug: 21853106 Change-Id: I126263caf34c0f5bb8f5e6794454d4e72526ce38 --- init/builtins.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) (limited to 'init') diff --git a/init/builtins.cpp b/init/builtins.cpp index b290ce3..d0dbecc 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -16,7 +16,9 @@ #include #include +#include #include +#include #include #include #include @@ -38,6 +40,7 @@ #include #include #include +#include #include #include "init.h" @@ -49,6 +52,8 @@ #include "log.h" #define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW +#define UNMOUNT_CHECK_MS 5000 +#define UNMOUNT_CHECK_TIMES 10 int add_environment(const char *name, const char *value); @@ -109,6 +114,67 @@ static void service_start_if_not_disabled(struct service *svc) } } +static void unmount_and_fsck(const struct mntent *entry) +{ + if (strcmp(entry->mnt_type, "f2fs") && strcmp(entry->mnt_type, "ext4")) + return; + + /* First, lazily unmount the directory. This unmount request finishes when + * all processes that open a file or directory in |entry->mnt_dir| exit. + */ + TEMP_FAILURE_RETRY(umount2(entry->mnt_dir, MNT_DETACH)); + + /* Next, kill all processes except init, kthreadd, and kthreadd's + * children to finish the lazy unmount. Killing all processes here is okay + * because this callback function is only called right before reboot(). + * It might be cleaner to selectively kill processes that actually use + * |entry->mnt_dir| rather than killing all, probably by reusing a function + * like killProcessesWithOpenFiles() in vold/, but the selinux policy does + * not allow init to scan /proc/ files which the utility function + * heavily relies on. The policy does not allow the process to execute + * killall/pkill binaries either. Note that some processes might + * automatically restart after kill(), but that is not really a problem + * because |entry->mnt_dir| is no longer visible to such new processes. + */ + service_for_each(service_stop); + TEMP_FAILURE_RETRY(kill(-1, SIGKILL)); + + int count = 0; + while (count++ < UNMOUNT_CHECK_TIMES) { + int fd = TEMP_FAILURE_RETRY(open(entry->mnt_fsname, O_RDONLY | O_EXCL)); + if (fd >= 0) { + /* |entry->mnt_dir| has sucessfully been unmounted. */ + close(fd); + break; + } else if (errno == EBUSY) { + /* Some processes using |entry->mnt_dir| are still alive. Wait for a + * while then retry. + */ + TEMP_FAILURE_RETRY( + usleep(UNMOUNT_CHECK_MS * 1000 / UNMOUNT_CHECK_TIMES)); + continue; + } else { + /* Cannot open the device. Give up. */ + return; + } + } + + int st; + if (!strcmp(entry->mnt_type, "f2fs")) { + const char *f2fs_argv[] = { + "/system/bin/fsck.f2fs", "-f", entry->mnt_fsname, + }; + android_fork_execvp_ext(ARRAY_SIZE(f2fs_argv), (char **)f2fs_argv, + &st, true, LOG_KLOG, true, NULL); + } else if (!strcmp(entry->mnt_type, "ext4")) { + const char *ext4_argv[] = { + "/system/bin/e2fsck", "-f", "-y", entry->mnt_fsname, + }; + android_fork_execvp_ext(ARRAY_SIZE(ext4_argv), (char **)ext4_argv, + &st, true, LOG_KLOG, true, NULL); + } +} + int do_class_start(int nargs, char **args) { char prop[PROP_NAME_MAX]; @@ -577,6 +643,7 @@ int do_powerctl(int nargs, char **args) int len = 0; int cmd = 0; const char *reboot_target; + void (*callback_on_ro_remount)(const struct mntent*) = NULL; res = expand_props(command, args[1], sizeof(command)); if (res) { @@ -590,6 +657,7 @@ int do_powerctl(int nargs, char **args) } cmd = ANDROID_RB_POWEROFF; len = 8; + callback_on_ro_remount = unmount_and_fsck; } else if (strncmp(command, "reboot", 6) == 0) { cmd = ANDROID_RB_RESTART2; len = 6; @@ -614,7 +682,8 @@ int do_powerctl(int nargs, char **args) return -EINVAL; } - return android_reboot(cmd, 0, reboot_target); + return android_reboot_with_callback(cmd, 0, reboot_target, + callback_on_ro_remount); } int do_trigger(int nargs, char **args) -- cgit v1.1