OSDN Git Service

merge in master-release history after reset to 8c008397141bf9a7d619eb2c53452bf3e397da39
[android-x86/system-vold.git] / fstrim.c
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 static unsigned long long get_boot_time_ms(void)
43 {
44     struct timespec t;
45     unsigned long long time_ms;
46
47     t.tv_sec = 0;
48     t.tv_nsec = 0;
49     clock_gettime(CLOCK_BOOTTIME, &t);
50     time_ms = (t.tv_sec * 1000LL) + (t.tv_nsec / 1000000);
51
52     return time_ms;
53 }
54
55 static void *do_fstrim_filesystems(void *ignored UNUSED)
56 {
57     int i;
58     int fd;
59     int ret = 0;
60     struct fstrim_range range = { 0 };
61     struct stat sb;
62     extern struct fstab *fstab;
63
64     SLOGI("Starting fstrim work...\n");
65
66     /* Log the start time in the event log */
67     LOG_EVENT_LONG(LOG_FSTRIM_START, get_boot_time_ms());
68
69     for (i = 0; i < fstab->num_entries; i++) {
70         /* Skip raw partitions */
71         if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
72             !strcmp(fstab->recs[i].fs_type, "mtd")) {
73             continue;
74         }
75         /* Skip read-only filesystems */
76         if (fstab->recs[i].flags & MS_RDONLY) {
77             continue;
78         }
79         if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
80             continue; /* Should we trim fat32 filesystems? */
81         }
82
83         if (stat(fstab->recs[i].mount_point, &sb) == -1) {
84             SLOGE("Cannot stat mount point %s\n", fstab->recs[i].mount_point);
85             ret = -1;
86             continue;
87         }
88         if (!S_ISDIR(sb.st_mode)) {
89             SLOGE("%s is not a directory\n", fstab->recs[i].mount_point);
90             ret = -1;
91             continue;
92         }
93
94         fd = open(fstab->recs[i].mount_point, O_RDONLY);
95         if (fd < 0) {
96             SLOGE("Cannot open %s for FITRIM\n", fstab->recs[i].mount_point);
97             ret = -1;
98             continue;
99         }
100
101         memset(&range, 0, sizeof(range));
102         range.len = ULLONG_MAX;
103         SLOGI("Invoking FITRIM ioctl on %s", fstab->recs[i].mount_point);
104         if (ioctl(fd, FITRIM, &range)) {
105             SLOGE("FITRIM ioctl failed on %s", fstab->recs[i].mount_point);
106             ret = -1;
107         } else {
108             SLOGI("Trimmed %llu bytes on %s\n", range.len, fstab->recs[i].mount_point);
109         }
110         close(fd);
111     }
112
113     /* Log the finish time in the event log */
114     LOG_EVENT_LONG(LOG_FSTRIM_FINISH, get_boot_time_ms());
115
116     SLOGI("Finished fstrim work.\n");
117
118     /* Release the wakelock that let us work */
119     release_wake_lock(FSTRIM_WAKELOCK);
120
121     return (void *)(uintptr_t)ret;
122 }
123
124 int fstrim_filesystems(void)
125 {
126     pthread_t t;
127     int ret;
128
129     /* Get a wakelock as this may take a while, and we don't want the
130      * device to sleep on us.
131      */
132     acquire_wake_lock(PARTIAL_WAKE_LOCK, FSTRIM_WAKELOCK);
133
134     /* Depending on the emmc chip and size, this can take upwards
135      * of a few minutes.  If done in the same thread as the caller
136      * of this function, that would block vold from accepting any
137      * commands until the trim is finished.  So start another thread
138      * to do the work, and return immediately.
139      *
140      * This function should not be called more than once per day, but
141      * even if it is called a second time before the first one finishes,
142      * the kernel will "do the right thing" and split the work between
143      * the two ioctls invoked in separate threads.
144      */
145     ret = pthread_create(&t, NULL, do_fstrim_filesystems, NULL);
146     if (ret) {
147         SLOGE("Cannot create thread to do fstrim");
148         return ret;
149     }
150
151     ret = pthread_detach(t);
152     if (ret) {
153         SLOGE("Cannot detach thread doing fstrim");
154         return ret;
155     }
156
157     return 0;
158 }