Merge "libprocessgroup: Rework SetupCgroup()" am: d35f56b199 am: 7e1218646c
Original change: https://android-review.googlesource.com/c/platform/system/core/+/2424612 Change-Id: If317974694502679a68947c2688f632f2080d0be Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
5ff1e5353d
1 changed files with 100 additions and 73 deletions
|
|
@ -254,86 +254,64 @@ static bool ReadDescriptors(std::map<std::string, CgroupDescriptor>* descriptors
|
||||||
// To avoid issues in sdk_mac build
|
// To avoid issues in sdk_mac build
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
|
|
||||||
static bool SetupCgroup(const CgroupDescriptor& descriptor) {
|
static bool IsOptionalController(const format::CgroupController* controller) {
|
||||||
|
return controller->flags() & CGROUPRC_CONTROLLER_FLAG_OPTIONAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool MountV2CgroupController(const CgroupDescriptor& descriptor) {
|
||||||
const format::CgroupController* controller = descriptor.controller();
|
const format::CgroupController* controller = descriptor.controller();
|
||||||
|
|
||||||
int result;
|
// /sys/fs/cgroup is created by cgroup2 with specific selinux permissions,
|
||||||
if (controller->version() == 2) {
|
// try to create again in case the mount point is changed
|
||||||
result = 0;
|
if (!Mkdir(controller->path(), 0, "", "")) {
|
||||||
if (!strcmp(controller->name(), CGROUPV2_CONTROLLER_NAME)) {
|
LOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup";
|
||||||
// /sys/fs/cgroup is created by cgroup2 with specific selinux permissions,
|
return false;
|
||||||
// try to create again in case the mount point is changed
|
}
|
||||||
if (!Mkdir(controller->path(), 0, "", "")) {
|
|
||||||
LOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The memory_recursiveprot mount option has been introduced by kernel commit
|
// The memory_recursiveprot mount option has been introduced by kernel commit
|
||||||
// 8a931f801340 ("mm: memcontrol: recursive memory.low protection"; v5.7). Try first to
|
// 8a931f801340 ("mm: memcontrol: recursive memory.low protection"; v5.7). Try first to
|
||||||
// mount with that option enabled. If mounting fails because the kernel is too old,
|
// mount with that option enabled. If mounting fails because the kernel is too old,
|
||||||
// retry without that mount option.
|
// retry without that mount option.
|
||||||
if (mount("none", controller->path(), "cgroup2", MS_NODEV | MS_NOEXEC | MS_NOSUID,
|
if (mount("none", controller->path(), "cgroup2", MS_NODEV | MS_NOEXEC | MS_NOSUID,
|
||||||
"memory_recursiveprot") < 0) {
|
"memory_recursiveprot") < 0) {
|
||||||
LOG(INFO) << "Mounting memcg with memory_recursiveprot failed. Retrying without.";
|
LOG(INFO) << "Mounting memcg with memory_recursiveprot failed. Retrying without.";
|
||||||
if (mount("none", controller->path(), "cgroup2", MS_NODEV | MS_NOEXEC | MS_NOSUID,
|
if (mount("none", controller->path(), "cgroup2", MS_NODEV | MS_NOEXEC | MS_NOSUID,
|
||||||
nullptr) < 0) {
|
nullptr) < 0) {
|
||||||
PLOG(ERROR) << "Failed to mount cgroup v2";
|
PLOG(ERROR) << "Failed to mount cgroup v2";
|
||||||
}
|
return IsOptionalController(controller);
|
||||||
}
|
|
||||||
|
|
||||||
// selinux permissions change after mounting, so it's ok to change mode and owner now
|
|
||||||
if (!ChangeDirModeAndOwner(controller->path(), descriptor.mode(), descriptor.uid(),
|
|
||||||
descriptor.gid())) {
|
|
||||||
LOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup";
|
|
||||||
result = -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!Mkdir(controller->path(), descriptor.mode(), descriptor.uid(), descriptor.gid())) {
|
|
||||||
LOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (controller->flags() & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION) {
|
|
||||||
std::string str = std::string("+") + controller->name();
|
|
||||||
std::string path = std::string(controller->path()) + "/cgroup.subtree_control";
|
|
||||||
|
|
||||||
if (!base::WriteStringToFile(str, path)) {
|
|
||||||
LOG(ERROR) << "Failed to activate controller " << controller->name();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// mkdir <path> [mode] [owner] [group]
|
|
||||||
if (!Mkdir(controller->path(), descriptor.mode(), descriptor.uid(), descriptor.gid())) {
|
|
||||||
LOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unfortunately historically cpuset controller was mounted using a mount command
|
|
||||||
// different from all other controllers. This results in controller attributes not
|
|
||||||
// to be prepended with controller name. For example this way instead of
|
|
||||||
// /dev/cpuset/cpuset.cpus the attribute becomes /dev/cpuset/cpus which is what
|
|
||||||
// the system currently expects.
|
|
||||||
if (!strcmp(controller->name(), "cpuset")) {
|
|
||||||
// mount cpuset none /dev/cpuset nodev noexec nosuid
|
|
||||||
result = mount("none", controller->path(), controller->name(),
|
|
||||||
MS_NODEV | MS_NOEXEC | MS_NOSUID, nullptr);
|
|
||||||
} else {
|
|
||||||
// mount cgroup none <path> nodev noexec nosuid <controller>
|
|
||||||
result = mount("none", controller->path(), "cgroup", MS_NODEV | MS_NOEXEC | MS_NOSUID,
|
|
||||||
controller->name());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result < 0) {
|
// selinux permissions change after mounting, so it's ok to change mode and owner now
|
||||||
bool optional = controller->flags() & CGROUPRC_CONTROLLER_FLAG_OPTIONAL;
|
if (!ChangeDirModeAndOwner(controller->path(), descriptor.mode(), descriptor.uid(),
|
||||||
|
descriptor.gid())) {
|
||||||
|
PLOG(ERROR) << "Change of ownership or mode failed for controller " << controller->name();
|
||||||
|
return IsOptionalController(controller);
|
||||||
|
}
|
||||||
|
|
||||||
if (optional && errno == EINVAL) {
|
return true;
|
||||||
// Optional controllers are allowed to fail to mount if kernel does not support them
|
}
|
||||||
LOG(INFO) << "Optional " << controller->name() << " cgroup controller is not mounted";
|
|
||||||
} else {
|
static bool ActivateV2CgroupController(const CgroupDescriptor& descriptor) {
|
||||||
PLOG(ERROR) << "Failed to mount " << controller->name() << " cgroup";
|
const format::CgroupController* controller = descriptor.controller();
|
||||||
|
|
||||||
|
if (!Mkdir(controller->path(), descriptor.mode(), descriptor.uid(), descriptor.gid())) {
|
||||||
|
LOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controller->flags() & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION) {
|
||||||
|
std::string str = "+";
|
||||||
|
str += controller->name();
|
||||||
|
std::string path = controller->path();
|
||||||
|
path += "/cgroup.subtree_control";
|
||||||
|
|
||||||
|
if (!base::WriteStringToFile(str, path)) {
|
||||||
|
if (IsOptionalController(controller)) {
|
||||||
|
PLOG(INFO) << "Failed to activate optional controller " << controller->name();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
PLOG(ERROR) << "Failed to activate controller " << controller->name();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -341,6 +319,55 @@ static bool SetupCgroup(const CgroupDescriptor& descriptor) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool MountV1CgroupController(const CgroupDescriptor& descriptor) {
|
||||||
|
const format::CgroupController* controller = descriptor.controller();
|
||||||
|
|
||||||
|
// mkdir <path> [mode] [owner] [group]
|
||||||
|
if (!Mkdir(controller->path(), descriptor.mode(), descriptor.uid(), descriptor.gid())) {
|
||||||
|
LOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unfortunately historically cpuset controller was mounted using a mount command
|
||||||
|
// different from all other controllers. This results in controller attributes not
|
||||||
|
// to be prepended with controller name. For example this way instead of
|
||||||
|
// /dev/cpuset/cpuset.cpus the attribute becomes /dev/cpuset/cpus which is what
|
||||||
|
// the system currently expects.
|
||||||
|
int res;
|
||||||
|
if (!strcmp(controller->name(), "cpuset")) {
|
||||||
|
// mount cpuset none /dev/cpuset nodev noexec nosuid
|
||||||
|
res = mount("none", controller->path(), controller->name(),
|
||||||
|
MS_NODEV | MS_NOEXEC | MS_NOSUID, nullptr);
|
||||||
|
} else {
|
||||||
|
// mount cgroup none <path> nodev noexec nosuid <controller>
|
||||||
|
res = mount("none", controller->path(), "cgroup", MS_NODEV | MS_NOEXEC | MS_NOSUID,
|
||||||
|
controller->name());
|
||||||
|
}
|
||||||
|
if (res != 0) {
|
||||||
|
if (IsOptionalController(controller)) {
|
||||||
|
PLOG(INFO) << "Failed to mount optional controller " << controller->name();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
PLOG(ERROR) << "Failed to mount controller " << controller->name();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool SetupCgroup(const CgroupDescriptor& descriptor) {
|
||||||
|
const format::CgroupController* controller = descriptor.controller();
|
||||||
|
|
||||||
|
if (controller->version() == 2) {
|
||||||
|
if (!strcmp(controller->name(), CGROUPV2_CONTROLLER_NAME)) {
|
||||||
|
return MountV2CgroupController(descriptor);
|
||||||
|
} else {
|
||||||
|
return ActivateV2CgroupController(descriptor);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return MountV1CgroupController(descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// Stubs for non-Android targets.
|
// Stubs for non-Android targets.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue