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 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 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;
for (const auto& entry : fstab_default) {
// Skip raw partitions and swap space.
@ -133,6 +140,10 @@ static void addFromFstab(std::list<std::string>* paths, PathTypes path_type) {
continue;
}
if (only_data_part && entry.mount_point != "/data") {
continue;
}
// Skip the multi-type partitions, which are required to be following each other.
// See fs_mgr.c's mount_with_alternatives().
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) {
paths->push_back(entry.mount_point);
} else if (path_type == PathTypes::kBlkDevice) {
std::string gc_path;
std::string path;
if (entry.fs_type == "f2fs" &&
Realpath(android::vold::BlockDeviceForPath(entry.mount_point + "/"), &gc_path)) {
paths->push_back("/sys/fs/" + entry.fs_type + "/" + Basename(gc_path));
Realpath(android::vold::BlockDeviceForPath(entry.mount_point + "/"), &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
std::list<std::string> paths;
addFromFstab(&paths, PathTypes::kMountPoint);
addFromFstab(&paths, PathTypes::kMountPoint, false);
addFromVolumeManager(&paths, PathTypes::kMountPoint);
for (const auto& path : paths) {
@ -264,15 +275,18 @@ static int stopGc(const std::list<std::string>& paths) {
return android::OK;
}
static void runDevGcFstab(void) {
std::string path;
static std::string getDevSysfsPath() {
for (const auto& entry : fstab_default) {
if (!entry.sysfs_path.empty()) {
path = entry.sysfs_path;
break;
return entry.sysfs_path;
}
}
LOG(WARNING) << "Cannot find dev sysfs path";
return "";
}
static void runDevGcFstab(void) {
std::string path = getDevSysfsPath();
if (path.empty()) {
return;
}
@ -402,8 +416,10 @@ static void runDevGc(void) {
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);
bool gc_aborted = false;
if (idle_maint_stat != IdleMaintStats::kStopped) {
LOG(DEBUG) << "idle maintenance is already running";
if (listener) {
@ -422,15 +438,17 @@ int RunIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener) {
return android::UNEXPECTED_NULL;
}
std::list<std::string> paths;
addFromFstab(&paths, PathTypes::kBlkDevice);
addFromVolumeManager(&paths, PathTypes::kBlkDevice);
if (needGC) {
std::list<std::string> paths;
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();
idle_maint_stat = IdleMaintStats::kStopped;
@ -480,5 +498,150 @@ int AbortIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener)
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 android

View file

@ -23,8 +23,13 @@ namespace android {
namespace vold {
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);
int32_t GetStorageLifeTime();
void SetGCUrgentPace(int32_t neededSegments, int32_t minSegmentThreshold, float dirtyReclaimRate,
float reclaimWeight);
void RefreshLatestWrite();
int32_t GetWriteAmount();
} // namespace vold
} // namespace android

View file

@ -470,11 +470,11 @@ binder::Status VoldNativeService::fstrim(
}
binder::Status VoldNativeService::runIdleMaint(
const android::sp<android::os::IVoldTaskListener>& listener) {
bool needGC, const android::sp<android::os::IVoldTaskListener>& listener) {
ENFORCE_SYSTEM_OR_ROOT;
ACQUIRE_LOCK;
std::thread([=]() { android::vold::RunIdleMaint(listener); }).detach();
std::thread([=]() { android::vold::RunIdleMaint(needGC, listener); }).detach();
return Ok();
}
@ -487,6 +487,40 @@ binder::Status VoldNativeService::abortIdleMaint(
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,
android::base::unique_fd* _aidl_return) {
ENFORCE_SYSTEM_OR_ROOT;

View file

@ -85,8 +85,14 @@ class VoldNativeService : public BinderService<VoldNativeService>, public os::Bn
binder::Status fstrim(int32_t fstrimFlags,
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 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,
android::base::unique_fd* _aidl_return);

View file

@ -65,8 +65,13 @@ interface IVold {
void destroyObb(@utf8InCpp String volId);
void fstrim(int fstrimFlags, IVoldTaskListener listener);
void runIdleMaint(IVoldTaskListener listener);
void runIdleMaint(boolean needGC, 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);
void unmountAppFuse(int uid, int mountId);