fstrim: prep for supporting a deep trim ioctl

This adds an "fstrim dodtrim" command which will attempt to use
the FIDTRIM ioctl() if FIDTRIM is defined in the uapi/linux/fs.h.
If not, it will fail with EINVAL.

If no FIDTRIM is defined, it does not affect the "fstrim dotrim".

Change-Id: Icbfd621abb592b170db06f749e5eedfd1175f723
diff --git a/fstrim.c b/fstrim.c
index 9a6637d..7f83ff7 100644
--- a/fstrim.c
+++ b/fstrim.c
@@ -52,7 +52,7 @@
     return time_ms;
 }
 
-static void *do_fstrim_filesystems(void *ignored UNUSED)
+static void *do_fstrim_filesystems(void *thread_arg)
 {
     int i;
     int fd;
@@ -60,6 +60,7 @@
     struct fstrim_range range = { 0 };
     struct stat sb;
     extern struct fstab *fstab;
+    int deep_trim = !!thread_arg;
 
     SLOGI("Starting fstrim work...\n");
 
@@ -100,9 +101,19 @@
 
         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);
+        SLOGI("Invoking %s ioctl on %s", deep_trim ? "FIDTRIM" : "FITRIM", fstab->recs[i].mount_point);
+#if defined(FIDTRIM)
+        ret = ioctl(fd, deep_trim ? FIDTRIM : FITRIM, &range);
+#else
+        if (deep_trim) {
+            ret = -1;
+            errno = EINVAL;
+        } else {
+            ret = ioctl(fd, FITRIM, &range);
+        }
+#endif
+        if (ret) {
+            SLOGE("FIDTRIM ioctl failed on %s (error %d/%s)", fstab->recs[i].mount_point, errno, strerror(errno));
             ret = -1;
         } else {
             SLOGI("Trimmed %llu bytes on %s\n", range.len, fstab->recs[i].mount_point);
@@ -121,7 +132,7 @@
     return (void *)(uintptr_t)ret;
 }
 
-int fstrim_filesystems(void)
+int fstrim_filesystems(int deep_trim)
 {
     pthread_t t;
     int ret;
@@ -142,7 +153,7 @@
      * the kernel will "do the right thing" and split the work between
      * the two ioctls invoked in separate threads.
      */
-    ret = pthread_create(&t, NULL, do_fstrim_filesystems, NULL);
+    ret = pthread_create(&t, NULL, do_fstrim_filesystems, (void *)(intptr_t)deep_trim);
     if (ret) {
         SLOGE("Cannot create thread to do fstrim");
         return ret;