Merge "Add interfaces required by smart idle maintenance service"

This commit is contained in:
Daeho Jeong 2022-01-13 16:38:04 +00:00 committed by Gerrit Code Review
commit 6845e06ab9
5 changed files with 234 additions and 21 deletions

View file

@ -85,6 +85,13 @@ static const int DIRTY_SEGMENTS_THRESHOLD = 100;
*/ */
static const int GC_TIMEOUT_SEC = 420; static const int GC_TIMEOUT_SEC = 420;
static const int DEVGC_TIMEOUT_SEC = 120; static const int DEVGC_TIMEOUT_SEC = 120;
static const int KBYTES_IN_SEGMENT = 2048;
static const int MIN_GC_URGENT_SLEEP_TIME = 500;
static const int ONE_HOUR_IN_MS = 3600000;
static const int GC_NORMAL_MODE = 0;
static const int GC_URGENT_HIGH_MODE = 1;
static int32_t previousSegmentWrite = 0;
static IdleMaintStats idle_maint_stat(IdleMaintStats::kStopped); static IdleMaintStats idle_maint_stat(IdleMaintStats::kStopped);
static std::condition_variable cv_abort, cv_stop; static std::condition_variable cv_abort, cv_stop;
@ -111,7 +118,7 @@ static void addFromVolumeManager(std::list<std::string>* paths, PathTypes path_t
} }
} }
static void addFromFstab(std::list<std::string>* paths, PathTypes path_type) { static void addFromFstab(std::list<std::string>* paths, PathTypes path_type, bool only_data_part) {
std::string previous_mount_point; std::string previous_mount_point;
for (const auto& entry : fstab_default) { for (const auto& entry : fstab_default) {
// Skip raw partitions and swap space. // Skip raw partitions and swap space.
@ -133,6 +140,10 @@ static void addFromFstab(std::list<std::string>* paths, PathTypes path_type) {
continue; continue;
} }
if (only_data_part && entry.mount_point != "/data") {
continue;
}
// Skip the multi-type partitions, which are required to be following each other. // Skip the multi-type partitions, which are required to be following each other.
// See fs_mgr.c's mount_with_alternatives(). // See fs_mgr.c's mount_with_alternatives().
if (entry.mount_point == previous_mount_point) { if (entry.mount_point == previous_mount_point) {
@ -142,10 +153,10 @@ static void addFromFstab(std::list<std::string>* paths, PathTypes path_type) {
if (path_type == PathTypes::kMountPoint) { if (path_type == PathTypes::kMountPoint) {
paths->push_back(entry.mount_point); paths->push_back(entry.mount_point);
} else if (path_type == PathTypes::kBlkDevice) { } else if (path_type == PathTypes::kBlkDevice) {
std::string gc_path; std::string path;
if (entry.fs_type == "f2fs" && if (entry.fs_type == "f2fs" &&
Realpath(android::vold::BlockDeviceForPath(entry.mount_point + "/"), &gc_path)) { Realpath(android::vold::BlockDeviceForPath(entry.mount_point + "/"), &path)) {
paths->push_back("/sys/fs/" + entry.fs_type + "/" + Basename(gc_path)); paths->push_back("/sys/fs/" + entry.fs_type + "/" + Basename(path));
} }
} }
@ -161,7 +172,7 @@ void Trim(const android::sp<android::os::IVoldTaskListener>& listener) {
// Collect both fstab and vold volumes // Collect both fstab and vold volumes
std::list<std::string> paths; std::list<std::string> paths;
addFromFstab(&paths, PathTypes::kMountPoint); addFromFstab(&paths, PathTypes::kMountPoint, false);
addFromVolumeManager(&paths, PathTypes::kMountPoint); addFromVolumeManager(&paths, PathTypes::kMountPoint);
for (const auto& path : paths) { for (const auto& path : paths) {
@ -264,15 +275,18 @@ static int stopGc(const std::list<std::string>& paths) {
return android::OK; return android::OK;
} }
static void runDevGcFstab(void) { static std::string getDevSysfsPath() {
std::string path;
for (const auto& entry : fstab_default) { for (const auto& entry : fstab_default) {
if (!entry.sysfs_path.empty()) { if (!entry.sysfs_path.empty()) {
path = entry.sysfs_path; return entry.sysfs_path;
break;
} }
} }
LOG(WARNING) << "Cannot find dev sysfs path";
return "";
}
static void runDevGcFstab(void) {
std::string path = getDevSysfsPath();
if (path.empty()) { if (path.empty()) {
return; return;
} }
@ -402,8 +416,10 @@ static void runDevGc(void) {
runDevGcFstab(); runDevGcFstab();
} }
int RunIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener) { int RunIdleMaint(bool needGC, const android::sp<android::os::IVoldTaskListener>& listener) {
std::unique_lock<std::mutex> lk(cv_m); std::unique_lock<std::mutex> lk(cv_m);
bool gc_aborted = false;
if (idle_maint_stat != IdleMaintStats::kStopped) { if (idle_maint_stat != IdleMaintStats::kStopped) {
LOG(DEBUG) << "idle maintenance is already running"; LOG(DEBUG) << "idle maintenance is already running";
if (listener) { if (listener) {
@ -422,15 +438,17 @@ int RunIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener) {
return android::UNEXPECTED_NULL; return android::UNEXPECTED_NULL;
} }
std::list<std::string> paths; if (needGC) {
addFromFstab(&paths, PathTypes::kBlkDevice); std::list<std::string> paths;
addFromVolumeManager(&paths, PathTypes::kBlkDevice); addFromFstab(&paths, PathTypes::kBlkDevice, false);
addFromVolumeManager(&paths, PathTypes::kBlkDevice);
startGc(paths); startGc(paths);
bool gc_aborted = waitForGc(paths); gc_aborted = waitForGc(paths);
stopGc(paths); stopGc(paths);
}
lk.lock(); lk.lock();
idle_maint_stat = IdleMaintStats::kStopped; idle_maint_stat = IdleMaintStats::kStopped;
@ -480,5 +498,150 @@ int AbortIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener)
return android::OK; return android::OK;
} }
int getLifeTime(const std::string& path) {
std::string result;
if (!ReadFileToString(path, &result)) {
PLOG(WARNING) << "Reading lifetime estimation failed for " << path;
return -1;
}
return std::stoi(result, 0, 16);
}
int32_t GetStorageLifeTime() {
std::string path = getDevSysfsPath();
if (path.empty()) {
return -1;
}
std::string lifeTimeBasePath = path + "/health_descriptor/life_time_estimation_";
int32_t lifeTime = getLifeTime(lifeTimeBasePath + "c");
if (lifeTime != -1) {
return lifeTime;
}
int32_t lifeTimeA = getLifeTime(lifeTimeBasePath + "a");
int32_t lifeTimeB = getLifeTime(lifeTimeBasePath + "b");
lifeTime = std::max(lifeTimeA, lifeTimeB);
if (lifeTime != -1) {
return lifeTime == 0 ? -1 : lifeTime * 10;
}
return -1;
}
void SetGCUrgentPace(int32_t neededSegments, int32_t minSegmentThreshold, float dirtyReclaimRate,
float reclaimWeight) {
std::list<std::string> paths;
bool needGC = true;
addFromFstab(&paths, PathTypes::kBlkDevice, true);
if (paths.empty()) {
LOG(WARNING) << "There is no valid blk device path for data partition";
return;
}
std::string f2fsSysfsPath = paths.front();
std::string freeSegmentsPath = f2fsSysfsPath + "/free_segments";
std::string dirtySegmentsPath = f2fsSysfsPath + "/dirty_segments";
std::string gcSleepTimePath = f2fsSysfsPath + "/gc_urgent_sleep_time";
std::string gcUrgentModePath = f2fsSysfsPath + "/gc_urgent";
std::string freeSegmentsStr, dirtySegmentsStr;
if (!ReadFileToString(freeSegmentsPath, &freeSegmentsStr)) {
PLOG(WARNING) << "Reading failed in " << freeSegmentsPath;
return;
}
if (!ReadFileToString(dirtySegmentsPath, &dirtySegmentsStr)) {
PLOG(WARNING) << "Reading failed in " << dirtySegmentsPath;
return;
}
int32_t freeSegments = std::stoi(freeSegmentsStr);
int32_t dirtySegments = std::stoi(dirtySegmentsStr);
neededSegments *= reclaimWeight;
if (freeSegments >= neededSegments) {
LOG(INFO) << "Enough free segments: " << freeSegments
<< ", needed segments: " << neededSegments;
needGC = false;
} else if (freeSegments + dirtySegments < minSegmentThreshold) {
LOG(INFO) << "The sum of free segments: " << freeSegments
<< ", dirty segments: " << dirtySegments << " is under " << minSegmentThreshold;
needGC = false;
}
if (!needGC) {
if (!WriteStringToFile(std::to_string(GC_NORMAL_MODE), gcUrgentModePath)) {
PLOG(WARNING) << "Writing failed in " << gcUrgentModePath;
}
return;
}
int32_t sleepTime;
neededSegments -= freeSegments;
neededSegments = std::min(neededSegments, (int32_t)(dirtySegments * dirtyReclaimRate));
if (neededSegments == 0) {
sleepTime = MIN_GC_URGENT_SLEEP_TIME;
} else {
sleepTime = ONE_HOUR_IN_MS / neededSegments;
if (sleepTime < MIN_GC_URGENT_SLEEP_TIME) {
sleepTime = MIN_GC_URGENT_SLEEP_TIME;
}
}
if (!WriteStringToFile(std::to_string(sleepTime), gcSleepTimePath)) {
PLOG(WARNING) << "Writing failed in " << gcSleepTimePath;
return;
}
if (!WriteStringToFile(std::to_string(GC_URGENT_HIGH_MODE), gcUrgentModePath)) {
PLOG(WARNING) << "Writing failed in " << gcUrgentModePath;
return;
}
LOG(INFO) << "Successfully set gc urgent mode: "
<< "free segments: " << freeSegments << ", reclaim target: " << neededSegments
<< ", sleep time: " << sleepTime;
}
static int32_t getLifeTimeWrite() {
std::list<std::string> paths;
addFromFstab(&paths, PathTypes::kBlkDevice, true);
if (paths.empty()) {
LOG(WARNING) << "There is no valid blk device path for data partition";
return -1;
}
std::string writeKbytesPath = paths.front() + "/lifetime_write_kbytes";
std::string writeKbytesStr;
if (!ReadFileToString(writeKbytesPath, &writeKbytesStr)) {
PLOG(WARNING) << "Reading failed in " << writeKbytesPath;
return -1;
}
long long writeBytes = std::stoll(writeKbytesStr);
return writeBytes / KBYTES_IN_SEGMENT;
}
void RefreshLatestWrite() {
int32_t segmentWrite = getLifeTimeWrite();
if (segmentWrite != -1) {
previousSegmentWrite = segmentWrite;
}
}
int32_t GetWriteAmount() {
int32_t currentSegmentWrite = getLifeTimeWrite();
if (currentSegmentWrite == -1) {
return -1;
}
int32_t writeAmount = currentSegmentWrite - previousSegmentWrite;
previousSegmentWrite = currentSegmentWrite;
return writeAmount;
}
} // namespace vold } // namespace vold
} // namespace android } // namespace android

View file

@ -23,8 +23,13 @@ namespace android {
namespace vold { namespace vold {
void Trim(const android::sp<android::os::IVoldTaskListener>& listener); void Trim(const android::sp<android::os::IVoldTaskListener>& listener);
int RunIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener); int RunIdleMaint(bool needGC, const android::sp<android::os::IVoldTaskListener>& listener);
int AbortIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener); int AbortIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener);
int32_t GetStorageLifeTime();
void SetGCUrgentPace(int32_t neededSegments, int32_t minSegmentThreshold, float dirtyReclaimRate,
float reclaimWeight);
void RefreshLatestWrite();
int32_t GetWriteAmount();
} // namespace vold } // namespace vold
} // namespace android } // namespace android

View file

@ -470,11 +470,11 @@ binder::Status VoldNativeService::fstrim(
} }
binder::Status VoldNativeService::runIdleMaint( binder::Status VoldNativeService::runIdleMaint(
const android::sp<android::os::IVoldTaskListener>& listener) { bool needGC, const android::sp<android::os::IVoldTaskListener>& listener) {
ENFORCE_SYSTEM_OR_ROOT; ENFORCE_SYSTEM_OR_ROOT;
ACQUIRE_LOCK; ACQUIRE_LOCK;
std::thread([=]() { android::vold::RunIdleMaint(listener); }).detach(); std::thread([=]() { android::vold::RunIdleMaint(needGC, listener); }).detach();
return Ok(); return Ok();
} }
@ -487,6 +487,40 @@ binder::Status VoldNativeService::abortIdleMaint(
return Ok(); return Ok();
} }
binder::Status VoldNativeService::getStorageLifeTime(int32_t* _aidl_return) {
ENFORCE_SYSTEM_OR_ROOT;
ACQUIRE_LOCK;
*_aidl_return = GetStorageLifeTime();
return Ok();
}
binder::Status VoldNativeService::setGCUrgentPace(int32_t neededSegments,
int32_t minSegmentThreshold,
float dirtyReclaimRate, float reclaimWeight) {
ENFORCE_SYSTEM_OR_ROOT;
ACQUIRE_LOCK;
SetGCUrgentPace(neededSegments, minSegmentThreshold, dirtyReclaimRate, reclaimWeight);
return Ok();
}
binder::Status VoldNativeService::refreshLatestWrite() {
ENFORCE_SYSTEM_OR_ROOT;
ACQUIRE_LOCK;
RefreshLatestWrite();
return Ok();
}
binder::Status VoldNativeService::getWriteAmount(int32_t* _aidl_return) {
ENFORCE_SYSTEM_OR_ROOT;
ACQUIRE_LOCK;
*_aidl_return = GetWriteAmount();
return Ok();
}
binder::Status VoldNativeService::mountAppFuse(int32_t uid, int32_t mountId, binder::Status VoldNativeService::mountAppFuse(int32_t uid, int32_t mountId,
android::base::unique_fd* _aidl_return) { android::base::unique_fd* _aidl_return) {
ENFORCE_SYSTEM_OR_ROOT; ENFORCE_SYSTEM_OR_ROOT;

View file

@ -85,8 +85,14 @@ class VoldNativeService : public BinderService<VoldNativeService>, public os::Bn
binder::Status fstrim(int32_t fstrimFlags, binder::Status fstrim(int32_t fstrimFlags,
const android::sp<android::os::IVoldTaskListener>& listener); const android::sp<android::os::IVoldTaskListener>& listener);
binder::Status runIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener); binder::Status runIdleMaint(bool needGC,
const android::sp<android::os::IVoldTaskListener>& listener);
binder::Status abortIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener); binder::Status abortIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener);
binder::Status getStorageLifeTime(int32_t* _aidl_return);
binder::Status setGCUrgentPace(int32_t neededSegments, int32_t minSegmentThreshold,
float dirtyReclaimRate, float reclaimWeight);
binder::Status refreshLatestWrite();
binder::Status getWriteAmount(int32_t* _aidl_return);
binder::Status mountAppFuse(int32_t uid, int32_t mountId, binder::Status mountAppFuse(int32_t uid, int32_t mountId,
android::base::unique_fd* _aidl_return); android::base::unique_fd* _aidl_return);

View file

@ -65,8 +65,13 @@ interface IVold {
void destroyObb(@utf8InCpp String volId); void destroyObb(@utf8InCpp String volId);
void fstrim(int fstrimFlags, IVoldTaskListener listener); void fstrim(int fstrimFlags, IVoldTaskListener listener);
void runIdleMaint(IVoldTaskListener listener); void runIdleMaint(boolean needGC, IVoldTaskListener listener);
void abortIdleMaint(IVoldTaskListener listener); void abortIdleMaint(IVoldTaskListener listener);
int getStorageLifeTime();
void setGCUrgentPace(int neededSegments, int minSegmentThreshold,
float dirtyReclaimRate, float reclaimWeight);
void refreshLatestWrite();
int getWriteAmount();
FileDescriptor mountAppFuse(int uid, int mountId); FileDescriptor mountAppFuse(int uid, int mountId);
void unmountAppFuse(int uid, int mountId); void unmountAppFuse(int uid, int mountId);