Merge "Vold: Add the fstrim subsystem to vold" into jb-mr2-dev
diff --git a/Android.mk b/Android.mk
index d13fa8b..669d9af 100644
--- a/Android.mk
+++ b/Android.mk
@@ -15,6 +15,7 @@
 	Devmapper.cpp \
 	ResponseCode.cpp \
 	Xwarp.cpp \
+	fstrim.c \
 	cryptfs.c
 
 common_c_includes := \
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 2986cac..f8baff5 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -38,6 +38,7 @@
 #include "Loop.h"
 #include "Devmapper.h"
 #include "cryptfs.h"
+#include "fstrim.h"
 
 #define DUMP_ARGS 0
 
@@ -50,6 +51,7 @@
     registerCmd(new StorageCmd());
     registerCmd(new XwarpCmd());
     registerCmd(new CryptfsCmd());
+    registerCmd(new FstrimCmd());
 }
 
 void CommandListener::dumpArgs(int argc, char **argv, int argObscure) {
@@ -609,3 +611,41 @@
 
     return 0;
 }
+
+CommandListener::FstrimCmd::FstrimCmd() :
+                 VoldCommand("fstrim") {
+}
+int CommandListener::FstrimCmd::runCommand(SocketClient *cli,
+                                                      int argc, char **argv) {
+    if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
+        cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run fstrim commands", false);
+        return 0;
+    }
+
+    if (argc < 2) {
+        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
+        return 0;
+    }
+
+    int rc = 0;
+
+    if (!strcmp(argv[1], "dotrim")) {
+        if (argc != 2) {
+            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: fstrim dotrim", false);
+            return 0;
+        }
+        dumpArgs(argc, argv, -1);
+        rc = fstrim_filesystems();
+    } else {
+        dumpArgs(argc, argv, -1);
+        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown fstrim cmd", false);
+    }
+
+    // Always report that the command succeeded and return the error code.
+    // The caller will check the return value to see what the error was.
+    char msg[255];
+    snprintf(msg, sizeof(msg), "%d", rc);
+    cli->sendMsg(ResponseCode::CommandOkay, msg, false);
+
+    return 0;
+}
diff --git a/CommandListener.h b/CommandListener.h
index 4ef4a0c..8cc5b09 100644
--- a/CommandListener.h
+++ b/CommandListener.h
@@ -78,6 +78,13 @@
         virtual ~CryptfsCmd() {}
         int runCommand(SocketClient *c, int argc, char ** argv);
     };
+
+    class FstrimCmd : public VoldCommand {
+    public:
+        FstrimCmd();
+        virtual ~FstrimCmd() {}
+        int runCommand(SocketClient *c, int argc, char ** argv);
+    };
 };
 
 #endif
diff --git a/fstrim.c b/fstrim.c
new file mode 100644
index 0000000..156446a
--- /dev/null
+++ b/fstrim.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2013 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <limits.h>
+#include <linux/fs.h>
+#include <fs_mgr.h>
+#define LOG_TAG "fstrim"
+#include "cutils/log.h"
+
+int fstrim_filesystems(void)
+{
+    int i;
+    int fd;
+    int ret = 0;
+    struct fstrim_range range = { 0 };
+    struct stat sb;
+    extern struct fstab *fstab;
+
+    SLOGI("Starting fstrim work...\n");
+
+    for (i = 0; i < fstab->num_entries; i++) {
+        /* Skip raw partitions */
+        if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
+            !strcmp(fstab->recs[i].fs_type, "mtd")) {
+            continue;
+        }
+        /* Skip read-only filesystems */
+        if (fstab->recs[i].flags & MS_RDONLY) {
+            continue;
+        }
+        if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
+            continue; /* Should we trim fat32 filesystems? */
+        }
+
+        if (stat(fstab->recs[i].mount_point, &sb) == -1) {
+            SLOGE("Cannot stat mount point %s\n", fstab->recs[i].mount_point);
+            ret = -1;
+            continue;
+        }
+        if (!S_ISDIR(sb.st_mode)) {
+            SLOGE("%s is not a directory\n", fstab->recs[i].mount_point);
+            ret = -1;
+            continue;
+        }
+
+        fd = open(fstab->recs[i].mount_point, O_RDONLY);
+        if (fd < 0) {
+            SLOGE("Cannot open %s for FITRIM\n", fstab->recs[i].mount_point);
+            ret = -1;
+            continue;
+        }
+
+        memset(&range, 0, sizeof(range));
+        range.len = ULLONG_MAX;
+        SLOGI("Invoking FITRIM ioctl on %s", fstab->recs[i].mount_point);
+        if (ioctl(fd, FITRIM, &range)) {
+            SLOGE("FITRIM ioctl failed on %s", fstab->recs[i].mount_point);
+            ret = -1;
+        }
+        SLOGI("Trimmed %llu bytes on %s\n", range.len, fstab->recs[i].mount_point);
+        close(fd);
+    }
+    SLOGI("Finished fstrim work.\n");
+
+    return ret;
+}
+
diff --git a/fstrim.h b/fstrim.h
new file mode 100644
index 0000000..e46e804
--- /dev/null
+++ b/fstrim.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    int fstrim_filesystems(void);
+#ifdef __cplusplus
+}
+#endif
+