From 457f928e793cb1f6ef254935ad07f58b8762c72f Mon Sep 17 00:00:00 2001 From: William Hubbs Date: Thu, 14 Sep 2017 10:38:10 -0500 Subject: [PATCH] add support for control groups version 2 This is for #94. --- etc/rc.conf | 45 ++++++++++++++++---- init.d/sysfs.in | 100 ++++++++++++++++++++++++++++++++++++-------- sh/openrc-run.sh.in | 15 ++++--- sh/rc-cgroup.sh.in | 51 ++++++++++++++++++++++ 4 files changed, 182 insertions(+), 29 deletions(-) diff --git a/etc/rc.conf b/etc/rc.conf index 689e6be2..d9ad911d 100644 --- a/etc/rc.conf +++ b/etc/rc.conf @@ -191,13 +191,43 @@ rc_tty_number=12 ############################################################################## # LINUX CGROUPS RESOURCE MANAGEMENT -# If you have cgroups turned on in your kernel, this switch controls -# whether or not a group for each controller is mounted under -# /sys/fs/cgroup. -# None of the other options in this section work if this is set to "NO". +# This sets the mode used to mount cgroups. +# "hybrid" mounts cgroups version 2 on /sys/fs/cgroup/unified and +# cgroups version 1 on /sys/fs/cgroup. +# "legacy" mounts cgroups version 1 on /sys/fs/cgroup +# "unified" mounts cgroups version 2 on /sys/fs/cgroup +#rc_cgroup_mode="hybrid" + +# This is a list of controllers which should be enabled for cgroups version 2. +# If hybrid mode is being used, controllers listed here will not be +# available for cgroups version 1. +# This is a global setting. +#rc_cgroup_controllers="" + +# This variable contains the cgroups version 2 settings for your services. +# If this is set in this file, the settings will apply to all services. +# If you want different settings for each service, place the settings in +# /etc/conf.d/foo for service foo. +# The format is to specify the setting and value followed by a newline. +# Multiple settings and values can be specified. +# For example, you would use this to set the maximum memory and maximum +# number of pids for a service. +#rc_cgroup_settings=" +#memory.max 10485760 +#pids.max max +#" +# +# For more information about the adjustments that can be made with +# cgroups version 2, see Documentation/cgroups-v2.txt in the linux kernel +# source tree. +#rc_cgroup_settings="" + +# This switch controls whether or not cgroups version 1 controllers are +# individually mounted under +# /sys/fs/cgroup in hybrid or legacy mode. #rc_controller_cgroups="YES" -# The following settings allow you to set up values for the cgroup +# The following settings allow you to set up values for the cgroups version 1 # controllers for your services. # They can be set in this file;, however, if you do this, the settings # will apply to all of your services. @@ -211,8 +241,9 @@ rc_tty_number=12 # cpu.shares 512 # " # -#For more information about the adjustments that can be made with -#cgroups, see Documentation/cgroups/* in the linux kernel source tree. +# For more information about the adjustments that can be made with +# cgroups version 1, see Documentation/cgroups-v1/* in the linux kernel +# source tree. # Set the blkio controller settings for this service. #rc_cgroup_blkio="" diff --git a/init.d/sysfs.in b/init.d/sysfs.in index a2538114..9f39fb57 100644 --- a/init.d/sysfs.in +++ b/init.d/sysfs.in @@ -107,20 +107,16 @@ mount_misc() fi } -mount_cgroups() +cgroup1_base() { - # set up kernel support for cgroups - if [ -d /sys/fs/cgroup ] && ! mountinfo -q /sys/fs/cgroup; then - if grep -qs cgroup /proc/filesystems; then - ebegin "Mounting cgroup filesystem" - local opts="${sysfs_opts},mode=755,size=${rc_cgroupsize:-10m}" - mount -n -t tmpfs -o ${opts} cgroup_root /sys/fs/cgroup - eend $? - fi + grep -qw cgroup /proc/filesystems || return 0 + if ! mountinfo -q /sys/fs/cgroup; then + ebegin "Mounting cgroup filesystem" + local opts="${sysfs_opts},mode=755,size=${rc_cgroupsize:-10m}" + mount -n -t tmpfs -o "${opts}" cgroup_root /sys/fs/cgroup + eend $? fi - mountinfo -q /sys/fs/cgroup || return 0 - if ! mountinfo -q /sys/fs/cgroup/openrc; then local agent="@LIBEXECDIR@/sh/cgroup-release-agent.sh" mkdir /sys/fs/cgroup/openrc @@ -129,17 +125,87 @@ mount_cgroups() openrc /sys/fs/cgroup/openrc printf 1 > /sys/fs/cgroup/openrc/notify_on_release fi + return 0 +} - yesno ${rc_controller_cgroups:-YES} && [ -e /proc/cgroups ] || return 0 - while read name hier groups enabled rest; do +cgroup1_controllers() +{ + yesno "${rc_controller_cgroups:-YES}" && [ -e /proc/cgroups ] || return 0 + while read -r name _ _ enabled rest; do case "${enabled}" in - 1) mountinfo -q /sys/fs/cgroup/${name} && continue - mkdir /sys/fs/cgroup/${name} - mount -n -t cgroup -o ${sysfs_opts},${name} \ - ${name} /sys/fs/cgroup/${name} + 1) mountinfo -q "/sys/fs/cgroup/${name}" && continue + local x + for x in $rc_cgroup_controllers; do + [ "${name}" = "blkio" ] && [ "${x}" = "io" ] && + continue 2 + [ "${name}" = "${x}" ] && + continue 2 + done + mkdir "/sys/fs/cgroup/${name}" + mount -n -t cgroup -o "${sysfs_opts},${name}" \ + "${name}" "/sys/fs/cgroup/${name}" ;; esac done < /proc/cgroups + return 0 +} + +cgroup2_controllers() +{ + local active cgroup_path x y + cgroup_path="$(cgroup2_find_path)" + [ -z "${cgroup_path}" ] && return 0 + [ -e "${cgroup_path}/cgroup.controllers" ] && + read -r active < "${cgroup_path}/cgroup.controllers" + for x in ${rc_cgroup_controllers}; do + for y in ${active}; do + [ "$x" = "$y" ] && + [ -e "${cgroup_path}/cgroup.subtree_control" ]&& + echo "+${x}" > "${cgroup_path}/cgroup.subtree_control" + done + done + return 0 +} + +cgroups_hybrid() +{ + grep -qw cgroup /proc/filesystems && + grep -qw cgroup2 /proc/filesystems || + return 0 + cgroup1_base + mkdir /sys/fs/cgroup/unified + mount -t cgroup2 none -o "${sysfs_opts},nsdelegate" /sys/fs/cgroup/unified + cgroup2_controllers + cgroup1_controllers + return 0 +} + +cgroups_legacy() +{ + grep -qw cgroup /proc/filesystems || return 0 + cgroup1_base + cgroup1_controllers + return 0 +} + +cgroups_unified() +{ + grep -qw cgroup2 /proc/filesystems || return 0 + mount -t cgroup2 none -o "${sysfs_opts},nsdelegate" /sys/fs/cgroup + return 0 +} + +mount_cgroups() +{ + # set up kernel support for cgroups + if [ -d /sys/fs/cgroup ]; then + case "${rc_cgroup_mode:-hybrid}" in + hybrid) cgroups_hybrid ;; + legacy) cgroups_legacy ;; + unified) cgroups_unified ;; + esac + fi + return 0 } restorecon_sys() diff --git a/sh/openrc-run.sh.in b/sh/openrc-run.sh.in index a38d46d6..e778bd09 100644 --- a/sh/openrc-run.sh.in +++ b/sh/openrc-run.sh.in @@ -258,8 +258,7 @@ for _cmd; do [ -n "${rc_ulimit:-$RC_ULIMIT}" ] && \ ulimit ${rc_ulimit:-$RC_ULIMIT} # Apply cgroups settings if defined - if [ "$(command -v cgroup_add_service)" = \ - "cgroup_add_service" ] + if [ "$(command -v cgroup_add_service)" = "cgroup_add_service" ] then if [ -d /sys/fs/cgroup -a ! -w /sys/fs/cgroup ]; then eerror "No permission to apply cgroup settings" @@ -268,9 +267,11 @@ for _cmd; do cgroup_add_service /sys/fs/cgroup/openrc cgroup_add_service /sys/fs/cgroup/systemd/system fi - [ "$(command -v cgroup_set_limits)" = \ - "cgroup_set_limits" ] && \ - cgroup_set_limits + [ "$(command -v cgroup_set_limits)" = "cgroup_set_limits" ] && + cgroup_set_limits + [ "$(command -v cgroup2_set_limits)" = "cgroup2_set_limits" ] && + [ "$_cmd" = start ] && + cgroup2_set_limits break fi done @@ -368,6 +369,10 @@ while [ -n "$1" ]; do "$1" = "stop" ] && \ yesno "${rc_cgroup_cleanup}" && \ cgroup_cleanup + if [ "$(command -v cgroup2_remove)" = "cgroup2_remove" ]; then + [ "$1" = stop ] || [ -z "${command}" ] && + cgroup2_remove + fi shift continue 2 else diff --git a/sh/rc-cgroup.sh.in b/sh/rc-cgroup.sh.in index 5987f966..40501f22 100644 --- a/sh/rc-cgroup.sh.in +++ b/sh/rc-cgroup.sh.in @@ -152,3 +152,54 @@ cgroup_cleanup() kill -9 $pids eend $(cgroup_running && echo 1 || echo 0) "fail to stop all processes" } + +cgroup2_find_path() +{ + case "${rc_cgroup_mode:-hybrid}" in + hybrid) printf "/sys/fs/cgroup/unified" ;; + unified) printf "/sys/fs/cgroup" ;; + esac + return 0 +} + +cgroup2_remove() +{ + local cgroup_path="$(cgroup2_find_path)" rc_cgroup_path + [ -z "${cgroup_path}" ] && return 0 + rc_cgroup_path="${cgroup_path}/${RC_SVCNAME}" + [ ! -d "${rc_cgroup_path}" ] || + [ ! -e "${rc_cgroup_path}"/cgroup.events ] && + return 0 + grep -qx "$$" "${rc_cgroup_path}/cgroup.procs" && + echo 0 > "${cgroup_path}/cgroup.procs" + local key populated vvalue + while read key value; do + case "${key}" in + populated) populated=${value} ;; + *) ;; + esac + done < "${rc_cgroup_path}/cgroup.events" + [ "${populated}" = 1 ] && return 0 + rmdir "${rc_cgroup_path}" + return 0 +} + +cgroup2_set_limits() +{ + local cgroup_path="$(cgroup2_find_path)" + [ -z "${cgroup_path}" ] && return 0 + rc_cgroup_path="${cgroup_path}/${RC_SVCNAME}" + local OIFS="$IFS" + IFS=" +" + [ ! -d "${rc_cgroup_path}" ] && mkdir "${rc_cgroup_path}" + echo 0 > "${rc_cgroup_path}/cgroup.procs" + echo "${rc_cgroup_settings}" | while IFS="$OIFS" read key value; do + [ -z "${key}" ] || [ -z "${value}" ] && continue + [ ! -e "${rc_cgroup_path}/${key}" ] && continue + veinfo "${RC_SVCNAME}: cgroups: ${key} ${value}" + echo "${value}" > "${rc_cgroup_path}/${key}" + done + IFS="$OIFS" + return 0 +}