Merge "liblog: fortify event_log_tags test"
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index e0d46d3..f682216 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -22,6 +22,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/ioctl.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
 #include <sys/swap.h>
@@ -38,6 +39,7 @@
 #include <ext4_utils/ext4_sb.h>
 #include <ext4_utils/ext4_utils.h>
 #include <ext4_utils/wipe.h>
+#include <linux/fs.h>
 #include <linux/loop.h>
 #include <logwrap/logwrap.h>
 #include <private/android_filesystem_config.h>
@@ -50,8 +52,9 @@
 #define KEY_IN_FOOTER  "footer"
 
 #define E2FSCK_BIN      "/system/bin/e2fsck"
-#define F2FS_FSCK_BIN  "/system/bin/fsck.f2fs"
+#define F2FS_FSCK_BIN   "/system/bin/fsck.f2fs"
 #define MKSWAP_BIN      "/system/bin/mkswap"
+#define TUNE2FS_BIN     "/system/bin/tune2fs"
 
 #define FSCK_LOG_FILE   "/dev/fscklogs/log"
 
@@ -180,6 +183,99 @@
     return;
 }
 
+/* Function to read the primary superblock */
+static int read_super_block(int fd, struct ext4_super_block *sb)
+{
+    off64_t ret;
+
+    ret = lseek64(fd, 1024, SEEK_SET);
+    if (ret < 0)
+        return ret;
+
+    ret = read(fd, sb, sizeof(*sb));
+    if (ret < 0)
+        return ret;
+    if (ret != sizeof(*sb))
+        return ret;
+
+    return 0;
+}
+
+static ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es)
+{
+    return ((ext4_fsblk_t)le32_to_cpu(es->s_blocks_count_hi) << 32) |
+            le32_to_cpu(es->s_blocks_count_lo);
+}
+
+static ext4_fsblk_t ext4_r_blocks_count(struct ext4_super_block *es)
+{
+    return ((ext4_fsblk_t)le32_to_cpu(es->s_r_blocks_count_hi) << 32) |
+            le32_to_cpu(es->s_r_blocks_count_lo);
+}
+
+static void do_reserved_size(char *blk_device, char *fs_type, struct fstab_rec *rec)
+{
+    /* Check for the types of filesystems we know how to check */
+    if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
+        /*
+         * Some system images do not have tune2fs for licensing reasons
+         * Detect these and skip reserve blocks.
+         */
+        if (access(TUNE2FS_BIN, X_OK)) {
+            ERROR("Not running %s on %s (executable not in system image)\n",
+                  TUNE2FS_BIN, blk_device);
+        } else {
+            INFO("Running %s on %s\n", TUNE2FS_BIN, blk_device);
+
+            int status = 0;
+            int ret = 0;
+            unsigned long reserved_blocks = 0;
+            int fd = TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC));
+            if (fd >= 0) {
+                struct ext4_super_block sb;
+                ret = read_super_block(fd, &sb);
+                if (ret < 0) {
+                    ERROR("Can't read '%s' super block: %s\n", blk_device, strerror(errno));
+                    goto out;
+                }
+                reserved_blocks = rec->reserved_size / EXT4_BLOCK_SIZE(&sb);
+                unsigned long reserved_threshold = ext4_blocks_count(&sb) * 0.02;
+                if (reserved_threshold < reserved_blocks) {
+                    WARNING("Reserved blocks %lu is too large\n", reserved_blocks);
+                    reserved_blocks = reserved_threshold;
+                }
+
+                if (ext4_r_blocks_count(&sb) == reserved_blocks) {
+                    INFO("Have reserved same blocks\n");
+                    goto out;
+                }
+            } else {
+                ERROR("Failed to open '%s': %s\n", blk_device, strerror(errno));
+                return;
+            }
+
+            char buf[16] = {0};
+            snprintf(buf, sizeof (buf), "-r %lu", reserved_blocks);
+            char *tune2fs_argv[] = {
+                TUNE2FS_BIN,
+                buf,
+                blk_device,
+            };
+
+            ret = android_fork_execvp_ext(ARRAY_SIZE(tune2fs_argv), tune2fs_argv,
+                                          &status, true, LOG_KLOG | LOG_FILE,
+                                          true, NULL, NULL, 0);
+
+            if (ret < 0) {
+                /* No need to check for error in fork, we can't really handle it now */
+                ERROR("Failed trying to run %s\n", TUNE2FS_BIN);
+            }
+      out:
+            close(fd);
+        }
+    }
+}
+
 static void remove_trailing_slashes(char *n)
 {
     int len;
@@ -325,6 +421,12 @@
                 check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
                          fstab->recs[i].mount_point);
             }
+
+            if (fstab->recs[i].fs_mgr_flags & MF_RESERVEDSIZE) {
+                do_reserved_size(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
+                                 &fstab->recs[i]);
+            }
+
             if (!__mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point, &fstab->recs[i])) {
                 *attempted_idx = i;
                 mounted = 1;
@@ -690,6 +792,10 @@
                      fstab->recs[i].mount_point);
         }
 
+        if (fstab->recs[i].fs_mgr_flags & MF_RESERVEDSIZE) {
+            do_reserved_size(n_blk_device, fstab->recs[i].fs_type, &fstab->recs[i]);
+        }
+
         if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
             int rc = fs_mgr_setup_verity(&fstab->recs[i]);
             if (__android_log_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index b219b38..472b421 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -33,6 +33,7 @@
     int swap_prio;
     int max_comp_streams;
     unsigned int zram_size;
+    uint64_t reserved_size;
 };
 
 struct flag_list {
@@ -80,6 +81,7 @@
     { "slotselect",  MF_SLOTSELECT },
     { "nofail",      MF_NOFAIL },
     { "latemount",   MF_LATEMOUNT },
+    { "reservedsize=", MF_RESERVEDSIZE },
     { "defaults",    0 },
     { 0,             0 },
 };
@@ -97,6 +99,20 @@
     return total;
 }
 
+static uint64_t parse_size(const char *arg)
+{
+    char *endptr;
+    uint64_t size = strtoull(arg, &endptr, 10);
+    if (*endptr == 'k' || *endptr == 'K')
+        size *= 1024LL;
+    else if (*endptr == 'm' || *endptr == 'M')
+        size *= 1024LL * 1024LL;
+    else if (*endptr == 'g' || *endptr == 'G')
+        size *= 1024LL * 1024LL * 1024LL;
+
+    return size;
+}
+
 static int parse_flags(char *flags, struct flag_list *fl,
                        struct fs_mgr_flag_values *flag_vals,
                        char *fs_options, int fs_options_len)
@@ -191,6 +207,11 @@
                         flag_vals->zram_size = calculate_zram_size(val);
                     else
                         flag_vals->zram_size = val;
+                } else if ((fl[i].flag == MF_RESERVEDSIZE) && flag_vals) {
+                    /* The reserved flag is followed by an = and the
+                     * reserved size of the partition.  Get it and return it.
+                     */
+                    flag_vals->reserved_size = parse_size(strchr(p, '=') + 1);
                 }
                 break;
             }
@@ -335,6 +356,7 @@
         fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
         fstab->recs[cnt].max_comp_streams = flag_vals.max_comp_streams;
         fstab->recs[cnt].zram_size = flag_vals.zram_size;
+        fstab->recs[cnt].reserved_size = flag_vals.reserved_size;
         cnt++;
     }
     /* If an A/B partition, modify block device to be the real block device */
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 741f5e9..23c97e4 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -86,6 +86,7 @@
 #define MF_LATEMOUNT    0x20000
 #define MF_NOFAIL       0x40000
 #define MF_MAX_COMP_STREAMS 0x100000
+#define MF_RESERVEDSIZE 0x200000
 
 #define DM_BUF_SIZE 4096
 
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 37df8f8..43aef20 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -75,6 +75,7 @@
     int swap_prio;
     int max_comp_streams;
     unsigned int zram_size;
+    uint64_t reserved_size;
 };
 
 // Callback function for verity status
diff --git a/init/init.cpp b/init/init.cpp
index 371186b..ef6f37c 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -731,15 +731,15 @@
         // By default, sleep until something happens.
         int epoll_timeout_ms = -1;
 
-        // If there's more work to do, wake up again immediately.
-        if (am.HasMoreCommands()) epoll_timeout_ms = 0;
-
         // If there's a process that needs restarting, wake up in time for that.
         if (process_needs_restart_at != 0) {
             epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
             if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
         }
 
+        // If there's more work to do, wake up again immediately.
+        if (am.HasMoreCommands()) epoll_timeout_ms = 0;
+
         bootchart_sample(&epoll_timeout_ms);
 
         epoll_event ev;
diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c
index af7e189..159a9d4 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.c
@@ -42,24 +42,6 @@
     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);
@@ -78,8 +60,7 @@
         return;
     }
     while ((mentry = getmntent(fp)) != NULL) {
-        if (is_block_device(mentry->mnt_fsname) &&
-            has_mount_option(mentry->mnt_opts, "rw")) {
+        if (is_block_device(mentry->mnt_fsname) && hasmntopt(mentry, "rw")) {
             mntent_list* item = (mntent_list*)calloc(1, sizeof(mntent_list));
             item->entry = *mentry;
             item->entry.mnt_fsname = strdup(mentry->mnt_fsname);
@@ -170,8 +151,7 @@
             goto out;
         }
         while ((mentry = getmntent(fp)) != NULL) {
-            if (!is_block_device(mentry->mnt_fsname) ||
-                !has_mount_option(mentry->mnt_opts, "ro")) {
+            if (!is_block_device(mentry->mnt_fsname) || !hasmntopt(mentry, "ro")) {
                 continue;
             }
             mntent_list* item = find_item(&rw_entries, mentry->mnt_fsname);