blob: 5a19b8c1bb26cd648780fe551bd5e1f97ed2005a [file] [log] [blame]
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -07001/*
2 * Copyright (C) 2015 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
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -060017#include "IdleMaint.h"
Jaegeuk Kim31e962f2018-07-29 06:56:57 -070018#include "FileDeviceUtils.h"
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -070019#include "Utils.h"
20#include "VolumeManager.h"
Jin Qiana370c142017-10-17 15:41:45 -070021#include "model/PrivateVolume.h"
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -070022
Jin Qiana370c142017-10-17 15:41:45 -070023#include <thread>
24
25#include <android-base/chrono_utils.h>
26#include <android-base/file.h>
Elliott Hughes7e128fb2015-12-04 15:50:53 -080027#include <android-base/stringprintf.h>
28#include <android-base/logging.h>
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -070029#include <fs_mgr.h>
30#include <private/android_filesystem_config.h>
31#include <hardware_legacy/power.h>
32
33#include <dirent.h>
34#include <sys/mount.h>
35#include <sys/stat.h>
36#include <sys/types.h>
37#include <sys/wait.h>
38#include <fcntl.h>
39
Jin Qiana370c142017-10-17 15:41:45 -070040using android::base::Basename;
41using android::base::ReadFileToString;
42using android::base::Realpath;
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -070043using android::base::StringPrintf;
Jin Qiana370c142017-10-17 15:41:45 -070044using android::base::Timer;
45using android::base::WriteStringToFile;
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -070046
47namespace android {
48namespace vold {
49
Jin Qiana370c142017-10-17 15:41:45 -070050enum class PathTypes {
51 kMountPoint = 1,
52 kBlkDevice,
53};
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -070054
Jin Qiana370c142017-10-17 15:41:45 -070055enum class IdleMaintStats {
56 kStopped = 1,
57 kRunning,
58 kAbort,
59};
60
61static const char* kWakeLock = "IdleMaint";
62static const int DIRTY_SEGMENTS_THRESHOLD = 100;
Jaegeuk Kimeefc5ee2018-02-12 21:57:04 -080063/*
64 * Timing policy:
65 * 1. F2FS_GC = 7 mins
66 * 2. Trim = 1 min
67 * 3. Dev GC = 2 mins
68 */
69static const int GC_TIMEOUT_SEC = 420;
70static const int DEVGC_TIMEOUT_SEC = 120;
Jin Qiana370c142017-10-17 15:41:45 -070071
72static IdleMaintStats idle_maint_stat(IdleMaintStats::kStopped);
73static std::condition_variable cv_abort, cv_stop;
74static std::mutex cv_m;
75
76static void addFromVolumeManager(std::list<std::string>* paths,
77 PathTypes path_type) {
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -070078 VolumeManager* vm = VolumeManager::Instance();
79 std::list<std::string> privateIds;
80 vm->listVolumes(VolumeBase::Type::kPrivate, privateIds);
Chih-Hung Hsieh11a2ce82016-07-27 14:11:02 -070081 for (const auto& id : privateIds) {
Jin Qiana370c142017-10-17 15:41:45 -070082 PrivateVolume* vol = static_cast<PrivateVolume*>(vm->findVolume(id).get());
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -070083 if (vol != nullptr && vol->getState() == VolumeBase::State::kMounted) {
Jin Qiana370c142017-10-17 15:41:45 -070084 if (path_type == PathTypes::kMountPoint) {
85 paths->push_back(vol->getPath());
86 } else if (path_type == PathTypes::kBlkDevice) {
87 std::string gc_path;
88 const std::string& fs_type = vol->getFsType();
Jaegeuk Kim31e962f2018-07-29 06:56:57 -070089 if (fs_type == "f2fs" && (Realpath(vol->getRawDmDevPath(), &gc_path) ||
90 Realpath(vol->getRawDevPath(), &gc_path))) {
Jin Qiana370c142017-10-17 15:41:45 -070091 paths->push_back(std::string("/sys/fs/") + fs_type +
92 "/" + Basename(gc_path));
93 }
94 }
95
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -070096 }
97 }
98}
99
Jin Qiana370c142017-10-17 15:41:45 -0700100static void addFromFstab(std::list<std::string>* paths, PathTypes path_type) {
Bowgo Tsaie8fb6c32017-03-09 23:11:33 +0800101 std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
102 fs_mgr_free_fstab);
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -0700103 struct fstab_rec *prev_rec = NULL;
104
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -0700105 for (int i = 0; i < fstab->num_entries; i++) {
Jeff Sharkey3472e522017-10-06 18:02:53 -0600106 auto fs_type = std::string(fstab->recs[i].fs_type);
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -0700107 /* Skip raw partitions */
Jeff Sharkey3472e522017-10-06 18:02:53 -0600108 if (fs_type == "emmc" || fs_type == "mtd") {
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -0700109 continue;
110 }
111 /* Skip read-only filesystems */
112 if (fstab->recs[i].flags & MS_RDONLY) {
113 continue;
114 }
115 if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
116 continue; /* Should we trim fat32 filesystems? */
117 }
118 if (fs_mgr_is_notrim(&fstab->recs[i])) {
119 continue;
120 }
121
122 /* Skip the multi-type partitions, which are required to be following each other.
123 * See fs_mgr.c's mount_with_alternatives().
124 */
125 if (prev_rec && !strcmp(prev_rec->mount_point, fstab->recs[i].mount_point)) {
126 continue;
127 }
128
Jin Qiana370c142017-10-17 15:41:45 -0700129 if (path_type == PathTypes::kMountPoint) {
130 paths->push_back(fstab->recs[i].mount_point);
131 } else if (path_type == PathTypes::kBlkDevice) {
132 std::string gc_path;
133 if (std::string(fstab->recs[i].fs_type) == "f2fs" &&
Jaegeuk Kim31e962f2018-07-29 06:56:57 -0700134 Realpath(android::vold::BlockDeviceForPath(
135 std::string(fstab->recs[i].mount_point) + "/"), &gc_path)) {
Jin Qiana370c142017-10-17 15:41:45 -0700136 paths->push_back(std::string("/sys/fs/") + fstab->recs[i].fs_type +
137 "/" + Basename(gc_path));
138 }
139 }
140
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -0700141 prev_rec = &fstab->recs[i];
142 }
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -0700143}
144
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600145void Trim(const android::sp<android::os::IVoldTaskListener>& listener) {
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -0700146 acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
147
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600148 // Collect both fstab and vold volumes
149 std::list<std::string> paths;
Jin Qiana370c142017-10-17 15:41:45 -0700150 addFromFstab(&paths, PathTypes::kMountPoint);
151 addFromVolumeManager(&paths, PathTypes::kMountPoint);
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600152
153 for (const auto& path : paths) {
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -0700154 LOG(DEBUG) << "Starting trim of " << path;
155
Jeff Sharkey52f7a912017-09-15 12:57:44 -0600156 android::os::PersistableBundle extras;
157 extras.putString(String16("path"), String16(path.c_str()));
158
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -0700159 int fd = open(path.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
160 if (fd < 0) {
161 PLOG(WARNING) << "Failed to open " << path;
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600162 if (listener) {
163 listener->onStatus(-1, extras);
Jeff Sharkey52f7a912017-09-15 12:57:44 -0600164 }
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -0700165 continue;
166 }
167
168 struct fstrim_range range;
169 memset(&range, 0, sizeof(range));
170 range.len = ULLONG_MAX;
171
172 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600173 if (ioctl(fd, FITRIM, &range)) {
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -0700174 PLOG(WARNING) << "Trim failed on " << path;
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600175 if (listener) {
176 listener->onStatus(-1, extras);
Jeff Sharkey52f7a912017-09-15 12:57:44 -0600177 }
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -0700178 } else {
Jeff Sharkey52f7a912017-09-15 12:57:44 -0600179 nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -0700180 LOG(INFO) << "Trimmed " << range.len << " bytes on " << path
Jeff Sharkey52f7a912017-09-15 12:57:44 -0600181 << " in " << nanoseconds_to_milliseconds(time) << "ms";
182 extras.putLong(String16("bytes"), range.len);
183 extras.putLong(String16("time"), time);
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600184 if (listener) {
185 listener->onStatus(0, extras);
Jeff Sharkey52f7a912017-09-15 12:57:44 -0600186 }
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -0700187 }
188 close(fd);
Jeff Sharkey52f7a912017-09-15 12:57:44 -0600189 }
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -0700190
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600191 if (listener) {
Jeff Sharkey52f7a912017-09-15 12:57:44 -0600192 android::os::PersistableBundle extras;
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600193 listener->onFinished(0, extras);
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -0700194 }
195
196 release_wake_lock(kWakeLock);
197}
198
Jin Qiana370c142017-10-17 15:41:45 -0700199static bool waitForGc(const std::list<std::string>& paths) {
200 std::unique_lock<std::mutex> lk(cv_m, std::defer_lock);
201 bool stop = false, aborted = false;
202 Timer timer;
203
204 while (!stop && !aborted) {
205 stop = true;
206 for (const auto& path : paths) {
207 std::string dirty_segments;
208 if (!ReadFileToString(path + "/dirty_segments", &dirty_segments)) {
209 PLOG(WARNING) << "Reading dirty_segments failed in " << path;
210 continue;
211 }
212 if (std::stoi(dirty_segments) > DIRTY_SEGMENTS_THRESHOLD) {
213 stop = false;
214 break;
215 }
216 }
217
218 if (stop) break;
219
220 if (timer.duration() >= std::chrono::seconds(GC_TIMEOUT_SEC)) {
221 LOG(WARNING) << "GC timeout";
222 break;
223 }
224
225 lk.lock();
226 aborted = cv_abort.wait_for(lk, 10s, []{
227 return idle_maint_stat == IdleMaintStats::kAbort;});
228 lk.unlock();
229 }
230
231 return aborted;
232}
233
234static int startGc(const std::list<std::string>& paths) {
235 for (const auto& path : paths) {
236 LOG(DEBUG) << "Start GC on " << path;
Jaegeuk Kima6aae2f2018-02-17 06:02:30 -0800237 if (!WriteStringToFile("1", path + "/discard_granularity")) {
238 PLOG(WARNING) << "Set discard gralunarity failed on" << path;
239 }
Jin Qiana370c142017-10-17 15:41:45 -0700240 if (!WriteStringToFile("1", path + "/gc_urgent")) {
241 PLOG(WARNING) << "Start GC failed on " << path;
242 }
243 }
244 return android::OK;
245}
246
247static int stopGc(const std::list<std::string>& paths) {
248 for (const auto& path : paths) {
249 LOG(DEBUG) << "Stop GC on " << path;
250 if (!WriteStringToFile("0", path + "/gc_urgent")) {
251 PLOG(WARNING) << "Stop GC failed on " << path;
252 }
Jaegeuk Kima6aae2f2018-02-17 06:02:30 -0800253 if (!WriteStringToFile("16", path + "/discard_granularity")) {
254 PLOG(WARNING) << "Set discard gralunarity failed on" << path;
255 }
Jin Qiana370c142017-10-17 15:41:45 -0700256 }
257 return android::OK;
258}
259
Jaegeuk Kimeefc5ee2018-02-12 21:57:04 -0800260static void runDevGc(void) {
261 std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
262 fs_mgr_free_fstab);
263 struct fstab_rec *rec = NULL;
264
265 for (int i = 0; i < fstab->num_entries; i++) {
266 if (fs_mgr_has_sysfs_path(&fstab->recs[i])) {
267 rec = &fstab->recs[i];
268 break;
269 }
270 }
271 if (!rec) {
272 return;
273 }
274
275 std::string path;
276 path.append(rec->sysfs_path);
277 path = path + "/manual_gc";
278 Timer timer;
279
280 LOG(DEBUG) << "Start Dev GC on " << path;
281 while (1) {
282 std::string require;
283 if (!ReadFileToString(path, &require)) {
284 PLOG(WARNING) << "Reading manual_gc failed in " << path;
285 break;
286 }
287
288 if (require == "" || require == "off" || require == "disabled") {
289 LOG(DEBUG) << "No more to do Dev GC";
290 break;
291 }
292
293 LOG(DEBUG) << "Trigger Dev GC on " << path;
294 if (!WriteStringToFile("1", path)) {
295 PLOG(WARNING) << "Start Dev GC failed on " << path;
296 break;
297 }
298
299 if (timer.duration() >= std::chrono::seconds(DEVGC_TIMEOUT_SEC)) {
300 LOG(WARNING) << "Dev GC timeout";
301 break;
302 }
303 sleep(2);
304 }
305 LOG(DEBUG) << "Stop Dev GC on " << path;
306 if (!WriteStringToFile("0", path)) {
307 PLOG(WARNING) << "Stop Dev GC failed on " << path;
308 }
309 return;
310}
311
Jin Qiana370c142017-10-17 15:41:45 -0700312int RunIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener) {
313 std::unique_lock<std::mutex> lk(cv_m);
314 if (idle_maint_stat != IdleMaintStats::kStopped) {
315 LOG(DEBUG) << "idle maintenance is already running";
316 if (listener) {
317 android::os::PersistableBundle extras;
318 listener->onFinished(0, extras);
319 }
320 return android::OK;
321 }
322 idle_maint_stat = IdleMaintStats::kRunning;
323 lk.unlock();
324
325 LOG(DEBUG) << "idle maintenance started";
326
327 acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
328
329 std::list<std::string> paths;
330 addFromFstab(&paths, PathTypes::kBlkDevice);
331 addFromVolumeManager(&paths, PathTypes::kBlkDevice);
332
333 startGc(paths);
334
335 bool gc_aborted = waitForGc(paths);
336
337 stopGc(paths);
338
339 lk.lock();
340 idle_maint_stat = IdleMaintStats::kStopped;
341 lk.unlock();
342
343 cv_stop.notify_one();
344
345 if (!gc_aborted) {
346 Trim(nullptr);
Jaegeuk Kimeefc5ee2018-02-12 21:57:04 -0800347 runDevGc();
Jin Qiana370c142017-10-17 15:41:45 -0700348 }
349
350 if (listener) {
351 android::os::PersistableBundle extras;
352 listener->onFinished(0, extras);
353 }
354
355 LOG(DEBUG) << "idle maintenance completed";
356
357 release_wake_lock(kWakeLock);
358
359 return android::OK;
360}
361
362int AbortIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener) {
363 acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
364
365 std::unique_lock<std::mutex> lk(cv_m);
366 if (idle_maint_stat != IdleMaintStats::kStopped) {
367 idle_maint_stat = IdleMaintStats::kAbort;
368 lk.unlock();
369 cv_abort.notify_one();
370 lk.lock();
371 LOG(DEBUG) << "aborting idle maintenance";
372 cv_stop.wait(lk, []{
373 return idle_maint_stat == IdleMaintStats::kStopped;});
374 }
375 lk.unlock();
376
377 if (listener) {
378 android::os::PersistableBundle extras;
379 listener->onFinished(0, extras);
380 }
381
382 release_wake_lock(kWakeLock);
383
384 LOG(DEBUG) << "idle maintenance stopped";
385
386 return android::OK;
387}
388
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -0700389} // namespace vold
390} // namespace android