libprocessgroup: Use WriteStringToFd for WriteFileAction
Using WriteStringToFile will hold kernfs_mutex which is a big lock,
so use WriteStringToFd instead. Besides, also support fd cache for it.
Bug: 206970384
Test: build pass
Change-Id: Id79f9e1095f52079393c58edb9a4d526f4cc6b5e
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index e935f99..3834f91 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -144,30 +144,13 @@
return true;
}
-bool SetCgroupAction::IsAppDependentPath(const std::string& path) {
- return path.find("<uid>", 0) != std::string::npos || path.find("<pid>", 0) != std::string::npos;
-}
-
-SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p)
- : controller_(c), path_(p) {
- // file descriptors for app-dependent paths can't be cached
- if (IsAppDependentPath(path_)) {
- // file descriptor is not cached
- fd_.reset(FDS_APP_DEPENDENT);
- return;
- }
-
- // file descriptor can be cached later on request
- fd_.reset(FDS_NOT_CACHED);
-}
-
-void SetCgroupAction::EnableResourceCaching() {
+void CachedFdProfileAction::EnableResourceCaching() {
std::lock_guard<std::mutex> lock(fd_mutex_);
if (fd_ != FDS_NOT_CACHED) {
return;
}
- std::string tasks_path = controller_.GetTasksFilePath(path_);
+ std::string tasks_path = GetPath();
if (access(tasks_path.c_str(), W_OK) != 0) {
// file is not accessible
@@ -185,7 +168,7 @@
fd_ = std::move(fd);
}
-void SetCgroupAction::DropResourceCaching() {
+void CachedFdProfileAction::DropResourceCaching() {
std::lock_guard<std::mutex> lock(fd_mutex_);
if (fd_ == FDS_NOT_CACHED) {
return;
@@ -194,6 +177,26 @@
fd_.reset(FDS_NOT_CACHED);
}
+bool CachedFdProfileAction::IsAppDependentPath(const std::string& path) {
+ return path.find("<uid>", 0) != std::string::npos || path.find("<pid>", 0) != std::string::npos;
+}
+
+void CachedFdProfileAction::InitFd(const std::string& path) {
+ // file descriptors for app-dependent paths can't be cached
+ if (IsAppDependentPath(path)) {
+ // file descriptor is not cached
+ fd_.reset(FDS_APP_DEPENDENT);
+ return;
+ }
+ // file descriptor can be cached later on request
+ fd_.reset(FDS_NOT_CACHED);
+}
+
+SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p)
+ : controller_(c), path_(p) {
+ InitFd(controller_.GetTasksFilePath(path_));
+}
+
bool SetCgroupAction::AddTidToCgroup(int tid, int fd, const char* controller_name) {
if (tid <= 0) {
return true;
@@ -270,7 +273,7 @@
std::string tasks_path = controller()->GetTasksFilePath(path_);
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
- PLOG(WARNING) << "Failed to open " << tasks_path << ": " << strerror(errno);
+ PLOG(WARNING) << "Failed to open " << tasks_path;
return false;
}
if (!AddTidToCgroup(tid, tmp_fd, controller()->name())) {
@@ -281,37 +284,73 @@
return true;
}
-bool WriteFileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
- std::string filepath(filepath_), value(value_);
+WriteFileAction::WriteFileAction(const std::string& path, const std::string& value,
+ bool logfailures)
+ : path_(path), value_(value), logfailures_(logfailures) {
+ InitFd(path_);
+}
- filepath = StringReplace(filepath, "<uid>", std::to_string(uid), true);
- filepath = StringReplace(filepath, "<pid>", std::to_string(pid), true);
- value = StringReplace(value, "<uid>", std::to_string(uid), true);
- value = StringReplace(value, "<pid>", std::to_string(pid), true);
+bool WriteFileAction::WriteValueToFile(const std::string& value, const std::string& path,
+ bool logfailures) {
+ // Use WriteStringToFd instead of WriteStringToFile because the latter will open file with
+ // O_TRUNC which causes kernfs_mutex contention
+ unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CLOEXEC)));
- if (!WriteStringToFile(value, filepath)) {
- if (logfailures_) PLOG(ERROR) << "Failed to write '" << value << "' to " << filepath;
+ if (tmp_fd < 0) {
+ if (logfailures) PLOG(WARNING) << "Failed to open " << path;
+ return false;
+ }
+
+ if (!WriteStringToFd(value, tmp_fd)) {
+ if (logfailures) PLOG(ERROR) << "Failed to write '" << value << "' to " << path;
return false;
}
return true;
}
+bool WriteFileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ std::string value(value_);
+ std::string path(path_);
+
+ value = StringReplace(value, "<uid>", std::to_string(uid), true);
+ value = StringReplace(value, "<pid>", std::to_string(pid), true);
+ path = StringReplace(path, "<uid>", std::to_string(uid), true);
+ path = StringReplace(path, "<pid>", std::to_string(pid), true);
+
+ return WriteValueToFile(value, path, logfailures_);
+}
+
bool WriteFileAction::ExecuteForTask(int tid) const {
- std::string filepath(filepath_), value(value_);
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ std::string value(value_);
int uid = getuid();
- filepath = StringReplace(filepath, "<uid>", std::to_string(uid), true);
- filepath = StringReplace(filepath, "<pid>", std::to_string(tid), true);
value = StringReplace(value, "<uid>", std::to_string(uid), true);
value = StringReplace(value, "<pid>", std::to_string(tid), true);
- if (!WriteStringToFile(value, filepath)) {
- if (logfailures_) PLOG(ERROR) << "Failed to write '" << value << "' to " << filepath;
+ if (IsFdValid()) {
+ // fd is cached, reuse it
+ if (!WriteStringToFd(value, fd_)) {
+ if (logfailures_) PLOG(ERROR) << "Failed to write '" << value << "' to " << path_;
+ return false;
+ }
+ return true;
+ }
+
+ if (fd_ == FDS_INACCESSIBLE) {
+ // no permissions to access the file, ignore
+ return true;
+ }
+
+ if (fd_ == FDS_APP_DEPENDENT) {
+ // application-dependent path can't be used with tid
+ PLOG(ERROR) << "Application profile can't be applied to a thread";
return false;
}
- return true;
+ return WriteValueToFile(value, path_, logfailures_);
}
bool ApplyProfileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {