Merge "adb: Retry io in case of interrupt"
diff --git a/daemon/remount_service.cpp b/daemon/remount_service.cpp
index 7876368..eb46903 100644
--- a/daemon/remount_service.cpp
+++ b/daemon/remount_service.cpp
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <mntent.h>
+#include <spawn.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -106,6 +107,41 @@
     return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0;
 }
 
+static bool can_unshare_blocks(int fd, const char* dev) {
+    const char* E2FSCK_BIN = "/system/bin/e2fsck";
+    if (access(E2FSCK_BIN, X_OK)) {
+        WriteFdFmt(fd, "e2fsck is not available, cannot undo deduplication on %s\n", dev);
+        return false;
+    }
+
+    pid_t child;
+    char* env[] = {nullptr};
+    const char* argv[] = {E2FSCK_BIN, "-n", "-E", "unshare_blocks", dev, nullptr};
+    if (posix_spawn(&child, E2FSCK_BIN, nullptr, nullptr, const_cast<char**>(argv), env)) {
+        WriteFdFmt(fd, "failed to e2fsck to check deduplication: %s\n", strerror(errno));
+        return false;
+    }
+    int status = 0;
+    int ret = TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
+    if (ret < 0) {
+        WriteFdFmt(fd, "failed to get e2fsck status: %s\n", strerror(errno));
+        return false;
+    }
+    if (!WIFEXITED(status)) {
+        WriteFdFmt(fd, "e2fsck exited abnormally with status %d\n", status);
+        return false;
+    }
+    int rc = WEXITSTATUS(status);
+    if (rc != 0) {
+        WriteFdFmt(fd,
+                   "%s is deduplicated, and an e2fsck check failed. It might not "
+                   "have enough free-space to be remounted as writable.\n",
+                   dev);
+        return false;
+    }
+    return true;
+}
+
 static bool remount_partition(int fd, const char* dir, std::vector<std::string>& dedup) {
     if (!directory_exists(dir)) {
         return true;
@@ -133,6 +169,9 @@
     }
     if (mount(dev.c_str(), dir, "none", MS_REMOUNT, nullptr) == -1) {
         if (errno == EROFS && fs_has_shared_blocks(dev.c_str())) {
+            if (!can_unshare_blocks(fd, dev.c_str())) {
+                return false;
+            }
             // We return true so remount_service() can detect that the only
             // failure was deduplicated filesystems.
             dedup.push_back(dev);
diff --git a/daemon/usb.cpp b/daemon/usb.cpp
index 263303f..c724b11 100644
--- a/daemon/usb.cpp
+++ b/daemon/usb.cpp
@@ -234,6 +234,10 @@
     for (unsigned i = 0; i < USB_FFS_NUM_BUFS; i++) {
         aiob->iocbs[i] = &aiob->iocb[i];
     }
+    memset(&aiob->ctx, 0, sizeof(aiob->ctx));
+    if (io_setup(USB_FFS_NUM_BUFS, &aiob->ctx)) {
+        D("[ aio: got error on io_setup (%d) ]", errno);
+    }
 }
 
 static int getMaxPacketSize(int ffs_fd) {
@@ -312,13 +316,6 @@
         goto err;
     }
 
-    memset(&h->read_aiob.ctx, 0, sizeof(h->read_aiob.ctx));
-    memset(&h->write_aiob.ctx, 0, sizeof(h->write_aiob.ctx));
-    if (io_setup(USB_FFS_NUM_BUFS, &h->read_aiob.ctx) ||
-        io_setup(USB_FFS_NUM_BUFS, &h->write_aiob.ctx)) {
-        D("[ aio: got error on io_setup (%d) ]", errno);
-    }
-
     h->read_aiob.fd = h->bulk_out;
     h->write_aiob.fd = h->bulk_in;
     return true;
@@ -500,8 +497,6 @@
     h->kicked = false;
     adb_close(h->bulk_out);
     adb_close(h->bulk_in);
-    io_destroy(h->read_aiob.ctx);
-    io_destroy(h->write_aiob.ctx);
 
     // Notify usb_adb_open_thread to open a new connection.
     h->lock.lock();