#!/bin/sh # Copyright (c) 2012 Alexander Vershilov # Released under the 2-clause BSD license. extra_stopped_commands="${extra_stopped_commands} cgroup_cleanup" description_cgroup_cleanup="Kill all processes in the cgroup" cgroup_find_path() { local OIFS n name dir result [ -n "$1" ] || return 0 OIFS="$IFS" IFS=":" while read n name dir; do [ "$name" = "$1" ] && result="$dir" done < /proc/1/cgroup IFS="$OIFS" echo $result } cgroup_get_pids() { local p pids= while read p; do [ $p -eq $$ ] || pids="${pids} ${p}" done < /sys/fs/cgroup/openrc/${RC_SVCNAME}/tasks [ -n "$pids" ] } cgroup_running() { [ -d "/sys/fs/cgroup/openrc/${RC_SVCNAME}" ] } cgroup_set_values() { [ -n "$1" -a -n "$2" -a -d "/sys/fs/cgroup/$1" ] || return 0 local controller="$1" h=$(cgroup_find_path "$1") cgroup="/sys/fs/cgroup/${1}${h}openrc_${RC_SVCNAME}" [ -d "$cgroup" ] || mkdir -p "$cgroup" set -- $2 local name val while [ -n "$1" -a "$controller" != "cpuacct" ]; do case "$1" in $controller.*) if [ -n "$name" -a -f "$cgroup/$name" -a -n "$val" ]; then veinfo "$RC_SVCNAME: Setting $cgroup/$name to $val" printf "%s" "$val" > "$cgroup/$name" fi name=$1 val= ;; *) val="$val $1" ;; esac shift done if [ -n "$name" -a -f "$cgroup/$name" -a -n "$val" ]; then veinfo "$RC_SVCNAME: Setting $cgroup/$name to $val" printf "%s" "$val" > "$cgroup/$name" fi if [ -f "$cgroup/tasks" ]; then veinfo "$RC_SVCNAME: adding to $cgroup/tasks" printf "%d" 0 > "$cgroup/tasks" fi return 0 } cgroup_add_service() { # relocate starting process to the top of the cgroup # it prevents from unwanted inheriting of the user # cgroups. But may lead to a problems where that inheriting # is needed. echo "!! START cgroup_add_service .${@}. $RC_SVCNAME" for d in /sys/fs/cgroup/* ; do if test -f "${d}"/tasks -a "$d" != "/sys/fs/cgroup/openrc"; then echo "${d}/tasks" printf "%d" 0 > "${d}"/tasks fi done # sleep 1 #delay after all, except the openrc one (has no effect on the issue) ps afwj $$ >/dev/null #2>/dev/null 1>&2 if test -f "/sys/fs/cgroup/openrc/tasks" ; then printf "%d" 0 > "/sys/fs/cgroup/openrc/tasks" fi #no delay after openrc => issue happens (sporadically) #delay after this openrc and the issue is gone (the ps delay) ps afwj $$ >/dev/null #2>/dev/null 1>&2 # cat /sys/fs/cgroup/openrc/tasks | tail -n3 # sleep 1 openrc_cgroup=/sys/fs/cgroup/openrc if [ -d "$openrc_cgroup" ]; then cgroup="$openrc_cgroup/$RC_SVCNAME" #the delay these introduce, seems to prevent wtw race is going on that causes this: /lib64/rc/sh/rc-cgroup.sh: line 89: printf: write error: No such device # echo "Current: $$ $RC_SVCNAME" >/dev/null #2>/dev/null 1>&2 # ps afwj $$ >/dev/null #2>/dev/null 1>&2 #^tested and confirmed to FAIL(2) (at boot) when the above 2 lines are commented out! but not when they are uncommented! so, draw your own conclusions. # sleep 1 mkdir -p "$cgroup" local fail=0 if test -f "$cgroup/tasks"; then if ! printf "%d" 0 > "$cgroup/tasks"; then fail=1 fi else fail=2 fi if test "$fail" -ne "0"; then echo "------FAIL(${fail})----- $cgroup/tasks" 1>&2 echo "Current: $$ $RC_SVCNAME" 1>&2 cat "$cgroup/tasks" fi # [ -f "$cgroup/tasks" ] || ls -la "$openrc_cgroup" 1>&2 # [ -f "$cgroup/tasks" ] && printf "%d" 0 > "$cgroup/tasks" cat "$cgroup/tasks" fi cat /sys/fs/cgroup/openrc/tasks | tail -n3 echo "!! DONE cgroup_add_service .${@}. $RC_SVCNAME" } cgroup_set_limits() { local blkio="${rc_cgroup_blkio:-$RC_CGROUP_BLKIO}" [ -n "$blkio" ] && cgroup_set_values blkio "$blkio" local cpu="${rc_cgroup_cpu:-$RC_CGROUP_CPU}" [ -n "$cpu" ] && cgroup_set_values cpu "$cpu" local cpuacct="${rc_cgroup_cpuacct:-$RC_CGROUP_CPUACCT}" [ -n "$cpuacct" ] && cgroup_set_values cpuacct "$cpuacct" local cpuset="${rc_cgroup_cpuset:-$RC_CGROUP_cpuset}" [ -n "$cpuset" ] && cgroup_set_values cpuset "$cpuset" local devices="${rc_cgroup_devices:-$RC_CGROUP_DEVICES}" [ -n "$devices" ] && cgroup_set_values devices "$devices" local memory="${rc_cgroup_memory:-$RC_CGROUP_MEMORY}" [ -n "$memory" ] && cgroup_set_values memory "$memory" local net_prio="${rc_cgroup_net_prio:-$RC_CGROUP_NET_PRIO}" [ -n "$net_prio" ] && cgroup_set_values net_prio "$net_prio" return 0 } cgroup_cleanup() { cgroup_running || return 0 ebegin "starting cgroups cleanup" for sig in TERM QUIT INT; do cgroup_get_pids || { eend 0 "finished" ; return 0 ; } for i in 0 1; do kill -s $sig $pids for j in 0 1 2; do cgroup_get_pids || { eend 0 "finished" ; return 0 ; } sleep 1 done done 2>/dev/null done cgroup_get_pids || { eend 0 "finished" ; return 0; } kill -9 $pids eend $(cgroup_running && echo 1 || echo 0) "fail to stop all processes" }