do not sleep if it is shutting down am: 375ac25773
am: 4460d0e554

Change-Id: I017220c17760d4264359a91395ff834bd01e1394
diff --git a/Android.mk b/Android.mk
index e92955f..9dba651 100644
--- a/Android.mk
+++ b/Android.mk
@@ -88,6 +88,8 @@
     vold_cflags += -DTARGET_USES_MKE2FS
     required_modules += mke2fs
   else
+    # Adoptable storage has fully moved to mke2fs, so we need both tools
+    required_modules += mke2fs
     required_modules += make_ext4fs
   endif
 endif
@@ -158,7 +160,10 @@
 LOCAL_TIDY := true
 LOCAL_TIDY_FLAGS := $(common_local_tidy_flags)
 LOCAL_TIDY_CHECKS := $(common_local_tidy_checks)
-LOCAL_SRC_FILES:= secdiscard.cpp
+LOCAL_SRC_FILES:= \
+    FileDeviceUtils.cpp \
+    secdiscard.cpp \
+
 LOCAL_MODULE:= secdiscard
 LOCAL_SHARED_LIBRARIES := libbase
 LOCAL_CFLAGS := $(vold_cflags)
diff --git a/AutoCloseFD.h b/AutoCloseFD.h
deleted file mode 100644
index 9b68469..0000000
--- a/AutoCloseFD.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <string>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <android-base/logging.h>
-
-// File descriptor which is automatically closed when this object is destroyed.
-// Cannot be copied, since that would cause double-closes.
-class AutoCloseFD {
-public:
-    AutoCloseFD(const char *path, int flags = O_RDONLY, int mode = 0):
-        fd{TEMP_FAILURE_RETRY(open(path, flags | O_CLOEXEC, mode))} {}
-    AutoCloseFD(const std::string &path, int flags = O_RDONLY, int mode = 0):
-        AutoCloseFD(path.c_str(), flags, mode) {}
-    ~AutoCloseFD() {
-        if (fd != -1) {
-            int preserve_errno = errno;
-            if (close(fd) == -1) {
-                PLOG(ERROR) << "close(2) failed";
-            };
-            errno = preserve_errno;
-        }
-    }
-    AutoCloseFD(const AutoCloseFD&) = delete;
-    AutoCloseFD& operator=(const AutoCloseFD&) = delete;
-    explicit operator bool() {return fd != -1;}
-    int get() const {return fd;}
-private:
-    const int fd;
-};
-
diff --git a/Disk.cpp b/Disk.cpp
index b424aba..9c22400 100644
--- a/Disk.cpp
+++ b/Disk.cpp
@@ -24,6 +24,7 @@
 #include "Ext4Crypt.h"
 
 #include <android-base/file.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/logging.h>
 #include <diskconfig/diskconfig.h>
@@ -446,7 +447,8 @@
 status_t Disk::partitionMixed(int8_t ratio) {
     int res;
 
-    if (e4crypt_is_native()) {
+    if (e4crypt_is_native()
+            && !android::base::GetBoolProperty("persist.sys.adoptable_fbe", false)) {
         LOG(ERROR) << "Private volumes not yet supported on FBE devices";
         return -EINVAL;
     }
@@ -469,9 +471,14 @@
     // We've had some success above, so generate both the private partition
     // GUID and encryption key and persist them.
     std::string partGuidRaw;
+    if (GenerateRandomUuid(partGuidRaw) != OK) {
+        LOG(ERROR) << "Failed to generate GUID";
+        return -EIO;
+    }
+
     std::string keyRaw;
-    if (ReadRandomBytes(16, partGuidRaw) || ReadRandomBytes(16, keyRaw)) {
-        LOG(ERROR) << "Failed to generate GUID or key";
+    if (ReadRandomBytes(16, keyRaw) != OK) {
+        LOG(ERROR) << "Failed to generate key";
         return -EIO;
     }
 
diff --git a/EmulatedVolume.cpp b/EmulatedVolume.cpp
index 44ad22a..df91904 100644
--- a/EmulatedVolume.cpp
+++ b/EmulatedVolume.cpp
@@ -103,6 +103,8 @@
         LOG(VERBOSE) << "Waiting for FUSE to spin up...";
         usleep(50000); // 50ms
     }
+    /* sdcardfs will have exited already. FUSE will still be running */
+    TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, WNOHANG));
 
     return OK;
 }
diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp
index c3e0cc3..f9d4cf8 100644
--- a/Ext4Crypt.cpp
+++ b/Ext4Crypt.cpp
@@ -30,6 +30,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <unistd.h>
 #include <limits.h>
 #include <selinux/android.h>
 #include <sys/mount.h>
@@ -54,6 +55,7 @@
 #include <android-base/stringprintf.h>
 
 using android::base::StringPrintf;
+using android::base::WriteStringToFile;
 using android::vold::kEmptyAuthentication;
 
 // NOTE: keep in sync with StorageManager
@@ -399,6 +401,15 @@
     return true;
 }
 
+static void drop_caches() {
+    // Clean any dirty pages (otherwise they won't be dropped).
+    sync();
+    // Drop inode and page caches.
+    if (!WriteStringToFile("3", "/proc/sys/vm/drop_caches")) {
+        PLOG(ERROR) << "Failed to drop caches during key eviction";
+    }
+}
+
 static bool evict_ce_key(userid_t user_id) {
    s_ce_keys.erase(user_id);
     bool success = true;
@@ -406,6 +417,7 @@
     // If we haven't loaded the CE key, no need to evict it.
     if (lookup_key_ref(s_ce_key_raw_refs, user_id, &raw_ref)) {
         success &= android::vold::evictKey(raw_ref);
+        drop_caches();
     }
     s_ce_key_raw_refs.erase(user_id);
     return success;
@@ -599,8 +611,7 @@
         if (!prepare_dir(misc_de_path, 01771, AID_SYSTEM, AID_MISC)) return false;
         if (!prepare_dir(user_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
 
-        // For now, FBE is only supported on internal storage
-        if (e4crypt_is_native() && volume_uuid == nullptr) {
+        if (e4crypt_is_native()) {
             std::string de_raw_ref;
             if (!lookup_key_ref(s_de_key_raw_refs, user_id, &de_raw_ref)) return false;
             if (!ensure_policy(de_raw_ref, system_de_path)) return false;
@@ -621,8 +632,7 @@
         if (!prepare_dir(media_ce_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW)) return false;
         if (!prepare_dir(user_ce_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
 
-        // For now, FBE is only supported on internal storage
-        if (e4crypt_is_native() && volume_uuid == nullptr) {
+        if (e4crypt_is_native()) {
             std::string ce_raw_ref;
             if (!lookup_key_ref(s_ce_key_raw_refs, user_id, &ce_raw_ref)) return false;
             if (!ensure_policy(ce_raw_ref, system_ce_path)) return false;
diff --git a/FileDeviceUtils.cpp b/FileDeviceUtils.cpp
new file mode 100644
index 0000000..bc9f4bd
--- /dev/null
+++ b/FileDeviceUtils.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "FileDeviceUtils.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <linux/fs.h>
+#include <linux/fiemap.h>
+#include <mntent.h>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+namespace {
+
+std::unique_ptr<struct fiemap> alloc_fiemap(uint32_t extent_count);
+
+}
+
+namespace android {
+namespace vold {
+
+// Given a file path, look for the corresponding block device in /proc/mount
+std::string BlockDeviceForPath(const std::string &path)
+{
+    std::unique_ptr<FILE, int(*)(FILE*)> mnts(setmntent("/proc/mounts", "re"), endmntent);
+    if (!mnts) {
+        PLOG(ERROR) << "Unable to open /proc/mounts";
+        return "";
+    }
+    std::string result;
+    size_t best_length = 0;
+    struct mntent *mnt; // getmntent returns a thread local, so it's safe.
+    while ((mnt = getmntent(mnts.get())) != nullptr) {
+        auto l = strlen(mnt->mnt_dir);
+        if (l > best_length &&
+            path.size() > l &&
+            path[l] == '/' &&
+            path.compare(0, l, mnt->mnt_dir) == 0) {
+                result = mnt->mnt_fsname;
+                best_length = l;
+        }
+    }
+    if (result.empty()) {
+        LOG(ERROR) <<"Didn't find a mountpoint to match path " << path;
+        return "";
+    }
+    LOG(DEBUG) << "For path " << path << " block device is " << result;
+    return result;
+}
+
+std::unique_ptr<struct fiemap> PathFiemap(const std::string &path, uint32_t extent_count)
+{
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(
+        path.c_str(), O_RDONLY | O_CLOEXEC, 0)));
+    if (fd == -1) {
+        if (errno == ENOENT) {
+            PLOG(DEBUG) << "Unable to open " << path;
+        } else {
+            PLOG(ERROR) << "Unable to open " << path;
+        }
+        return nullptr;
+    }
+    auto fiemap = alloc_fiemap(extent_count);
+    if (ioctl(fd.get(), FS_IOC_FIEMAP, fiemap.get()) != 0) {
+        PLOG(ERROR) << "Unable to FIEMAP " << path;
+        return nullptr;
+    }
+    auto mapped = fiemap->fm_mapped_extents;
+    if (mapped < 1 || mapped > extent_count) {
+        LOG(ERROR) << "Extent count not in bounds 1 <= " << mapped << " <= " << extent_count
+            << " in " << path;
+        return nullptr;
+    }
+    return fiemap;
+}
+
+}  // namespace vold
+}  // namespace android
+
+namespace {
+
+std::unique_ptr<struct fiemap> alloc_fiemap(uint32_t extent_count)
+{
+    size_t allocsize = offsetof(struct fiemap, fm_extents[extent_count]);
+    std::unique_ptr<struct fiemap> res(new (::operator new (allocsize)) struct fiemap);
+    memset(res.get(), 0, allocsize);
+    res->fm_start = 0;
+    res->fm_length = UINT64_MAX;
+    res->fm_flags = 0;
+    res->fm_extent_count = extent_count;
+    res->fm_mapped_extents = 0;
+    return res;
+}
+
+}
diff --git a/FileDeviceUtils.h b/FileDeviceUtils.h
new file mode 100644
index 0000000..4c1d49a
--- /dev/null
+++ b/FileDeviceUtils.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_VOLD_FILEDEVICEUTILS_H
+#define ANDROID_VOLD_FILEDEVICEUTILS_H
+
+#include <string>
+#include <linux/fiemap.h>
+
+namespace android {
+namespace vold {
+
+// Given a file path, look for the corresponding block device in /proc/mount
+std::string BlockDeviceForPath(const std::string &path);
+
+// Read the file's FIEMAP
+std::unique_ptr<struct fiemap> PathFiemap(const std::string &path, uint32_t extent_count);
+
+}  // namespace vold
+}  // namespace android
+
+#endif
diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp
index b707549..743e08c 100644
--- a/MetadataCrypt.cpp
+++ b/MetadataCrypt.cpp
@@ -29,10 +29,10 @@
 #include <linux/dm-ioctl.h>
 
 #include <android-base/logging.h>
+#include <android-base/unique_fd.h>
 #include <cutils/properties.h>
 #include <fs_mgr.h>
 
-#include "AutoCloseFD.h"
 #include "EncryptInplace.h"
 #include "KeyStorage.h"
 #include "KeyUtil.h"
@@ -105,8 +105,9 @@
 }
 
 static bool get_number_of_sectors(const std::string& real_blkdev, uint64_t *nr_sec) {
-    AutoCloseFD dev_fd(real_blkdev, O_RDONLY);
-    if (!dev_fd) {
+    android::base::unique_fd dev_fd(TEMP_FAILURE_RETRY(open(
+        real_blkdev.c_str(), O_RDONLY | O_CLOEXEC, 0)));
+    if (dev_fd == -1) {
         PLOG(ERROR) << "Unable to open " << real_blkdev << " to measure size";
         return false;
     }
@@ -143,8 +144,9 @@
 static bool create_crypto_blk_dev(const std::string& dm_name, uint64_t nr_sec,
                                   const std::string& target_type, const std::string& crypt_params,
                                   std::string* crypto_blkdev) {
-    AutoCloseFD dm_fd("/dev/device-mapper", O_RDWR);
-    if (!dm_fd) {
+    android::base::unique_fd dm_fd(TEMP_FAILURE_RETRY(open(
+        "/dev/device-mapper", O_RDWR | O_CLOEXEC, 0)));
+    if (dm_fd == -1) {
         PLOG(ERROR) << "Cannot open device-mapper";
         return false;
     }
diff --git a/MoveTask.cpp b/MoveTask.cpp
index ea64a1c..c565752 100644
--- a/MoveTask.cpp
+++ b/MoveTask.cpp
@@ -62,7 +62,8 @@
             StringPrintf("%d", progress).c_str(), false);
 }
 
-static status_t pushBackContents(const std::string& path, std::vector<std::string>& cmd) {
+static status_t pushBackContents(const std::string& path, std::vector<std::string>& cmd,
+        bool addWildcard) {
     DIR* dir = opendir(path.c_str());
     if (dir == NULL) {
         return -1;
@@ -73,7 +74,11 @@
         if ((!strcmp(ent->d_name, ".")) || (!strcmp(ent->d_name, ".."))) {
             continue;
         }
-        cmd.push_back(StringPrintf("%s/%s", path.c_str(), ent->d_name));
+        if (addWildcard) {
+            cmd.push_back(StringPrintf("%s/%s/*", path.c_str(), ent->d_name));
+        } else {
+            cmd.push_back(StringPrintf("%s/%s", path.c_str(), ent->d_name));
+        }
         found = true;
     }
     closedir(dir);
@@ -90,7 +95,7 @@
     cmd.push_back(kRmPath);
     cmd.push_back("-f"); /* force: remove without confirmation, no error if it doesn't exist */
     cmd.push_back("-R"); /* recursive: remove directory contents */
-    if (pushBackContents(path, cmd) != OK) {
+    if (pushBackContents(path, cmd, true) != OK) {
         LOG(WARNING) << "No contents in " << path;
         return OK;
     }
@@ -140,7 +145,7 @@
     cmd.push_back("-R"); /* recurse into subdirectories (DEST must be a directory) */
     cmd.push_back("-P"); /* Do not follow symlinks [default] */
     cmd.push_back("-d"); /* don't dereference symlinks */
-    if (pushBackContents(fromPath, cmd) != OK) {
+    if (pushBackContents(fromPath, cmd, false) != OK) {
         LOG(WARNING) << "No contents in " << fromPath;
         return OK;
     }
diff --git a/PublicVolume.cpp b/PublicVolume.cpp
index 119d92c..f976c4a 100644
--- a/PublicVolume.cpp
+++ b/PublicVolume.cpp
@@ -190,6 +190,8 @@
         LOG(VERBOSE) << "Waiting for FUSE to spin up...";
         usleep(50000); // 50ms
     }
+    /* sdcardfs will have exited already. FUSE will still be running */
+    TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, WNOHANG));
 
     return OK;
 }
diff --git a/Utils.cpp b/Utils.cpp
index c9d7d05..395a890 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -373,6 +373,17 @@
     }
 }
 
+status_t GenerateRandomUuid(std::string& out) {
+    status_t res = ReadRandomBytes(16, out);
+    if (res == OK) {
+        out[6] &= 0x0f;  /* clear version        */
+        out[6] |= 0x40;  /* set to version 4     */
+        out[8] &= 0x3f;  /* clear variant        */
+        out[8] |= 0x80;  /* set to IETF variant  */
+    }
+    return res;
+}
+
 status_t HexToStr(const std::string& hex, std::string& str) {
     str.clear();
     bool even = true;
diff --git a/Utils.h b/Utils.h
index 813ffac..7272fe1 100644
--- a/Utils.h
+++ b/Utils.h
@@ -78,6 +78,7 @@
 pid_t ForkExecvpAsync(const std::vector<std::string>& args);
 
 status_t ReadRandomBytes(size_t bytes, std::string& out);
+status_t GenerateRandomUuid(std::string& out);
 
 /* Converts hex string to raw bytes, ignoring [ :-] */
 status_t HexToStr(const std::string& hex, std::string& str);
diff --git a/cryptfs.cpp b/cryptfs.cpp
index 6319362..43c8177 100644
--- a/cryptfs.cpp
+++ b/cryptfs.cpp
@@ -1302,29 +1302,24 @@
     return rc;
 }
 
-static int prep_data_fs(void)
+static void prep_data_fs(void)
 {
-    int i;
-
     // NOTE: post_fs_data results in init calling back around to vold, so all
     // callers to this method must be async
 
     /* Do the prep of the /data filesystem */
     property_set("vold.post_fs_data_done", "0");
     property_set("vold.decrypt", "trigger_post_fs_data");
-    SLOGD("Just triggered post_fs_data\n");
+    SLOGD("Just triggered post_fs_data");
 
     /* Wait a max of 50 seconds, hopefully it takes much less */
-    if (!android::base::WaitForProperty("vold.post_fs_data_done",
+    while (!android::base::WaitForProperty("vold.post_fs_data_done",
                                         "1",
-                                        std::chrono::seconds(50))) {
-        /* Ugh, we failed to prep /data in time.  Bail. */
-        SLOGE("post_fs_data timed out!\n");
-        return -1;
-    } else {
-        SLOGD("post_fs_data done\n");
-        return 0;
+                                        std::chrono::seconds(15))) {
+        /* We timed out to prep /data in time.  Continue wait. */
+        SLOGE("waited 15s for vold.post_fs_data_done, still waiting...");
     }
+    SLOGD("post_fs_data done");
 }
 
 static void cryptfs_set_corrupt()
@@ -1475,9 +1470,7 @@
         }
 
         /* Create necessary paths on /data */
-        if (prep_data_fs()) {
-            return -1;
-        }
+        prep_data_fs();
         property_set("vold.decrypt", "trigger_load_persist_props");
 
         /* startup service classes main and late_start */
@@ -1945,15 +1938,17 @@
         SLOGI("Making empty filesystem with command %s %s %s %s %s %s\n",
               args[0], args[1], args[2], args[3], args[4], args[5]);
     } else if (type == F2FS_FS) {
-        args[0] = "/system/bin/mkfs.f2fs";
+        args[0] = "/system/bin/make_f2fs";
         args[1] = "-t";
         args[2] = "-d1";
-        args[3] = crypto_blkdev;
+        args[3] = "-f";
+        args[4] = "-O encrypt";
+        args[5] = crypto_blkdev;
         snprintf(size_str, sizeof(size_str), "%" PRId64, size);
-        args[4] = size_str;
-        num_args = 5;
-        SLOGI("Making empty filesystem with command %s %s %s %s %s\n",
-              args[0], args[1], args[2], args[3], args[4]);
+        args[6] = size_str;
+        num_args = 7;
+        SLOGI("Making empty filesystem with command %s %s %s %s %s %s %s\n",
+              args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
     } else {
         SLOGE("cryptfs_enable_wipe(): unknown filesystem type %d\n", type);
         return -1;
@@ -2216,9 +2211,7 @@
 
         /* restart the framework. */
         /* Create necessary paths on /data */
-        if (prep_data_fs()) {
-            goto error_shutting_down;
-        }
+        prep_data_fs();
 
         /* Ugh, shutting down the framework is not synchronous, so until it
          * can be fixed, this horrible hack will wait a moment for it all to
diff --git a/fs/Ext4.cpp b/fs/Ext4.cpp
index 0670bb5..0cf4f9e 100644
--- a/fs/Ext4.cpp
+++ b/fs/Ext4.cpp
@@ -38,6 +38,7 @@
 #define LOG_TAG "Vold"
 
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <cutils/log.h>
 #include <cutils/properties.h>
@@ -45,6 +46,7 @@
 #include <selinux/selinux.h>
 
 #include "Ext4.h"
+#include "Ext4Crypt.h"
 #include "Utils.h"
 #include "VoldUtil.h"
 
@@ -55,11 +57,7 @@
 namespace ext4 {
 
 static const char* kResizefsPath = "/system/bin/resize2fs";
-#ifdef TARGET_USES_MKE2FS
 static const char* kMkfsPath = "/system/bin/mke2fs";
-#else
-static const char* kMkfsPath = "/system/bin/make_ext4fs";
-#endif
 static const char* kFsckPath = "/system/bin/e2fsck";
 
 bool IsSupported() {
@@ -170,7 +168,6 @@
     std::vector<std::string> cmd;
     cmd.push_back(kMkfsPath);
 
-#ifdef TARGET_USES_MKE2FS
     cmd.push_back("-b");
     cmd.push_back("4096");
 
@@ -180,28 +177,22 @@
     cmd.push_back("-M");
     cmd.push_back(target);
 
-    cmd.push_back("-O");
-    cmd.push_back("^has_journal");
-
-    cmd.push_back(source);
-
-    if (numSectors)
-        cmd.push_back(StringPrintf("%lu", numSectors * (4096 / 512)));
-#else
-    cmd.push_back("-J");
-
-    cmd.push_back("-a");
-    cmd.push_back(target);
-
-    if (numSectors) {
-        cmd.push_back("-l");
-        cmd.push_back(StringPrintf("%lu", numSectors * 512));
+    std::string options("has_journal");
+    if (android::base::GetBoolProperty("vold.has_quota", false)) {
+        options += ",quota";
+    }
+    if (e4crypt_is_native()) {
+        options += ",encrypt";
     }
 
-    // Always generate a real UUID
-    cmd.push_back("-u");
+    cmd.push_back("-O");
+    cmd.push_back(options);
+
     cmd.push_back(source);
-#endif
+
+    if (numSectors) {
+        cmd.push_back(StringPrintf("%lu", numSectors * (4096 / 512)));
+    }
 
     return ForkExecvp(cmd);
 }
diff --git a/main.cpp b/main.cpp
index 4657377..30c839e 100644
--- a/main.cpp
+++ b/main.cpp
@@ -39,7 +39,7 @@
 #include <dirent.h>
 #include <fs_mgr.h>
 
-static int process_config(VolumeManager *vm, bool* has_adoptable);
+static int process_config(VolumeManager *vm, bool* has_adoptable, bool* has_quota);
 static void coldboot(const char *path);
 static void parse_args(int argc, char** argv);
 
@@ -107,8 +107,9 @@
     }
 
     bool has_adoptable;
+    bool has_quota;
 
-    if (process_config(vm, &has_adoptable)) {
+    if (process_config(vm, &has_adoptable, &has_quota)) {
         PLOG(ERROR) << "Error reading configuration... continuing anyways";
     }
 
@@ -133,6 +134,7 @@
     // This call should go after listeners are started to avoid
     // a deadlock between vold and init (see b/34278978 for details)
     property_set("vold.has_adoptable", has_adoptable ? "1" : "0");
+    property_set("vold.has_quota", has_quota ? "1" : "0");
 
     // Do coldboot here so it won't block booting,
     // also the cold boot is needed in case we have flash drive
@@ -214,7 +216,7 @@
     }
 }
 
-static int process_config(VolumeManager *vm, bool* has_adoptable) {
+static int process_config(VolumeManager *vm, bool* has_adoptable, bool* has_quota) {
     fstab = fs_mgr_read_fstab_default();
     if (!fstab) {
         PLOG(ERROR) << "Failed to open default fstab";
@@ -223,7 +225,12 @@
 
     /* Loop through entries looking for ones that vold manages */
     *has_adoptable = false;
+    *has_quota = false;
     for (int i = 0; i < fstab->num_entries; i++) {
+        if (fs_mgr_is_quota(&fstab->recs[i])) {
+            *has_quota = true;
+        }
+
         if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
             if (fs_mgr_is_nonremovable(&fstab->recs[i])) {
                 LOG(WARNING) << "nonremovable no longer supported; ignoring volume";
diff --git a/secdiscard.cpp b/secdiscard.cpp
index fe51990..f9532ea 100644
--- a/secdiscard.cpp
+++ b/secdiscard.cpp
@@ -29,8 +29,9 @@
 #include <mntent.h>
 
 #include <android-base/logging.h>
+#include <android-base/unique_fd.h>
 
-#include <AutoCloseFD.h>
+#include "FileDeviceUtils.h"
 
 namespace {
 
@@ -44,10 +45,7 @@
 bool read_command_line(int argc, const char * const argv[], Options &options);
 void usage(const char *progname);
 bool secdiscard_path(const std::string &path);
-std::unique_ptr<struct fiemap> path_fiemap(const std::string &path, uint32_t extent_count);
 bool check_fiemap(const struct fiemap &fiemap, const std::string &path);
-std::unique_ptr<struct fiemap> alloc_fiemap(uint32_t extent_count);
-std::string block_device_for_path(const std::string &path);
 bool overwrite_with_zeros(int fd, off64_t start, off64_t length);
 
 }
@@ -99,16 +97,17 @@
 
 // BLKSECDISCARD all content in "path", if it's small enough.
 bool secdiscard_path(const std::string &path) {
-    auto fiemap = path_fiemap(path, max_extents);
+    auto fiemap = android::vold::PathFiemap(path, max_extents);
     if (!fiemap || !check_fiemap(*fiemap, path)) {
         return false;
     }
-    auto block_device = block_device_for_path(path);
+    auto block_device = android::vold::BlockDeviceForPath(path);
     if (block_device.empty()) {
         return false;
     }
-    AutoCloseFD fs_fd(block_device, O_RDWR | O_LARGEFILE);
-    if (!fs_fd) {
+    android::base::unique_fd fs_fd(TEMP_FAILURE_RETRY(open(
+        block_device.c_str(), O_RDWR | O_LARGEFILE | O_CLOEXEC, 0)));
+    if (fs_fd == -1) {
         PLOG(ERROR) << "Failed to open device " << block_device;
         return false;
     }
@@ -125,32 +124,6 @@
     return true;
 }
 
-// Read the file's FIEMAP
-std::unique_ptr<struct fiemap> path_fiemap(const std::string &path, uint32_t extent_count)
-{
-    AutoCloseFD fd(path);
-    if (!fd) {
-        if (errno == ENOENT) {
-            PLOG(DEBUG) << "Unable to open " << path;
-        } else {
-            PLOG(ERROR) << "Unable to open " << path;
-        }
-        return nullptr;
-    }
-    auto fiemap = alloc_fiemap(extent_count);
-    if (ioctl(fd.get(), FS_IOC_FIEMAP, fiemap.get()) != 0) {
-        PLOG(ERROR) << "Unable to FIEMAP " << path;
-        return nullptr;
-    }
-    auto mapped = fiemap->fm_mapped_extents;
-    if (mapped < 1 || mapped > extent_count) {
-        LOG(ERROR) << "Extent count not in bounds 1 <= " << mapped << " <= " << extent_count
-            << " in " << path;
-        return nullptr;
-    }
-    return fiemap;
-}
-
 // Ensure that the FIEMAP covers the file and is OK to discard
 bool check_fiemap(const struct fiemap &fiemap, const std::string &path) {
     auto mapped = fiemap.fm_mapped_extents;
@@ -168,48 +141,6 @@
     return true;
 }
 
-std::unique_ptr<struct fiemap> alloc_fiemap(uint32_t extent_count)
-{
-    size_t allocsize = offsetof(struct fiemap, fm_extents[extent_count]);
-    std::unique_ptr<struct fiemap> res(new (::operator new (allocsize)) struct fiemap);
-    memset(res.get(), 0, allocsize);
-    res->fm_start = 0;
-    res->fm_length = UINT64_MAX;
-    res->fm_flags = 0;
-    res->fm_extent_count = extent_count;
-    res->fm_mapped_extents = 0;
-    return res;
-}
-
-// Given a file path, look for the corresponding block device in /proc/mount
-std::string block_device_for_path(const std::string &path)
-{
-    std::unique_ptr<FILE, int(*)(FILE*)> mnts(setmntent("/proc/mounts", "re"), endmntent);
-    if (!mnts) {
-        PLOG(ERROR) << "Unable to open /proc/mounts";
-        return "";
-    }
-    std::string result;
-    size_t best_length = 0;
-    struct mntent *mnt; // getmntent returns a thread local, so it's safe.
-    while ((mnt = getmntent(mnts.get())) != nullptr) {
-        auto l = strlen(mnt->mnt_dir);
-        if (l > best_length &&
-            path.size() > l &&
-            path[l] == '/' &&
-            path.compare(0, l, mnt->mnt_dir) == 0) {
-                result = mnt->mnt_fsname;
-                best_length = l;
-        }
-    }
-    if (result.empty()) {
-        LOG(ERROR) <<"Didn't find a mountpoint to match path " << path;
-        return "";
-    }
-    LOG(DEBUG) << "For path " << path << " block device is " << result;
-    return result;
-}
-
 bool overwrite_with_zeros(int fd, off64_t start, off64_t length) {
     if (lseek64(fd, start, SEEK_SET) != start) {
         PLOG(ERROR) << "Seek failed for zero overwrite";