Merge topic 'f2fs'

* changes:
  fsmgr: allow for a multiple fs-types for a mount point.
  F2FS support for fastboot format and fsmgr
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 73794a0..8fc1f0b 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -17,7 +17,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
-  $(LOCAL_PATH)/../../extras/ext4_utils
+  $(LOCAL_PATH)/../../extras/ext4_utils \
+  $(LOCAL_PATH)/../../extras/f2fs_utils
 LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c fs.c
 LOCAL_MODULE := fastboot
 LOCAL_MODULE_TAGS := debug
@@ -50,14 +51,20 @@
   LOCAL_C_INCLUDES += development/host/windows/usb/api
 endif
 
+# The following libf2fs_* are from system/extras/f2fs_utils,
+# and do not use code in external/f2fs-tools.
 LOCAL_STATIC_LIBRARIES := \
     $(EXTRA_STATIC_LIBS) \
     libzipfile \
     libunz \
     libext4_utils_host \
+    libf2fs_utils_host \
+    libf2fs_dlutils_host \
     libsparse_host \
     libz
-
+# libf2fs_dlutils_host will dlopen("libf2fs_fmt_host_dyn")
+LOCAL_LDLIBS := -ldl
+LOCAL_SHARED_LIBRARIES := libf2fs_fmt_host_dyn
 ifneq ($(HOST_OS),windows)
 LOCAL_STATIC_LIBRARIES += libselinux
 endif # HOST_OS != windows
diff --git a/fastboot/fs.c b/fastboot/fs.c
index cd4b880..11e391b 100644
--- a/fastboot/fs.c
+++ b/fastboot/fs.c
@@ -1,5 +1,6 @@
 #include "fastboot.h"
 #include "make_ext4fs.h"
+#include "make_f2fs.h"
 #include "fs.h"
 
 #include <errno.h>
@@ -28,15 +29,20 @@
     return 0;
 }
 
+int generate_f2fs_image(int fd, long long partSize)
+{
+    make_f2fs_sparse_fd(fd, partSize, NULL, NULL);
+    return 0;
+}
+
 static const struct fs_generator {
 
     char *fs_type;  //must match what fastboot reports for partition type
     int (*generate)(int fd, long long partSize); //returns 0 or error value
 
 } generators[] = {
-
-    { "ext4", generate_ext4_image}
-
+    { "ext4", generate_ext4_image},
+    { "f2fs", generate_f2fs_image},
 };
 
 const struct fs_generator* fs_get_generator(const char *fs_type)
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index ee3cbf9..798007d 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -46,6 +46,7 @@
 #define KEY_IN_FOOTER  "footer"
 
 #define E2FSCK_BIN      "/system/bin/e2fsck"
+#define F2FS_FSCK_BIN  "/system/bin/fsck.f2fs"
 #define MKSWAP_BIN      "/system/bin/mkswap"
 
 #define FSCK_LOG_FILE   "/dev/fscklogs/log"
@@ -135,6 +136,20 @@
                 ERROR("Failed trying to run %s\n", E2FSCK_BIN);
             }
         }
+    } else if (!strcmp(fs_type, "f2fs")) {
+            char *f2fs_fsck_argv[] = {
+                    F2FS_FSCK_BIN,
+                    blk_device
+            };
+        INFO("Running %s on %s\n", F2FS_FSCK_BIN, blk_device);
+
+        ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv,
+                                      &status, true, LOG_KLOG | LOG_FILE,
+                                      true, FSCK_LOG_FILE);
+        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", F2FS_FSCK_BIN);
+        }
     }
 
     return;
@@ -175,12 +190,12 @@
  * sets the underlying block device to read-only if the mount is read-only.
  * See "man 2 mount" for return values.
  */
-static int __mount(const char *source, const char *target,
-                   const char *filesystemtype, unsigned long mountflags,
-                   const void *data)
+static int __mount(const char *source, const char *target, const struct fstab_rec *rec)
 {
-    int ret = mount(source, target, filesystemtype, mountflags, data);
+    unsigned long mountflags = rec->flags;
+    int ret;
 
+    ret = mount(source, target, rec->fs_type, mountflags, rec->fs_options);
     if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
         fs_set_blk_ro(source);
     }
@@ -217,13 +232,18 @@
     return strcmp(value, "1") ? 0 : 1;
 }
 
+/* When multiple fstab records share the same mount_point, it will
+ * try to mount each one in turn, and ignore any duplicates after a
+ * first successful mount.
+ */
 int fs_mgr_mount_all(struct fstab *fstab)
 {
-    int i = 0;
+    int i = 0, j = 0;
     int encryptable = 0;
     int error_count = 0;
     int mret;
     int mount_errno;
+    const char *last_ok_mount_point = NULL;
 
     if (!fstab) {
         return -1;
@@ -259,10 +279,26 @@
             }
         }
 
-        mret = __mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
-                       fstab->recs[i].fs_type, fstab->recs[i].flags,
-                       fstab->recs[i].fs_options);
-
+        /*
+         * Don't try to mount/encrypt the same mount point again.
+         * Deal with alternate entries for the same point which are required to be all following
+         * each other.
+         */
+        if (last_ok_mount_point && !strcmp(last_ok_mount_point, fstab->recs[i].mount_point)) {
+            continue;
+        }
+        /* Hunt down an fstab entry for the same mount point that might succeed */
+        for (j = i, mret = -1;
+             /* We required that fstab entries for the same mountpoint be consecutive */
+             mret && j < fstab->num_entries && !strcmp(fstab->recs[i].mount_point, fstab->recs[j].mount_point);
+             j++) {
+                mret = __mount(fstab->recs[j].blk_device, fstab->recs[j].mount_point, &fstab->recs[j]);
+        }
+        /* Did one of the same mount points mount? If so pick it. */
+        if (!mret) {
+            i = j;
+            last_ok_mount_point = fstab->recs[i].mount_point;
+        }
         if (!mret) {
             /* If this is encryptable, need to trigger encryption */
             if ((fstab->recs[i].fs_mgr_flags & MF_FORCECRYPT)) {
@@ -279,7 +315,6 @@
                     continue;
                 }
             }
-
             /* Success!  Go get the next one */
             continue;
         }
@@ -293,10 +328,7 @@
             /* Need to mount a tmpfs at this mountpoint for now, and set
              * properties that vold will query later for decrypting
              */
-            if (mount("tmpfs", fstab->recs[i].mount_point, "tmpfs",
-                      MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS) < 0) {
-                ERROR("Cannot mount tmpfs filesystem for encryptable fs at %s error: %s\n",
-                       fstab->recs[i].mount_point, strerror(errno));
+            if (fs_mgr_do_tmpfs_mount(fstab->recs[i].mount_point) < 0) {
                 ++error_count;
                 continue;
             }
@@ -320,12 +352,16 @@
 
 /* If tmp_mount_point is non-null, mount the filesystem there.  This is for the
  * tmp mount we do to check the user password
+ * If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
+ * in turn, and stop on 1st success, or no more match.
  */
 int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
                     char *tmp_mount_point)
 {
     int i = 0;
     int ret = -1;
+    int mount_errors = 0;
+    int first_mount_errno = 0;
     char *m;
 
     if (!fstab) {
@@ -371,19 +407,23 @@
         } else {
             m = fstab->recs[i].mount_point;
         }
-        if (__mount(n_blk_device, m, fstab->recs[i].fs_type,
-                    fstab->recs[i].flags, fstab->recs[i].fs_options)) {
-            ERROR("Cannot mount filesystem on %s at %s options: %s error: %s\n",
-                n_blk_device, m, fstab->recs[i].fs_options, strerror(errno));
-            goto out;
+        if (__mount(n_blk_device, m, &fstab->recs[i])) {
+            if (!first_mount_errno) first_mount_errno = errno;
+            mount_errors++;
+            continue;
         } else {
             ret = 0;
             goto out;
         }
     }
-
-    /* We didn't find a match, say so and return an error */
-    ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
+    if (mount_errors) {
+        ERROR("Cannot mount filesystem on %s at %s. error: %s\n",
+            n_blk_device, m, strerror(first_mount_errno));
+        ret = -1;
+    } else {
+        /* We didn't find a match, say so and return an error */
+        ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
+    }
 
 out:
     return ret;
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 6c21425..3f84179 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -367,25 +367,47 @@
      return 0;
 }
 
-struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
+/*
+ * Returns the 1st matching fstab_rec that follows the start_rec.
+ * start_rec is the result of a previous search or NULL.
+ */
+struct fstab_rec *fs_mgr_get_entry_for_mount_point_after(struct fstab_rec *start_rec, struct fstab *fstab, const char *path)
 {
     int i;
-
     if (!fstab) {
         return NULL;
     }
 
-    for (i = 0; i < fstab->num_entries; i++) {
+    if (start_rec) {
+        for (i = 0; i < fstab->num_entries; i++) {
+            if (&fstab->recs[i] == start_rec) {
+                i++;
+                break;
+            }
+        }
+    } else {
+        i = 0;
+    }
+    for (; i < fstab->num_entries; i++) {
         int len = strlen(fstab->recs[i].mount_point);
         if (strncmp(path, fstab->recs[i].mount_point, len) == 0 &&
             (path[len] == '\0' || path[len] == '/')) {
             return &fstab->recs[i];
         }
     }
-
     return NULL;
 }
 
+/*
+ * Returns the 1st matching mount point.
+ * There might be more. To look for others, use fs_mgr_get_entry_for_mount_point_after()
+ * and give the fstab_rec from the previous search.
+ */
+struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
+{
+    return fs_mgr_get_entry_for_mount_point_after(NULL, fstab, path);
+}
+
 int fs_mgr_is_voldmanaged(struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & MF_VOLDMANAGED;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 835cf64..b8bb5aa 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -24,6 +24,11 @@
 extern "C" {
 #endif
 
+/*
+ * The entries must be kept in the same order as they were seen in the fstab.
+ * Unless explicitly requested, a lookup on mount point should always
+ * return the 1st one.
+ */
 struct fstab {
     int num_entries;
     struct fstab_rec *recs;