1*f40fafd4SAndroid Build Coastguard Worker /*
2*f40fafd4SAndroid Build Coastguard Worker * Copyright (C) 2015 The Android Open Source Project
3*f40fafd4SAndroid Build Coastguard Worker *
4*f40fafd4SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*f40fafd4SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*f40fafd4SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*f40fafd4SAndroid Build Coastguard Worker *
8*f40fafd4SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*f40fafd4SAndroid Build Coastguard Worker *
10*f40fafd4SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*f40fafd4SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*f40fafd4SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*f40fafd4SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*f40fafd4SAndroid Build Coastguard Worker * limitations under the License.
15*f40fafd4SAndroid Build Coastguard Worker */
16*f40fafd4SAndroid Build Coastguard Worker
17*f40fafd4SAndroid Build Coastguard Worker #include "IdleMaint.h"
18*f40fafd4SAndroid Build Coastguard Worker #include "FileDeviceUtils.h"
19*f40fafd4SAndroid Build Coastguard Worker #include "Utils.h"
20*f40fafd4SAndroid Build Coastguard Worker #include "VoldUtil.h"
21*f40fafd4SAndroid Build Coastguard Worker #include "VolumeManager.h"
22*f40fafd4SAndroid Build Coastguard Worker #include "model/PrivateVolume.h"
23*f40fafd4SAndroid Build Coastguard Worker
24*f40fafd4SAndroid Build Coastguard Worker #include <thread>
25*f40fafd4SAndroid Build Coastguard Worker #include <utility>
26*f40fafd4SAndroid Build Coastguard Worker
27*f40fafd4SAndroid Build Coastguard Worker #include <aidl/android/hardware/health/storage/BnGarbageCollectCallback.h>
28*f40fafd4SAndroid Build Coastguard Worker #include <aidl/android/hardware/health/storage/IStorage.h>
29*f40fafd4SAndroid Build Coastguard Worker #include <android-base/chrono_utils.h>
30*f40fafd4SAndroid Build Coastguard Worker #include <android-base/file.h>
31*f40fafd4SAndroid Build Coastguard Worker #include <android-base/logging.h>
32*f40fafd4SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
33*f40fafd4SAndroid Build Coastguard Worker #include <android-base/strings.h>
34*f40fafd4SAndroid Build Coastguard Worker #include <android/binder_manager.h>
35*f40fafd4SAndroid Build Coastguard Worker #include <android/hardware/health/storage/1.0/IStorage.h>
36*f40fafd4SAndroid Build Coastguard Worker #include <fs_mgr.h>
37*f40fafd4SAndroid Build Coastguard Worker #include <private/android_filesystem_config.h>
38*f40fafd4SAndroid Build Coastguard Worker #include <wakelock/wakelock.h>
39*f40fafd4SAndroid Build Coastguard Worker
40*f40fafd4SAndroid Build Coastguard Worker #include <dirent.h>
41*f40fafd4SAndroid Build Coastguard Worker #include <fcntl.h>
42*f40fafd4SAndroid Build Coastguard Worker #include <sys/mount.h>
43*f40fafd4SAndroid Build Coastguard Worker #include <sys/stat.h>
44*f40fafd4SAndroid Build Coastguard Worker #include <sys/types.h>
45*f40fafd4SAndroid Build Coastguard Worker #include <sys/wait.h>
46*f40fafd4SAndroid Build Coastguard Worker
47*f40fafd4SAndroid Build Coastguard Worker using android::base::Basename;
48*f40fafd4SAndroid Build Coastguard Worker using android::base::ReadFileToString;
49*f40fafd4SAndroid Build Coastguard Worker using android::base::Realpath;
50*f40fafd4SAndroid Build Coastguard Worker using android::base::StringPrintf;
51*f40fafd4SAndroid Build Coastguard Worker using android::base::Timer;
52*f40fafd4SAndroid Build Coastguard Worker using android::base::WriteStringToFile;
53*f40fafd4SAndroid Build Coastguard Worker using android::hardware::Return;
54*f40fafd4SAndroid Build Coastguard Worker using android::hardware::Void;
55*f40fafd4SAndroid Build Coastguard Worker using AStorage = aidl::android::hardware::health::storage::IStorage;
56*f40fafd4SAndroid Build Coastguard Worker using ABnGarbageCollectCallback =
57*f40fafd4SAndroid Build Coastguard Worker aidl::android::hardware::health::storage::BnGarbageCollectCallback;
58*f40fafd4SAndroid Build Coastguard Worker using AResult = aidl::android::hardware::health::storage::Result;
59*f40fafd4SAndroid Build Coastguard Worker using HStorage = android::hardware::health::storage::V1_0::IStorage;
60*f40fafd4SAndroid Build Coastguard Worker using HGarbageCollectCallback = android::hardware::health::storage::V1_0::IGarbageCollectCallback;
61*f40fafd4SAndroid Build Coastguard Worker using HResult = android::hardware::health::storage::V1_0::Result;
62*f40fafd4SAndroid Build Coastguard Worker using std::string_literals::operator""s;
63*f40fafd4SAndroid Build Coastguard Worker
64*f40fafd4SAndroid Build Coastguard Worker namespace android {
65*f40fafd4SAndroid Build Coastguard Worker namespace vold {
66*f40fafd4SAndroid Build Coastguard Worker
67*f40fafd4SAndroid Build Coastguard Worker enum class PathTypes {
68*f40fafd4SAndroid Build Coastguard Worker kMountPoint = 1,
69*f40fafd4SAndroid Build Coastguard Worker kBlkDevice,
70*f40fafd4SAndroid Build Coastguard Worker };
71*f40fafd4SAndroid Build Coastguard Worker
72*f40fafd4SAndroid Build Coastguard Worker enum class IdleMaintStats {
73*f40fafd4SAndroid Build Coastguard Worker kStopped = 1,
74*f40fafd4SAndroid Build Coastguard Worker kRunning,
75*f40fafd4SAndroid Build Coastguard Worker kAbort,
76*f40fafd4SAndroid Build Coastguard Worker };
77*f40fafd4SAndroid Build Coastguard Worker
78*f40fafd4SAndroid Build Coastguard Worker static const char* kWakeLock = "IdleMaint";
79*f40fafd4SAndroid Build Coastguard Worker static const int DIRTY_SEGMENTS_THRESHOLD = 100;
80*f40fafd4SAndroid Build Coastguard Worker /*
81*f40fafd4SAndroid Build Coastguard Worker * Timing policy:
82*f40fafd4SAndroid Build Coastguard Worker * 1. F2FS_GC = 7 mins
83*f40fafd4SAndroid Build Coastguard Worker * 2. Trim = 1 min
84*f40fafd4SAndroid Build Coastguard Worker * 3. Dev GC = 2 mins
85*f40fafd4SAndroid Build Coastguard Worker */
86*f40fafd4SAndroid Build Coastguard Worker static const int GC_TIMEOUT_SEC = 420;
87*f40fafd4SAndroid Build Coastguard Worker static const int DEVGC_TIMEOUT_SEC = 120;
88*f40fafd4SAndroid Build Coastguard Worker static const int KBYTES_IN_SEGMENT = 2048;
89*f40fafd4SAndroid Build Coastguard Worker static const int ONE_MINUTE_IN_MS = 60000;
90*f40fafd4SAndroid Build Coastguard Worker static const int GC_NORMAL_MODE = 0;
91*f40fafd4SAndroid Build Coastguard Worker static const int GC_URGENT_MID_MODE = 3;
92*f40fafd4SAndroid Build Coastguard Worker
93*f40fafd4SAndroid Build Coastguard Worker static int32_t previousSegmentWrite = 0;
94*f40fafd4SAndroid Build Coastguard Worker
95*f40fafd4SAndroid Build Coastguard Worker static IdleMaintStats idle_maint_stat(IdleMaintStats::kStopped);
96*f40fafd4SAndroid Build Coastguard Worker static std::condition_variable cv_abort, cv_stop;
97*f40fafd4SAndroid Build Coastguard Worker static std::mutex cv_m;
98*f40fafd4SAndroid Build Coastguard Worker
addFromVolumeManager(std::list<std::string> * paths,PathTypes path_type)99*f40fafd4SAndroid Build Coastguard Worker static void addFromVolumeManager(std::list<std::string>* paths, PathTypes path_type) {
100*f40fafd4SAndroid Build Coastguard Worker VolumeManager* vm = VolumeManager::Instance();
101*f40fafd4SAndroid Build Coastguard Worker std::list<std::string> privateIds;
102*f40fafd4SAndroid Build Coastguard Worker vm->listVolumes(VolumeBase::Type::kPrivate, privateIds);
103*f40fafd4SAndroid Build Coastguard Worker for (const auto& id : privateIds) {
104*f40fafd4SAndroid Build Coastguard Worker PrivateVolume* vol = static_cast<PrivateVolume*>(vm->findVolume(id).get());
105*f40fafd4SAndroid Build Coastguard Worker if (vol != nullptr && vol->getState() == VolumeBase::State::kMounted) {
106*f40fafd4SAndroid Build Coastguard Worker if (path_type == PathTypes::kMountPoint) {
107*f40fafd4SAndroid Build Coastguard Worker paths->push_back(vol->getPath());
108*f40fafd4SAndroid Build Coastguard Worker } else if (path_type == PathTypes::kBlkDevice) {
109*f40fafd4SAndroid Build Coastguard Worker std::string gc_path;
110*f40fafd4SAndroid Build Coastguard Worker const std::string& fs_type = vol->getFsType();
111*f40fafd4SAndroid Build Coastguard Worker if (fs_type == "f2fs" && (Realpath(vol->getRawDmDevPath(), &gc_path) ||
112*f40fafd4SAndroid Build Coastguard Worker Realpath(vol->getRawDevPath(), &gc_path))) {
113*f40fafd4SAndroid Build Coastguard Worker paths->push_back(std::string("/sys/fs/") + fs_type + "/" + Basename(gc_path));
114*f40fafd4SAndroid Build Coastguard Worker }
115*f40fafd4SAndroid Build Coastguard Worker }
116*f40fafd4SAndroid Build Coastguard Worker }
117*f40fafd4SAndroid Build Coastguard Worker }
118*f40fafd4SAndroid Build Coastguard Worker }
119*f40fafd4SAndroid Build Coastguard Worker
addFromFstab(std::list<std::string> * paths,PathTypes path_type,bool only_data_part)120*f40fafd4SAndroid Build Coastguard Worker static void addFromFstab(std::list<std::string>* paths, PathTypes path_type, bool only_data_part) {
121*f40fafd4SAndroid Build Coastguard Worker std::string previous_mount_point;
122*f40fafd4SAndroid Build Coastguard Worker for (const auto& entry : fstab_default) {
123*f40fafd4SAndroid Build Coastguard Worker // Skip raw partitions and swap space.
124*f40fafd4SAndroid Build Coastguard Worker if (entry.fs_type == "emmc" || entry.fs_type == "mtd" || entry.fs_type == "swap") {
125*f40fafd4SAndroid Build Coastguard Worker continue;
126*f40fafd4SAndroid Build Coastguard Worker }
127*f40fafd4SAndroid Build Coastguard Worker // Skip read-only filesystems and bind mounts.
128*f40fafd4SAndroid Build Coastguard Worker if (entry.flags & (MS_RDONLY | MS_BIND)) {
129*f40fafd4SAndroid Build Coastguard Worker continue;
130*f40fafd4SAndroid Build Coastguard Worker }
131*f40fafd4SAndroid Build Coastguard Worker // Skip anything without an underlying block device, e.g. virtiofs.
132*f40fafd4SAndroid Build Coastguard Worker if (entry.blk_device[0] != '/') {
133*f40fafd4SAndroid Build Coastguard Worker continue;
134*f40fafd4SAndroid Build Coastguard Worker }
135*f40fafd4SAndroid Build Coastguard Worker if (entry.fs_mgr_flags.vold_managed) {
136*f40fafd4SAndroid Build Coastguard Worker continue; // Should we trim fat32 filesystems?
137*f40fafd4SAndroid Build Coastguard Worker }
138*f40fafd4SAndroid Build Coastguard Worker if (entry.fs_mgr_flags.no_trim) {
139*f40fafd4SAndroid Build Coastguard Worker continue;
140*f40fafd4SAndroid Build Coastguard Worker }
141*f40fafd4SAndroid Build Coastguard Worker
142*f40fafd4SAndroid Build Coastguard Worker if (only_data_part && entry.mount_point != "/data") {
143*f40fafd4SAndroid Build Coastguard Worker continue;
144*f40fafd4SAndroid Build Coastguard Worker }
145*f40fafd4SAndroid Build Coastguard Worker
146*f40fafd4SAndroid Build Coastguard Worker // Skip the multi-type partitions, which are required to be following each other.
147*f40fafd4SAndroid Build Coastguard Worker // See fs_mgr.c's mount_with_alternatives().
148*f40fafd4SAndroid Build Coastguard Worker if (entry.mount_point == previous_mount_point) {
149*f40fafd4SAndroid Build Coastguard Worker continue;
150*f40fafd4SAndroid Build Coastguard Worker }
151*f40fafd4SAndroid Build Coastguard Worker
152*f40fafd4SAndroid Build Coastguard Worker if (path_type == PathTypes::kMountPoint) {
153*f40fafd4SAndroid Build Coastguard Worker paths->push_back(entry.mount_point);
154*f40fafd4SAndroid Build Coastguard Worker } else if (path_type == PathTypes::kBlkDevice) {
155*f40fafd4SAndroid Build Coastguard Worker std::string path;
156*f40fafd4SAndroid Build Coastguard Worker if (entry.fs_type == "f2fs" &&
157*f40fafd4SAndroid Build Coastguard Worker Realpath(android::vold::BlockDeviceForPath(entry.mount_point + "/"), &path)) {
158*f40fafd4SAndroid Build Coastguard Worker paths->push_back("/sys/fs/" + entry.fs_type + "/" + Basename(path));
159*f40fafd4SAndroid Build Coastguard Worker }
160*f40fafd4SAndroid Build Coastguard Worker }
161*f40fafd4SAndroid Build Coastguard Worker
162*f40fafd4SAndroid Build Coastguard Worker previous_mount_point = entry.mount_point;
163*f40fafd4SAndroid Build Coastguard Worker }
164*f40fafd4SAndroid Build Coastguard Worker }
165*f40fafd4SAndroid Build Coastguard Worker
Trim(const android::sp<android::os::IVoldTaskListener> & listener)166*f40fafd4SAndroid Build Coastguard Worker void Trim(const android::sp<android::os::IVoldTaskListener>& listener) {
167*f40fafd4SAndroid Build Coastguard Worker auto wl = android::wakelock::WakeLock::tryGet(kWakeLock);
168*f40fafd4SAndroid Build Coastguard Worker if (!wl.has_value()) {
169*f40fafd4SAndroid Build Coastguard Worker return;
170*f40fafd4SAndroid Build Coastguard Worker }
171*f40fafd4SAndroid Build Coastguard Worker
172*f40fafd4SAndroid Build Coastguard Worker // Collect both fstab and vold volumes
173*f40fafd4SAndroid Build Coastguard Worker std::list<std::string> paths;
174*f40fafd4SAndroid Build Coastguard Worker addFromFstab(&paths, PathTypes::kMountPoint, false);
175*f40fafd4SAndroid Build Coastguard Worker addFromVolumeManager(&paths, PathTypes::kMountPoint);
176*f40fafd4SAndroid Build Coastguard Worker
177*f40fafd4SAndroid Build Coastguard Worker for (const auto& path : paths) {
178*f40fafd4SAndroid Build Coastguard Worker LOG(DEBUG) << "Starting trim of " << path;
179*f40fafd4SAndroid Build Coastguard Worker
180*f40fafd4SAndroid Build Coastguard Worker android::os::PersistableBundle extras;
181*f40fafd4SAndroid Build Coastguard Worker extras.putString(String16("path"), String16(path.c_str()));
182*f40fafd4SAndroid Build Coastguard Worker
183*f40fafd4SAndroid Build Coastguard Worker int fd = open(path.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
184*f40fafd4SAndroid Build Coastguard Worker if (fd < 0) {
185*f40fafd4SAndroid Build Coastguard Worker PLOG(WARNING) << "Failed to open " << path;
186*f40fafd4SAndroid Build Coastguard Worker if (listener) {
187*f40fafd4SAndroid Build Coastguard Worker listener->onStatus(-1, extras);
188*f40fafd4SAndroid Build Coastguard Worker }
189*f40fafd4SAndroid Build Coastguard Worker continue;
190*f40fafd4SAndroid Build Coastguard Worker }
191*f40fafd4SAndroid Build Coastguard Worker
192*f40fafd4SAndroid Build Coastguard Worker struct fstrim_range range;
193*f40fafd4SAndroid Build Coastguard Worker memset(&range, 0, sizeof(range));
194*f40fafd4SAndroid Build Coastguard Worker range.len = ULLONG_MAX;
195*f40fafd4SAndroid Build Coastguard Worker
196*f40fafd4SAndroid Build Coastguard Worker nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
197*f40fafd4SAndroid Build Coastguard Worker if (ioctl(fd, FITRIM, &range)) {
198*f40fafd4SAndroid Build Coastguard Worker PLOG(WARNING) << "Trim failed on " << path;
199*f40fafd4SAndroid Build Coastguard Worker if (listener) {
200*f40fafd4SAndroid Build Coastguard Worker listener->onStatus(-1, extras);
201*f40fafd4SAndroid Build Coastguard Worker }
202*f40fafd4SAndroid Build Coastguard Worker } else {
203*f40fafd4SAndroid Build Coastguard Worker nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
204*f40fafd4SAndroid Build Coastguard Worker LOG(INFO) << "Trimmed " << range.len << " bytes on " << path << " in "
205*f40fafd4SAndroid Build Coastguard Worker << nanoseconds_to_milliseconds(time) << "ms";
206*f40fafd4SAndroid Build Coastguard Worker extras.putLong(String16("bytes"), range.len);
207*f40fafd4SAndroid Build Coastguard Worker extras.putLong(String16("time"), time);
208*f40fafd4SAndroid Build Coastguard Worker if (listener) {
209*f40fafd4SAndroid Build Coastguard Worker listener->onStatus(0, extras);
210*f40fafd4SAndroid Build Coastguard Worker }
211*f40fafd4SAndroid Build Coastguard Worker }
212*f40fafd4SAndroid Build Coastguard Worker close(fd);
213*f40fafd4SAndroid Build Coastguard Worker }
214*f40fafd4SAndroid Build Coastguard Worker
215*f40fafd4SAndroid Build Coastguard Worker if (listener) {
216*f40fafd4SAndroid Build Coastguard Worker android::os::PersistableBundle extras;
217*f40fafd4SAndroid Build Coastguard Worker listener->onFinished(0, extras);
218*f40fafd4SAndroid Build Coastguard Worker }
219*f40fafd4SAndroid Build Coastguard Worker
220*f40fafd4SAndroid Build Coastguard Worker }
221*f40fafd4SAndroid Build Coastguard Worker
waitForGc(const std::list<std::string> & paths)222*f40fafd4SAndroid Build Coastguard Worker static bool waitForGc(const std::list<std::string>& paths) {
223*f40fafd4SAndroid Build Coastguard Worker std::unique_lock<std::mutex> lk(cv_m, std::defer_lock);
224*f40fafd4SAndroid Build Coastguard Worker bool stop = false, aborted = false;
225*f40fafd4SAndroid Build Coastguard Worker Timer timer;
226*f40fafd4SAndroid Build Coastguard Worker
227*f40fafd4SAndroid Build Coastguard Worker while (!stop && !aborted) {
228*f40fafd4SAndroid Build Coastguard Worker stop = true;
229*f40fafd4SAndroid Build Coastguard Worker for (const auto& path : paths) {
230*f40fafd4SAndroid Build Coastguard Worker std::string dirty_segments;
231*f40fafd4SAndroid Build Coastguard Worker if (!ReadFileToString(path + "/dirty_segments", &dirty_segments)) {
232*f40fafd4SAndroid Build Coastguard Worker PLOG(WARNING) << "Reading dirty_segments failed in " << path;
233*f40fafd4SAndroid Build Coastguard Worker continue;
234*f40fafd4SAndroid Build Coastguard Worker }
235*f40fafd4SAndroid Build Coastguard Worker if (std::stoi(dirty_segments) > DIRTY_SEGMENTS_THRESHOLD) {
236*f40fafd4SAndroid Build Coastguard Worker stop = false;
237*f40fafd4SAndroid Build Coastguard Worker break;
238*f40fafd4SAndroid Build Coastguard Worker }
239*f40fafd4SAndroid Build Coastguard Worker }
240*f40fafd4SAndroid Build Coastguard Worker
241*f40fafd4SAndroid Build Coastguard Worker if (stop) break;
242*f40fafd4SAndroid Build Coastguard Worker
243*f40fafd4SAndroid Build Coastguard Worker if (timer.duration() >= std::chrono::seconds(GC_TIMEOUT_SEC)) {
244*f40fafd4SAndroid Build Coastguard Worker LOG(WARNING) << "GC timeout";
245*f40fafd4SAndroid Build Coastguard Worker break;
246*f40fafd4SAndroid Build Coastguard Worker }
247*f40fafd4SAndroid Build Coastguard Worker
248*f40fafd4SAndroid Build Coastguard Worker lk.lock();
249*f40fafd4SAndroid Build Coastguard Worker aborted =
250*f40fafd4SAndroid Build Coastguard Worker cv_abort.wait_for(lk, 10s, [] { return idle_maint_stat == IdleMaintStats::kAbort; });
251*f40fafd4SAndroid Build Coastguard Worker lk.unlock();
252*f40fafd4SAndroid Build Coastguard Worker }
253*f40fafd4SAndroid Build Coastguard Worker
254*f40fafd4SAndroid Build Coastguard Worker return aborted;
255*f40fafd4SAndroid Build Coastguard Worker }
256*f40fafd4SAndroid Build Coastguard Worker
startGc(const std::list<std::string> & paths)257*f40fafd4SAndroid Build Coastguard Worker static int startGc(const std::list<std::string>& paths) {
258*f40fafd4SAndroid Build Coastguard Worker for (const auto& path : paths) {
259*f40fafd4SAndroid Build Coastguard Worker LOG(DEBUG) << "Start GC on " << path;
260*f40fafd4SAndroid Build Coastguard Worker if (!WriteStringToFile("1", path + "/gc_urgent")) {
261*f40fafd4SAndroid Build Coastguard Worker PLOG(WARNING) << "Start GC failed on " << path;
262*f40fafd4SAndroid Build Coastguard Worker }
263*f40fafd4SAndroid Build Coastguard Worker }
264*f40fafd4SAndroid Build Coastguard Worker return android::OK;
265*f40fafd4SAndroid Build Coastguard Worker }
266*f40fafd4SAndroid Build Coastguard Worker
stopGc(const std::list<std::string> & paths)267*f40fafd4SAndroid Build Coastguard Worker static int stopGc(const std::list<std::string>& paths) {
268*f40fafd4SAndroid Build Coastguard Worker for (const auto& path : paths) {
269*f40fafd4SAndroid Build Coastguard Worker LOG(DEBUG) << "Stop GC on " << path;
270*f40fafd4SAndroid Build Coastguard Worker if (!WriteStringToFile("0", path + "/gc_urgent")) {
271*f40fafd4SAndroid Build Coastguard Worker PLOG(WARNING) << "Stop GC failed on " << path;
272*f40fafd4SAndroid Build Coastguard Worker }
273*f40fafd4SAndroid Build Coastguard Worker }
274*f40fafd4SAndroid Build Coastguard Worker return android::OK;
275*f40fafd4SAndroid Build Coastguard Worker }
276*f40fafd4SAndroid Build Coastguard Worker
getDevSysfsPath()277*f40fafd4SAndroid Build Coastguard Worker static std::string getDevSysfsPath() {
278*f40fafd4SAndroid Build Coastguard Worker for (const auto& entry : fstab_default) {
279*f40fafd4SAndroid Build Coastguard Worker if (!entry.sysfs_path.empty()) {
280*f40fafd4SAndroid Build Coastguard Worker return entry.sysfs_path;
281*f40fafd4SAndroid Build Coastguard Worker }
282*f40fafd4SAndroid Build Coastguard Worker }
283*f40fafd4SAndroid Build Coastguard Worker LOG(WARNING) << "Cannot find dev sysfs path";
284*f40fafd4SAndroid Build Coastguard Worker return "";
285*f40fafd4SAndroid Build Coastguard Worker }
286*f40fafd4SAndroid Build Coastguard Worker
runDevGcFstab(void)287*f40fafd4SAndroid Build Coastguard Worker static void runDevGcFstab(void) {
288*f40fafd4SAndroid Build Coastguard Worker std::string path = getDevSysfsPath();
289*f40fafd4SAndroid Build Coastguard Worker if (path.empty()) {
290*f40fafd4SAndroid Build Coastguard Worker return;
291*f40fafd4SAndroid Build Coastguard Worker }
292*f40fafd4SAndroid Build Coastguard Worker
293*f40fafd4SAndroid Build Coastguard Worker path = path + "/manual_gc";
294*f40fafd4SAndroid Build Coastguard Worker Timer timer;
295*f40fafd4SAndroid Build Coastguard Worker
296*f40fafd4SAndroid Build Coastguard Worker LOG(DEBUG) << "Start Dev GC on " << path;
297*f40fafd4SAndroid Build Coastguard Worker while (1) {
298*f40fafd4SAndroid Build Coastguard Worker std::string require;
299*f40fafd4SAndroid Build Coastguard Worker if (!ReadFileToString(path, &require)) {
300*f40fafd4SAndroid Build Coastguard Worker PLOG(WARNING) << "Reading manual_gc failed in " << path;
301*f40fafd4SAndroid Build Coastguard Worker break;
302*f40fafd4SAndroid Build Coastguard Worker }
303*f40fafd4SAndroid Build Coastguard Worker require = android::base::Trim(require);
304*f40fafd4SAndroid Build Coastguard Worker if (require == "" || require == "off" || require == "disabled") {
305*f40fafd4SAndroid Build Coastguard Worker LOG(DEBUG) << "No more to do Dev GC";
306*f40fafd4SAndroid Build Coastguard Worker break;
307*f40fafd4SAndroid Build Coastguard Worker }
308*f40fafd4SAndroid Build Coastguard Worker
309*f40fafd4SAndroid Build Coastguard Worker LOG(DEBUG) << "Trigger Dev GC on " << path;
310*f40fafd4SAndroid Build Coastguard Worker if (!WriteStringToFile("1", path)) {
311*f40fafd4SAndroid Build Coastguard Worker PLOG(WARNING) << "Start Dev GC failed on " << path;
312*f40fafd4SAndroid Build Coastguard Worker break;
313*f40fafd4SAndroid Build Coastguard Worker }
314*f40fafd4SAndroid Build Coastguard Worker
315*f40fafd4SAndroid Build Coastguard Worker if (timer.duration() >= std::chrono::seconds(DEVGC_TIMEOUT_SEC)) {
316*f40fafd4SAndroid Build Coastguard Worker LOG(WARNING) << "Dev GC timeout";
317*f40fafd4SAndroid Build Coastguard Worker break;
318*f40fafd4SAndroid Build Coastguard Worker }
319*f40fafd4SAndroid Build Coastguard Worker sleep(2);
320*f40fafd4SAndroid Build Coastguard Worker }
321*f40fafd4SAndroid Build Coastguard Worker LOG(DEBUG) << "Stop Dev GC on " << path;
322*f40fafd4SAndroid Build Coastguard Worker if (!WriteStringToFile("0", path)) {
323*f40fafd4SAndroid Build Coastguard Worker PLOG(WARNING) << "Stop Dev GC failed on " << path;
324*f40fafd4SAndroid Build Coastguard Worker }
325*f40fafd4SAndroid Build Coastguard Worker return;
326*f40fafd4SAndroid Build Coastguard Worker }
327*f40fafd4SAndroid Build Coastguard Worker
328*f40fafd4SAndroid Build Coastguard Worker enum class IDL { HIDL, AIDL };
operator <<(std::ostream & os,IDL idl)329*f40fafd4SAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, IDL idl) {
330*f40fafd4SAndroid Build Coastguard Worker return os << (idl == IDL::HIDL ? "HIDL" : "AIDL");
331*f40fafd4SAndroid Build Coastguard Worker }
332*f40fafd4SAndroid Build Coastguard Worker
333*f40fafd4SAndroid Build Coastguard Worker template <IDL idl, typename Result>
334*f40fafd4SAndroid Build Coastguard Worker class GcCallbackImpl {
335*f40fafd4SAndroid Build Coastguard Worker protected:
onFinishInternal(Result result)336*f40fafd4SAndroid Build Coastguard Worker void onFinishInternal(Result result) {
337*f40fafd4SAndroid Build Coastguard Worker std::unique_lock<std::mutex> lock(mMutex);
338*f40fafd4SAndroid Build Coastguard Worker mFinished = true;
339*f40fafd4SAndroid Build Coastguard Worker mResult = result;
340*f40fafd4SAndroid Build Coastguard Worker lock.unlock();
341*f40fafd4SAndroid Build Coastguard Worker mCv.notify_all();
342*f40fafd4SAndroid Build Coastguard Worker }
343*f40fafd4SAndroid Build Coastguard Worker
344*f40fafd4SAndroid Build Coastguard Worker public:
wait(uint64_t seconds)345*f40fafd4SAndroid Build Coastguard Worker void wait(uint64_t seconds) {
346*f40fafd4SAndroid Build Coastguard Worker std::unique_lock<std::mutex> lock(mMutex);
347*f40fafd4SAndroid Build Coastguard Worker mCv.wait_for(lock, std::chrono::seconds(seconds), [this] { return mFinished; });
348*f40fafd4SAndroid Build Coastguard Worker
349*f40fafd4SAndroid Build Coastguard Worker if (!mFinished) {
350*f40fafd4SAndroid Build Coastguard Worker LOG(WARNING) << "Dev GC on " << idl << " HAL timeout";
351*f40fafd4SAndroid Build Coastguard Worker } else if (mResult != Result::SUCCESS) {
352*f40fafd4SAndroid Build Coastguard Worker LOG(WARNING) << "Dev GC on " << idl << " HAL failed with " << toString(mResult);
353*f40fafd4SAndroid Build Coastguard Worker } else {
354*f40fafd4SAndroid Build Coastguard Worker LOG(INFO) << "Dev GC on " << idl << " HAL successful";
355*f40fafd4SAndroid Build Coastguard Worker }
356*f40fafd4SAndroid Build Coastguard Worker }
357*f40fafd4SAndroid Build Coastguard Worker
358*f40fafd4SAndroid Build Coastguard Worker private:
359*f40fafd4SAndroid Build Coastguard Worker std::mutex mMutex;
360*f40fafd4SAndroid Build Coastguard Worker std::condition_variable mCv;
361*f40fafd4SAndroid Build Coastguard Worker bool mFinished{false};
362*f40fafd4SAndroid Build Coastguard Worker Result mResult{Result::UNKNOWN_ERROR};
363*f40fafd4SAndroid Build Coastguard Worker };
364*f40fafd4SAndroid Build Coastguard Worker
365*f40fafd4SAndroid Build Coastguard Worker class AGcCallbackImpl : public ABnGarbageCollectCallback,
366*f40fafd4SAndroid Build Coastguard Worker public GcCallbackImpl<IDL::AIDL, AResult> {
onFinish(AResult result)367*f40fafd4SAndroid Build Coastguard Worker ndk::ScopedAStatus onFinish(AResult result) override {
368*f40fafd4SAndroid Build Coastguard Worker onFinishInternal(result);
369*f40fafd4SAndroid Build Coastguard Worker return ndk::ScopedAStatus::ok();
370*f40fafd4SAndroid Build Coastguard Worker }
371*f40fafd4SAndroid Build Coastguard Worker };
372*f40fafd4SAndroid Build Coastguard Worker
373*f40fafd4SAndroid Build Coastguard Worker class HGcCallbackImpl : public HGarbageCollectCallback, public GcCallbackImpl<IDL::HIDL, HResult> {
onFinish(HResult result)374*f40fafd4SAndroid Build Coastguard Worker Return<void> onFinish(HResult result) override {
375*f40fafd4SAndroid Build Coastguard Worker onFinishInternal(result);
376*f40fafd4SAndroid Build Coastguard Worker return Void();
377*f40fafd4SAndroid Build Coastguard Worker }
378*f40fafd4SAndroid Build Coastguard Worker };
379*f40fafd4SAndroid Build Coastguard Worker
380*f40fafd4SAndroid Build Coastguard Worker template <IDL idl, typename Service, typename GcCallbackImpl, typename GetDescription>
runDevGcOnHal(Service service,GcCallbackImpl cb,GetDescription get_description)381*f40fafd4SAndroid Build Coastguard Worker static void runDevGcOnHal(Service service, GcCallbackImpl cb, GetDescription get_description) {
382*f40fafd4SAndroid Build Coastguard Worker LOG(DEBUG) << "Start Dev GC on " << idl << " HAL";
383*f40fafd4SAndroid Build Coastguard Worker auto ret = service->garbageCollect(DEVGC_TIMEOUT_SEC, cb);
384*f40fafd4SAndroid Build Coastguard Worker if (!ret.isOk()) {
385*f40fafd4SAndroid Build Coastguard Worker LOG(WARNING) << "Cannot start Dev GC on " << idl
386*f40fafd4SAndroid Build Coastguard Worker << " HAL: " << std::invoke(get_description, ret);
387*f40fafd4SAndroid Build Coastguard Worker return;
388*f40fafd4SAndroid Build Coastguard Worker }
389*f40fafd4SAndroid Build Coastguard Worker cb->wait(DEVGC_TIMEOUT_SEC);
390*f40fafd4SAndroid Build Coastguard Worker }
391*f40fafd4SAndroid Build Coastguard Worker
runDevGc(void)392*f40fafd4SAndroid Build Coastguard Worker static void runDevGc(void) {
393*f40fafd4SAndroid Build Coastguard Worker runDevGcFstab();
394*f40fafd4SAndroid Build Coastguard Worker }
395*f40fafd4SAndroid Build Coastguard Worker
RunIdleMaint(bool needGC,const android::sp<android::os::IVoldTaskListener> & listener)396*f40fafd4SAndroid Build Coastguard Worker int RunIdleMaint(bool needGC, const android::sp<android::os::IVoldTaskListener>& listener) {
397*f40fafd4SAndroid Build Coastguard Worker std::unique_lock<std::mutex> lk(cv_m);
398*f40fafd4SAndroid Build Coastguard Worker bool gc_aborted = false;
399*f40fafd4SAndroid Build Coastguard Worker
400*f40fafd4SAndroid Build Coastguard Worker if (idle_maint_stat != IdleMaintStats::kStopped) {
401*f40fafd4SAndroid Build Coastguard Worker LOG(DEBUG) << "idle maintenance is already running";
402*f40fafd4SAndroid Build Coastguard Worker if (listener) {
403*f40fafd4SAndroid Build Coastguard Worker android::os::PersistableBundle extras;
404*f40fafd4SAndroid Build Coastguard Worker listener->onFinished(0, extras);
405*f40fafd4SAndroid Build Coastguard Worker }
406*f40fafd4SAndroid Build Coastguard Worker return android::OK;
407*f40fafd4SAndroid Build Coastguard Worker }
408*f40fafd4SAndroid Build Coastguard Worker idle_maint_stat = IdleMaintStats::kRunning;
409*f40fafd4SAndroid Build Coastguard Worker lk.unlock();
410*f40fafd4SAndroid Build Coastguard Worker
411*f40fafd4SAndroid Build Coastguard Worker LOG(DEBUG) << "idle maintenance started";
412*f40fafd4SAndroid Build Coastguard Worker
413*f40fafd4SAndroid Build Coastguard Worker auto wl = android::wakelock::WakeLock::tryGet(kWakeLock);
414*f40fafd4SAndroid Build Coastguard Worker if (!wl.has_value()) {
415*f40fafd4SAndroid Build Coastguard Worker return android::UNEXPECTED_NULL;
416*f40fafd4SAndroid Build Coastguard Worker }
417*f40fafd4SAndroid Build Coastguard Worker
418*f40fafd4SAndroid Build Coastguard Worker if (needGC) {
419*f40fafd4SAndroid Build Coastguard Worker std::list<std::string> paths;
420*f40fafd4SAndroid Build Coastguard Worker addFromFstab(&paths, PathTypes::kBlkDevice, false);
421*f40fafd4SAndroid Build Coastguard Worker addFromVolumeManager(&paths, PathTypes::kBlkDevice);
422*f40fafd4SAndroid Build Coastguard Worker
423*f40fafd4SAndroid Build Coastguard Worker startGc(paths);
424*f40fafd4SAndroid Build Coastguard Worker
425*f40fafd4SAndroid Build Coastguard Worker gc_aborted = waitForGc(paths);
426*f40fafd4SAndroid Build Coastguard Worker
427*f40fafd4SAndroid Build Coastguard Worker stopGc(paths);
428*f40fafd4SAndroid Build Coastguard Worker }
429*f40fafd4SAndroid Build Coastguard Worker
430*f40fafd4SAndroid Build Coastguard Worker if (!gc_aborted) {
431*f40fafd4SAndroid Build Coastguard Worker Trim(nullptr);
432*f40fafd4SAndroid Build Coastguard Worker runDevGc();
433*f40fafd4SAndroid Build Coastguard Worker }
434*f40fafd4SAndroid Build Coastguard Worker
435*f40fafd4SAndroid Build Coastguard Worker lk.lock();
436*f40fafd4SAndroid Build Coastguard Worker idle_maint_stat = IdleMaintStats::kStopped;
437*f40fafd4SAndroid Build Coastguard Worker lk.unlock();
438*f40fafd4SAndroid Build Coastguard Worker
439*f40fafd4SAndroid Build Coastguard Worker cv_stop.notify_all();
440*f40fafd4SAndroid Build Coastguard Worker
441*f40fafd4SAndroid Build Coastguard Worker if (listener) {
442*f40fafd4SAndroid Build Coastguard Worker android::os::PersistableBundle extras;
443*f40fafd4SAndroid Build Coastguard Worker listener->onFinished(0, extras);
444*f40fafd4SAndroid Build Coastguard Worker }
445*f40fafd4SAndroid Build Coastguard Worker
446*f40fafd4SAndroid Build Coastguard Worker LOG(DEBUG) << "idle maintenance completed";
447*f40fafd4SAndroid Build Coastguard Worker
448*f40fafd4SAndroid Build Coastguard Worker return android::OK;
449*f40fafd4SAndroid Build Coastguard Worker }
450*f40fafd4SAndroid Build Coastguard Worker
AbortIdleMaint(const android::sp<android::os::IVoldTaskListener> & listener)451*f40fafd4SAndroid Build Coastguard Worker int AbortIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener) {
452*f40fafd4SAndroid Build Coastguard Worker auto wl = android::wakelock::WakeLock::tryGet(kWakeLock);
453*f40fafd4SAndroid Build Coastguard Worker if (!wl.has_value()) {
454*f40fafd4SAndroid Build Coastguard Worker return android::UNEXPECTED_NULL;
455*f40fafd4SAndroid Build Coastguard Worker }
456*f40fafd4SAndroid Build Coastguard Worker
457*f40fafd4SAndroid Build Coastguard Worker std::unique_lock<std::mutex> lk(cv_m);
458*f40fafd4SAndroid Build Coastguard Worker if (idle_maint_stat != IdleMaintStats::kStopped) {
459*f40fafd4SAndroid Build Coastguard Worker idle_maint_stat = IdleMaintStats::kAbort;
460*f40fafd4SAndroid Build Coastguard Worker lk.unlock();
461*f40fafd4SAndroid Build Coastguard Worker cv_abort.notify_one();
462*f40fafd4SAndroid Build Coastguard Worker lk.lock();
463*f40fafd4SAndroid Build Coastguard Worker LOG(DEBUG) << "aborting idle maintenance";
464*f40fafd4SAndroid Build Coastguard Worker cv_stop.wait(lk, [] { return idle_maint_stat == IdleMaintStats::kStopped; });
465*f40fafd4SAndroid Build Coastguard Worker }
466*f40fafd4SAndroid Build Coastguard Worker lk.unlock();
467*f40fafd4SAndroid Build Coastguard Worker
468*f40fafd4SAndroid Build Coastguard Worker if (listener) {
469*f40fafd4SAndroid Build Coastguard Worker android::os::PersistableBundle extras;
470*f40fafd4SAndroid Build Coastguard Worker listener->onFinished(0, extras);
471*f40fafd4SAndroid Build Coastguard Worker }
472*f40fafd4SAndroid Build Coastguard Worker
473*f40fafd4SAndroid Build Coastguard Worker LOG(DEBUG) << "idle maintenance stopped";
474*f40fafd4SAndroid Build Coastguard Worker
475*f40fafd4SAndroid Build Coastguard Worker return android::OK;
476*f40fafd4SAndroid Build Coastguard Worker }
477*f40fafd4SAndroid Build Coastguard Worker
getLifeTime(const std::string & path)478*f40fafd4SAndroid Build Coastguard Worker int getLifeTime(const std::string& path) {
479*f40fafd4SAndroid Build Coastguard Worker std::string result;
480*f40fafd4SAndroid Build Coastguard Worker
481*f40fafd4SAndroid Build Coastguard Worker if (!ReadFileToString(path, &result)) {
482*f40fafd4SAndroid Build Coastguard Worker PLOG(WARNING) << "Reading lifetime estimation failed for " << path;
483*f40fafd4SAndroid Build Coastguard Worker return -1;
484*f40fafd4SAndroid Build Coastguard Worker }
485*f40fafd4SAndroid Build Coastguard Worker return std::stoi(result, 0, 16);
486*f40fafd4SAndroid Build Coastguard Worker }
487*f40fafd4SAndroid Build Coastguard Worker
GetStorageLifeTime()488*f40fafd4SAndroid Build Coastguard Worker int32_t GetStorageLifeTime() {
489*f40fafd4SAndroid Build Coastguard Worker std::string path = getDevSysfsPath();
490*f40fafd4SAndroid Build Coastguard Worker if (path.empty()) {
491*f40fafd4SAndroid Build Coastguard Worker return -1;
492*f40fafd4SAndroid Build Coastguard Worker }
493*f40fafd4SAndroid Build Coastguard Worker
494*f40fafd4SAndroid Build Coastguard Worker std::string lifeTimeBasePath = path + "/health_descriptor/life_time_estimation_";
495*f40fafd4SAndroid Build Coastguard Worker
496*f40fafd4SAndroid Build Coastguard Worker int32_t lifeTime = getLifeTime(lifeTimeBasePath + "c");
497*f40fafd4SAndroid Build Coastguard Worker if (lifeTime != -1) {
498*f40fafd4SAndroid Build Coastguard Worker return lifeTime;
499*f40fafd4SAndroid Build Coastguard Worker }
500*f40fafd4SAndroid Build Coastguard Worker
501*f40fafd4SAndroid Build Coastguard Worker int32_t lifeTimeA = getLifeTime(lifeTimeBasePath + "a");
502*f40fafd4SAndroid Build Coastguard Worker int32_t lifeTimeB = getLifeTime(lifeTimeBasePath + "b");
503*f40fafd4SAndroid Build Coastguard Worker lifeTime = std::max(lifeTimeA, lifeTimeB);
504*f40fafd4SAndroid Build Coastguard Worker if (lifeTime != -1) {
505*f40fafd4SAndroid Build Coastguard Worker return lifeTime == 0 ? -1 : lifeTime * 10;
506*f40fafd4SAndroid Build Coastguard Worker }
507*f40fafd4SAndroid Build Coastguard Worker return -1;
508*f40fafd4SAndroid Build Coastguard Worker }
509*f40fafd4SAndroid Build Coastguard Worker
GetStorageRemainingLifetime()510*f40fafd4SAndroid Build Coastguard Worker int32_t GetStorageRemainingLifetime() {
511*f40fafd4SAndroid Build Coastguard Worker std::string path = getDevSysfsPath();
512*f40fafd4SAndroid Build Coastguard Worker if (path.empty()) {
513*f40fafd4SAndroid Build Coastguard Worker return -1;
514*f40fafd4SAndroid Build Coastguard Worker }
515*f40fafd4SAndroid Build Coastguard Worker
516*f40fafd4SAndroid Build Coastguard Worker std::string lifeTimeBasePath = path + "/health_descriptor/life_time_estimation_";
517*f40fafd4SAndroid Build Coastguard Worker
518*f40fafd4SAndroid Build Coastguard Worker int32_t lifeTime = getLifeTime(lifeTimeBasePath + "c");
519*f40fafd4SAndroid Build Coastguard Worker if (lifeTime == -1) {
520*f40fafd4SAndroid Build Coastguard Worker int32_t lifeTimeA = getLifeTime(lifeTimeBasePath + "a");
521*f40fafd4SAndroid Build Coastguard Worker int32_t lifeTimeB = getLifeTime(lifeTimeBasePath + "b");
522*f40fafd4SAndroid Build Coastguard Worker lifeTime = std::max(lifeTimeA, lifeTimeB);
523*f40fafd4SAndroid Build Coastguard Worker if (lifeTime <= 0) {
524*f40fafd4SAndroid Build Coastguard Worker return -1;
525*f40fafd4SAndroid Build Coastguard Worker }
526*f40fafd4SAndroid Build Coastguard Worker
527*f40fafd4SAndroid Build Coastguard Worker // 1 = 0-10% used, 10 = 90-100% used. Subtract 1 so that a brand new
528*f40fafd4SAndroid Build Coastguard Worker // device looks 0% used.
529*f40fafd4SAndroid Build Coastguard Worker lifeTime = (lifeTime - 1) * 10;
530*f40fafd4SAndroid Build Coastguard Worker }
531*f40fafd4SAndroid Build Coastguard Worker return 100 - std::clamp(lifeTime, 0, 100);
532*f40fafd4SAndroid Build Coastguard Worker }
533*f40fafd4SAndroid Build Coastguard Worker
SetGCUrgentPace(int32_t neededSegments,int32_t minSegmentThreshold,float dirtyReclaimRate,float reclaimWeight,int32_t gcPeriod,int32_t minGCSleepTime,int32_t targetDirtyRatio)534*f40fafd4SAndroid Build Coastguard Worker void SetGCUrgentPace(int32_t neededSegments, int32_t minSegmentThreshold, float dirtyReclaimRate,
535*f40fafd4SAndroid Build Coastguard Worker float reclaimWeight, int32_t gcPeriod, int32_t minGCSleepTime,
536*f40fafd4SAndroid Build Coastguard Worker int32_t targetDirtyRatio) {
537*f40fafd4SAndroid Build Coastguard Worker std::list<std::string> paths;
538*f40fafd4SAndroid Build Coastguard Worker bool needGC = false;
539*f40fafd4SAndroid Build Coastguard Worker int32_t sleepTime;
540*f40fafd4SAndroid Build Coastguard Worker
541*f40fafd4SAndroid Build Coastguard Worker addFromFstab(&paths, PathTypes::kBlkDevice, true);
542*f40fafd4SAndroid Build Coastguard Worker if (paths.empty()) {
543*f40fafd4SAndroid Build Coastguard Worker LOG(WARNING) << "There is no valid blk device path for data partition";
544*f40fafd4SAndroid Build Coastguard Worker return;
545*f40fafd4SAndroid Build Coastguard Worker }
546*f40fafd4SAndroid Build Coastguard Worker
547*f40fafd4SAndroid Build Coastguard Worker std::string f2fsSysfsPath = paths.front();
548*f40fafd4SAndroid Build Coastguard Worker std::string freeSegmentsPath = f2fsSysfsPath + "/free_segments";
549*f40fafd4SAndroid Build Coastguard Worker std::string dirtySegmentsPath = f2fsSysfsPath + "/dirty_segments";
550*f40fafd4SAndroid Build Coastguard Worker std::string gcSleepTimePath = f2fsSysfsPath + "/gc_urgent_sleep_time";
551*f40fafd4SAndroid Build Coastguard Worker std::string gcUrgentModePath = f2fsSysfsPath + "/gc_urgent";
552*f40fafd4SAndroid Build Coastguard Worker std::string ovpSegmentsPath = f2fsSysfsPath + "/ovp_segments";
553*f40fafd4SAndroid Build Coastguard Worker std::string reservedBlocksPath = f2fsSysfsPath + "/reserved_blocks";
554*f40fafd4SAndroid Build Coastguard Worker std::string freeSegmentsStr, dirtySegmentsStr, ovpSegmentsStr, reservedBlocksStr;
555*f40fafd4SAndroid Build Coastguard Worker
556*f40fafd4SAndroid Build Coastguard Worker if (!ReadFileToString(freeSegmentsPath, &freeSegmentsStr)) {
557*f40fafd4SAndroid Build Coastguard Worker PLOG(WARNING) << "Reading failed in " << freeSegmentsPath;
558*f40fafd4SAndroid Build Coastguard Worker return;
559*f40fafd4SAndroid Build Coastguard Worker }
560*f40fafd4SAndroid Build Coastguard Worker
561*f40fafd4SAndroid Build Coastguard Worker if (!ReadFileToString(dirtySegmentsPath, &dirtySegmentsStr)) {
562*f40fafd4SAndroid Build Coastguard Worker PLOG(WARNING) << "Reading failed in " << dirtySegmentsPath;
563*f40fafd4SAndroid Build Coastguard Worker return;
564*f40fafd4SAndroid Build Coastguard Worker }
565*f40fafd4SAndroid Build Coastguard Worker
566*f40fafd4SAndroid Build Coastguard Worker if (!ReadFileToString(ovpSegmentsPath, &ovpSegmentsStr)) {
567*f40fafd4SAndroid Build Coastguard Worker PLOG(WARNING) << "Reading failed in " << ovpSegmentsPath;
568*f40fafd4SAndroid Build Coastguard Worker return;
569*f40fafd4SAndroid Build Coastguard Worker }
570*f40fafd4SAndroid Build Coastguard Worker
571*f40fafd4SAndroid Build Coastguard Worker if (!ReadFileToString(reservedBlocksPath, &reservedBlocksStr)) {
572*f40fafd4SAndroid Build Coastguard Worker PLOG(WARNING) << "Reading failed in " << reservedBlocksPath;
573*f40fafd4SAndroid Build Coastguard Worker return;
574*f40fafd4SAndroid Build Coastguard Worker }
575*f40fafd4SAndroid Build Coastguard Worker
576*f40fafd4SAndroid Build Coastguard Worker int32_t freeSegments = std::stoi(freeSegmentsStr);
577*f40fafd4SAndroid Build Coastguard Worker int32_t dirtySegments = std::stoi(dirtySegmentsStr);
578*f40fafd4SAndroid Build Coastguard Worker int32_t reservedSegments = std::stoi(ovpSegmentsStr) + std::stoi(reservedBlocksStr) / 512;
579*f40fafd4SAndroid Build Coastguard Worker
580*f40fafd4SAndroid Build Coastguard Worker freeSegments = freeSegments > reservedSegments ? freeSegments - reservedSegments : 0;
581*f40fafd4SAndroid Build Coastguard Worker int32_t totalSegments = freeSegments + dirtySegments;
582*f40fafd4SAndroid Build Coastguard Worker int32_t finalTargetSegments = 0;
583*f40fafd4SAndroid Build Coastguard Worker
584*f40fafd4SAndroid Build Coastguard Worker if (totalSegments < minSegmentThreshold) {
585*f40fafd4SAndroid Build Coastguard Worker LOG(INFO) << "The sum of free segments: " << freeSegments
586*f40fafd4SAndroid Build Coastguard Worker << ", dirty segments: " << dirtySegments << " is under " << minSegmentThreshold;
587*f40fafd4SAndroid Build Coastguard Worker } else {
588*f40fafd4SAndroid Build Coastguard Worker int32_t dirtyRatio = dirtySegments * 100 / totalSegments;
589*f40fafd4SAndroid Build Coastguard Worker int32_t neededForTargetRatio =
590*f40fafd4SAndroid Build Coastguard Worker (dirtyRatio > targetDirtyRatio)
591*f40fafd4SAndroid Build Coastguard Worker ? totalSegments * (dirtyRatio - targetDirtyRatio) / 100
592*f40fafd4SAndroid Build Coastguard Worker : 0;
593*f40fafd4SAndroid Build Coastguard Worker neededSegments *= reclaimWeight;
594*f40fafd4SAndroid Build Coastguard Worker neededSegments = (neededSegments > freeSegments) ? neededSegments - freeSegments : 0;
595*f40fafd4SAndroid Build Coastguard Worker
596*f40fafd4SAndroid Build Coastguard Worker finalTargetSegments = std::max(neededSegments, neededForTargetRatio);
597*f40fafd4SAndroid Build Coastguard Worker if (finalTargetSegments == 0) {
598*f40fafd4SAndroid Build Coastguard Worker LOG(INFO) << "Enough free segments: " << freeSegments;
599*f40fafd4SAndroid Build Coastguard Worker } else {
600*f40fafd4SAndroid Build Coastguard Worker finalTargetSegments =
601*f40fafd4SAndroid Build Coastguard Worker std::min(finalTargetSegments, (int32_t)(dirtySegments * dirtyReclaimRate));
602*f40fafd4SAndroid Build Coastguard Worker if (finalTargetSegments == 0) {
603*f40fafd4SAndroid Build Coastguard Worker LOG(INFO) << "Low dirty segments: " << dirtySegments;
604*f40fafd4SAndroid Build Coastguard Worker } else if (neededSegments >= neededForTargetRatio) {
605*f40fafd4SAndroid Build Coastguard Worker LOG(INFO) << "Trigger GC, because of needed segments exceeding free segments";
606*f40fafd4SAndroid Build Coastguard Worker needGC = true;
607*f40fafd4SAndroid Build Coastguard Worker } else {
608*f40fafd4SAndroid Build Coastguard Worker LOG(INFO) << "Trigger GC for target dirty ratio diff of: "
609*f40fafd4SAndroid Build Coastguard Worker << dirtyRatio - targetDirtyRatio;
610*f40fafd4SAndroid Build Coastguard Worker needGC = true;
611*f40fafd4SAndroid Build Coastguard Worker }
612*f40fafd4SAndroid Build Coastguard Worker }
613*f40fafd4SAndroid Build Coastguard Worker }
614*f40fafd4SAndroid Build Coastguard Worker
615*f40fafd4SAndroid Build Coastguard Worker if (!needGC) {
616*f40fafd4SAndroid Build Coastguard Worker if (!WriteStringToFile(std::to_string(GC_NORMAL_MODE), gcUrgentModePath)) {
617*f40fafd4SAndroid Build Coastguard Worker PLOG(WARNING) << "Writing failed in " << gcUrgentModePath;
618*f40fafd4SAndroid Build Coastguard Worker }
619*f40fafd4SAndroid Build Coastguard Worker return;
620*f40fafd4SAndroid Build Coastguard Worker }
621*f40fafd4SAndroid Build Coastguard Worker
622*f40fafd4SAndroid Build Coastguard Worker sleepTime = gcPeriod * ONE_MINUTE_IN_MS / finalTargetSegments;
623*f40fafd4SAndroid Build Coastguard Worker if (sleepTime < minGCSleepTime) {
624*f40fafd4SAndroid Build Coastguard Worker sleepTime = minGCSleepTime;
625*f40fafd4SAndroid Build Coastguard Worker }
626*f40fafd4SAndroid Build Coastguard Worker
627*f40fafd4SAndroid Build Coastguard Worker if (!WriteStringToFile(std::to_string(sleepTime), gcSleepTimePath)) {
628*f40fafd4SAndroid Build Coastguard Worker PLOG(WARNING) << "Writing failed in " << gcSleepTimePath;
629*f40fafd4SAndroid Build Coastguard Worker return;
630*f40fafd4SAndroid Build Coastguard Worker }
631*f40fafd4SAndroid Build Coastguard Worker
632*f40fafd4SAndroid Build Coastguard Worker if (!WriteStringToFile(std::to_string(GC_URGENT_MID_MODE), gcUrgentModePath)) {
633*f40fafd4SAndroid Build Coastguard Worker PLOG(WARNING) << "Writing failed in " << gcUrgentModePath;
634*f40fafd4SAndroid Build Coastguard Worker return;
635*f40fafd4SAndroid Build Coastguard Worker }
636*f40fafd4SAndroid Build Coastguard Worker
637*f40fafd4SAndroid Build Coastguard Worker LOG(INFO) << "Successfully set gc urgent mode: "
638*f40fafd4SAndroid Build Coastguard Worker << "free segments: " << freeSegments << ", reclaim target: " << finalTargetSegments
639*f40fafd4SAndroid Build Coastguard Worker << ", sleep time: " << sleepTime;
640*f40fafd4SAndroid Build Coastguard Worker }
641*f40fafd4SAndroid Build Coastguard Worker
getLifeTimeWrite()642*f40fafd4SAndroid Build Coastguard Worker static int32_t getLifeTimeWrite() {
643*f40fafd4SAndroid Build Coastguard Worker std::list<std::string> paths;
644*f40fafd4SAndroid Build Coastguard Worker addFromFstab(&paths, PathTypes::kBlkDevice, true);
645*f40fafd4SAndroid Build Coastguard Worker if (paths.empty()) {
646*f40fafd4SAndroid Build Coastguard Worker LOG(WARNING) << "There is no valid blk device path for data partition";
647*f40fafd4SAndroid Build Coastguard Worker return -1;
648*f40fafd4SAndroid Build Coastguard Worker }
649*f40fafd4SAndroid Build Coastguard Worker
650*f40fafd4SAndroid Build Coastguard Worker std::string writeKbytesPath = paths.front() + "/lifetime_write_kbytes";
651*f40fafd4SAndroid Build Coastguard Worker std::string writeKbytesStr;
652*f40fafd4SAndroid Build Coastguard Worker if (!ReadFileToString(writeKbytesPath, &writeKbytesStr)) {
653*f40fafd4SAndroid Build Coastguard Worker PLOG(WARNING) << "Reading failed in " << writeKbytesPath;
654*f40fafd4SAndroid Build Coastguard Worker return -1;
655*f40fafd4SAndroid Build Coastguard Worker }
656*f40fafd4SAndroid Build Coastguard Worker
657*f40fafd4SAndroid Build Coastguard Worker unsigned long long writeBytes = std::strtoull(writeKbytesStr.c_str(), NULL, 0);
658*f40fafd4SAndroid Build Coastguard Worker /* Careful: values > LLONG_MAX can appear in the file due to a kernel bug. */
659*f40fafd4SAndroid Build Coastguard Worker if (writeBytes / KBYTES_IN_SEGMENT > INT32_MAX) {
660*f40fafd4SAndroid Build Coastguard Worker LOG(WARNING) << "Bad lifetime_write_kbytes: " << writeKbytesStr;
661*f40fafd4SAndroid Build Coastguard Worker return -1;
662*f40fafd4SAndroid Build Coastguard Worker }
663*f40fafd4SAndroid Build Coastguard Worker return writeBytes / KBYTES_IN_SEGMENT;
664*f40fafd4SAndroid Build Coastguard Worker }
665*f40fafd4SAndroid Build Coastguard Worker
RefreshLatestWrite()666*f40fafd4SAndroid Build Coastguard Worker void RefreshLatestWrite() {
667*f40fafd4SAndroid Build Coastguard Worker int32_t segmentWrite = getLifeTimeWrite();
668*f40fafd4SAndroid Build Coastguard Worker if (segmentWrite != -1) {
669*f40fafd4SAndroid Build Coastguard Worker previousSegmentWrite = segmentWrite;
670*f40fafd4SAndroid Build Coastguard Worker }
671*f40fafd4SAndroid Build Coastguard Worker }
672*f40fafd4SAndroid Build Coastguard Worker
GetWriteAmount()673*f40fafd4SAndroid Build Coastguard Worker int32_t GetWriteAmount() {
674*f40fafd4SAndroid Build Coastguard Worker int32_t currentSegmentWrite = getLifeTimeWrite();
675*f40fafd4SAndroid Build Coastguard Worker if (currentSegmentWrite == -1) {
676*f40fafd4SAndroid Build Coastguard Worker return -1;
677*f40fafd4SAndroid Build Coastguard Worker }
678*f40fafd4SAndroid Build Coastguard Worker
679*f40fafd4SAndroid Build Coastguard Worker int32_t writeAmount = currentSegmentWrite - previousSegmentWrite;
680*f40fafd4SAndroid Build Coastguard Worker previousSegmentWrite = currentSegmentWrite;
681*f40fafd4SAndroid Build Coastguard Worker return writeAmount;
682*f40fafd4SAndroid Build Coastguard Worker }
683*f40fafd4SAndroid Build Coastguard Worker
684*f40fafd4SAndroid Build Coastguard Worker } // namespace vold
685*f40fafd4SAndroid Build Coastguard Worker } // namespace android
686