summaryrefslogtreecommitdiffstats
path: root/libcutils
diff options
context:
space:
mode:
authorYusuke Sato <yusukes@google.com>2015-07-08 14:57:07 -0700
committerSteve Kondik <steve@cyngn.com>2016-05-05 18:36:06 -0700
commit784c22c8388e50db243ac4ca3871747cd3eefadc (patch)
treecd61ce81b20696711d1cb566d984a3ff7b910c48 /libcutils
parent0d6557ec30fc8c3e06badcae93efff1ee5f6b6a1 (diff)
downloadsystem_core-784c22c8388e50db243ac4ca3871747cd3eefadc.tar.gz
system_core-784c22c8388e50db243ac4ca3871747cd3eefadc.tar.bz2
system_core-784c22c8388e50db243ac4ca3871747cd3eefadc.zip
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
Diffstat (limited to 'libcutils')
-rw-r--r--libcutils/android_reboot.c187
1 files changed, 155 insertions, 32 deletions
diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c
index 6ae23c1f0..af7e1892e 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.c
@@ -14,43 +14,108 @@
* limitations under the License.
*/
-#include <unistd.h>
-#include <sys/reboot.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <errno.h>
#include <fcntl.h>
#include <mntent.h>
+#include <stdbool.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <sys/cdefs.h>
+#include <sys/mount.h>
+#include <sys/reboot.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <cutils/android_reboot.h>
+#include <cutils/klog.h>
+#include <cutils/list.h>
-#define UNUSED __attribute__((unused))
+#define TAG "android_reboot"
+#define READONLY_CHECK_MS 5000
+#define READONLY_CHECK_TIMES 50
-/* Check to see if /proc/mounts contains any writeable filesystems
- * backed by a block device.
- * Return true if none found, else return false.
+typedef struct {
+ struct listnode list;
+ struct mntent entry;
+} mntent_list;
+
+static bool has_mount_option(const char* opts, const char* opt_to_find)
+{
+ bool ret = false;
+ char* copy = NULL;
+ char* opt;
+ char* rem;
+
+ while ((opt = strtok_r(copy ? NULL : (copy = strdup(opts)), ",", &rem))) {
+ if (!strcmp(opt, opt_to_find)) {
+ ret = true;
+ break;
+ }
+ }
+
+ free(copy);
+ return ret;
+}
+
+static bool is_block_device(const char* fsname)
+{
+ return !strncmp(fsname, "/dev/block", 10);
+}
+
+/* Find all read+write block devices in /proc/mounts and add them to
+ * |rw_entries|.
*/
-static int remount_ro_done(void)
+static void find_rw(struct listnode* rw_entries)
{
FILE* fp;
struct mntent* mentry;
- int found_rw_fs = 0;
if ((fp = setmntent("/proc/mounts", "r")) == NULL) {
- /* If we can't read /proc/mounts, just give up. */
- return 1;
+ KLOG_WARNING(TAG, "Failed to open /proc/mounts.\n");
+ return;
}
while ((mentry = getmntent(fp)) != NULL) {
- if (!strncmp(mentry->mnt_fsname, "/dev/block", 10) && strstr(mentry->mnt_opts, "rw,")) {
- found_rw_fs = 1;
- break;
+ if (is_block_device(mentry->mnt_fsname) &&
+ has_mount_option(mentry->mnt_opts, "rw")) {
+ mntent_list* item = (mntent_list*)calloc(1, sizeof(mntent_list));
+ item->entry = *mentry;
+ item->entry.mnt_fsname = strdup(mentry->mnt_fsname);
+ item->entry.mnt_dir = strdup(mentry->mnt_dir);
+ item->entry.mnt_type = strdup(mentry->mnt_type);
+ item->entry.mnt_opts = strdup(mentry->mnt_opts);
+ list_add_tail(rw_entries, &item->list);
}
}
endmntent(fp);
+}
+
+static void free_entries(struct listnode* entries)
+{
+ struct listnode* node;
+ struct listnode* n;
+ list_for_each_safe(node, n, entries) {
+ mntent_list* item = node_to_item(node, mntent_list, list);
+ free(item->entry.mnt_fsname);
+ free(item->entry.mnt_dir);
+ free(item->entry.mnt_type);
+ free(item->entry.mnt_opts);
+ free(item);
+ }
+}
- return !found_rw_fs;
+static mntent_list* find_item(struct listnode* rw_entries, const char* fsname_to_find)
+{
+ struct listnode* node;
+ list_for_each(node, rw_entries) {
+ mntent_list* item = node_to_item(node, mntent_list, list);
+ if (!strcmp(item->entry.mnt_fsname, fsname_to_find)) {
+ return item;
+ }
+ }
+ return NULL;
}
/* Remounting filesystems read-only is difficult when there are files
@@ -64,38 +129,92 @@ static int remount_ro_done(void)
* repeatedly until there are no more writable filesystems mounted on
* block devices.
*/
-static void remount_ro(void)
+static void remount_ro(void (*cb_on_remount)(const struct mntent*))
{
- int fd, cnt = 0;
+ int fd, cnt;
+ FILE* fp;
+ struct mntent* mentry;
+ struct listnode* node;
+
+ list_declare(rw_entries);
+ list_declare(ro_entries);
+
+ sync();
+ find_rw(&rw_entries);
/* Trigger the remount of the filesystems as read-only,
* which also marks them clean.
*/
- fd = open("/proc/sysrq-trigger", O_WRONLY);
+ fd = TEMP_FAILURE_RETRY(open("/proc/sysrq-trigger", O_WRONLY));
if (fd < 0) {
- return;
+ KLOG_WARNING(TAG, "Failed to open sysrq-trigger.\n");
+ /* TODO: Try to remount each rw parition manually in readonly mode.
+ * This may succeed if no process is using the partition.
+ */
+ goto out;
+ }
+ if (TEMP_FAILURE_RETRY(write(fd, "u", 1)) != 1) {
+ close(fd);
+ KLOG_WARNING(TAG, "Failed to write to sysrq-trigger.\n");
+ /* TODO: The same. Manually remount the paritions. */
+ goto out;
}
- write(fd, "u", 1);
close(fd);
-
/* Now poll /proc/mounts till it's done */
- while (!remount_ro_done() && (cnt < 50)) {
- usleep(100000);
+ cnt = 0;
+ while (cnt < READONLY_CHECK_TIMES) {
+ if ((fp = setmntent("/proc/mounts", "r")) == NULL) {
+ /* If we can't read /proc/mounts, just give up. */
+ KLOG_WARNING(TAG, "Failed to open /proc/mounts.\n");
+ goto out;
+ }
+ while ((mentry = getmntent(fp)) != NULL) {
+ if (!is_block_device(mentry->mnt_fsname) ||
+ !has_mount_option(mentry->mnt_opts, "ro")) {
+ continue;
+ }
+ mntent_list* item = find_item(&rw_entries, mentry->mnt_fsname);
+ if (item) {
+ /* |item| has now been ro remounted. */
+ list_remove(&item->list);
+ list_add_tail(&ro_entries, &item->list);
+ }
+ }
+ endmntent(fp);
+ if (list_empty(&rw_entries)) {
+ /* All rw block devices are now readonly. */
+ break;
+ }
+ TEMP_FAILURE_RETRY(
+ usleep(READONLY_CHECK_MS * 1000 / READONLY_CHECK_TIMES));
cnt++;
}
- return;
-}
+ list_for_each(node, &rw_entries) {
+ mntent_list* item = node_to_item(node, mntent_list, list);
+ KLOG_WARNING(TAG, "Failed to remount %s in readonly mode.\n",
+ item->entry.mnt_fsname);
+ }
+
+ if (cb_on_remount) {
+ list_for_each(node, &ro_entries) {
+ mntent_list* item = node_to_item(node, mntent_list, list);
+ cb_on_remount(&item->entry);
+ }
+ }
+out:
+ free_entries(&rw_entries);
+ free_entries(&ro_entries);
+}
-int android_reboot(int cmd, int flags UNUSED, const char *arg)
+int android_reboot_with_callback(
+ int cmd, int flags __unused, const char *arg,
+ void (*cb_on_remount)(const struct mntent*))
{
int ret;
-
- sync();
- remount_ro();
-
+ remount_ro(cb_on_remount);
switch (cmd) {
case ANDROID_RB_RESTART:
ret = reboot(RB_AUTOBOOT);
@@ -117,3 +236,7 @@ int android_reboot(int cmd, int flags UNUSED, const char *arg)
return ret;
}
+int android_reboot(int cmd, int flags, const char *arg)
+{
+ return android_reboot_with_callback(cmd, flags, arg, NULL);
+}