1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <sys/types.h> 18 #include <sys/stat.h> 19 #include <fcntl.h> 20 #include <unistd.h> 21 #include <sys/ioctl.h> 22 #include <string.h> 23 #include <limits.h> 24 #include <linux/fs.h> 25 #include <time.h> 26 #include <fs_mgr.h> 27 #include <pthread.h> 28 #define LOG_TAG "fstrim" 29 #include "cutils/log.h" 30 #include "hardware_legacy/power.h" 31 32 /* These numbers must match what the MountService specified in 33 * frameworks/base/services/java/com/android/server/EventLogTags.logtags 34 */ 35 #define LOG_FSTRIM_START 2755 36 #define LOG_FSTRIM_FINISH 2756 37 38 #define FSTRIM_WAKELOCK "dofstrim" 39 40 #define UNUSED __attribute__((unused)) 41 42 /* From a would-be kernel header */ 43 #define FIDTRIM _IOWR('f', 128, struct fstrim_range) /* Deep discard trim */ 44 45 static unsigned long long get_boot_time_ms(void) 46 { 47 struct timespec t; 48 unsigned long long time_ms; 49 50 t.tv_sec = 0; 51 t.tv_nsec = 0; 52 clock_gettime(CLOCK_BOOTTIME, &t); 53 time_ms = (t.tv_sec * 1000LL) + (t.tv_nsec / 1000000); 54 55 return time_ms; 56 } 57 58 static void *do_fstrim_filesystems(void *thread_arg) 59 { 60 int i; 61 int fd; 62 int ret = 0; 63 struct fstrim_range range = { 0 }; 64 struct stat sb; 65 extern struct fstab *fstab; 66 int deep_trim = !!thread_arg; 67 68 SLOGI("Starting fstrim work...\n"); 69 70 /* Log the start time in the event log */ 71 LOG_EVENT_LONG(LOG_FSTRIM_START, get_boot_time_ms()); 72 73 for (i = 0; i < fstab->num_entries; i++) { 74 /* Skip raw partitions */ 75 if (!strcmp(fstab->recs[i].fs_type, "emmc") || 76 !strcmp(fstab->recs[i].fs_type, "mtd")) { 77 continue; 78 } 79 /* Skip read-only filesystems */ 80 if (fstab->recs[i].flags & MS_RDONLY) { 81 continue; 82 } 83 if (fs_mgr_is_voldmanaged(&fstab->recs[i])) { 84 continue; /* Should we trim fat32 filesystems? */ 85 } 86 87 if (stat(fstab->recs[i].mount_point, &sb) == -1) { 88 SLOGE("Cannot stat mount point %s\n", fstab->recs[i].mount_point); 89 ret = -1; 90 continue; 91 } 92 if (!S_ISDIR(sb.st_mode)) { 93 SLOGE("%s is not a directory\n", fstab->recs[i].mount_point); 94 ret = -1; 95 continue; 96 } 97 98 fd = open(fstab->recs[i].mount_point, O_RDONLY); 99 if (fd < 0) { 100 SLOGE("Cannot open %s for FITRIM\n", fstab->recs[i].mount_point); 101 ret = -1; 102 continue; 103 } 104 105 memset(&range, 0, sizeof(range)); 106 range.len = ULLONG_MAX; 107 SLOGI("Invoking %s ioctl on %s", deep_trim ? "FIDTRIM" : "FITRIM", fstab->recs[i].mount_point); 108 109 ret = ioctl(fd, deep_trim ? FIDTRIM : FITRIM, &range); 110 if (ret) { 111 SLOGE("%s ioctl failed on %s (error %d/%s)", deep_trim ? "FIDTRIM" : "FITRIM", fstab->recs[i].mount_point, errno, strerror(errno)); 112 ret = -1; 113 } else { 114 SLOGI("Trimmed %llu bytes on %s\n", range.len, fstab->recs[i].mount_point); 115 } 116 close(fd); 117 } 118 119 /* Log the finish time in the event log */ 120 LOG_EVENT_LONG(LOG_FSTRIM_FINISH, get_boot_time_ms()); 121 122 SLOGI("Finished fstrim work.\n"); 123 124 /* Release the wakelock that let us work */ 125 release_wake_lock(FSTRIM_WAKELOCK); 126 127 return (void *)(uintptr_t)ret; 128 } 129 130 int fstrim_filesystems(int deep_trim) 131 { 132 pthread_t t; 133 int ret; 134 135 /* Get a wakelock as this may take a while, and we don't want the 136 * device to sleep on us. 137 */ 138 acquire_wake_lock(PARTIAL_WAKE_LOCK, FSTRIM_WAKELOCK); 139 140 /* Depending on the emmc chip and size, this can take upwards 141 * of a few minutes. If done in the same thread as the caller 142 * of this function, that would block vold from accepting any 143 * commands until the trim is finished. So start another thread 144 * to do the work, and return immediately. 145 * 146 * This function should not be called more than once per day, but 147 * even if it is called a second time before the first one finishes, 148 * the kernel will "do the right thing" and split the work between 149 * the two ioctls invoked in separate threads. 150 */ 151 ret = pthread_create(&t, NULL, do_fstrim_filesystems, (void *)(intptr_t)deep_trim); 152 if (ret) { 153 SLOGE("Cannot create thread to do fstrim"); 154 return ret; 155 } 156 157 ret = pthread_detach(t); 158 if (ret) { 159 SLOGE("Cannot detach thread doing fstrim"); 160 return ret; 161 } 162 163 return 0; 164 } 165