Support a base cgroup.
[util-vserver.git] / scripts / vserver.functions
index b8ed277..1dc880a 100644 (file)
@@ -49,6 +49,8 @@ declare -a OPTS_VTAG_CREATE=()
 declare -a OPTS_VTAG_ENTER=()
 declare -a OPTS_VMEMCTRL=()
 declare -a OPTS_VSPACE=( --default )
+declare -a OPTS_VSPACE_SHARED=()
+declare -a VSPACE_SHARED_CMD=()
 
 declare -a STOPCMD_PREPARE=()
 
@@ -75,6 +77,7 @@ SILENT_OPT=
 CGROUP_MNT=/dev/cgroup
 CGROUP_SUBSYS=all
 declare -a CGROUP_INHERIT=( cpuset.cpus cpuset.mems )
+CGROUP_BASE=""
 
 : ${VSERVER_NAME:=$(basename "$VSERVER_DIR")}
 
@@ -110,6 +113,12 @@ function _generateChbindOptions
 
     test -n "$_HAVE_INTERFACE_OPTIONS" || _generateInterfaceOptions "$vdir"
 
+    if test -e "$vdir"/noncontext -o \
+           \( -e "$vdir"/spaces/net -a ! -e "$vdir"/ncontext \); then
+       _HAVE_CHBIND_OPTIONS=1
+       return 0
+    fi
+
     local f="$vdir"/interfaces/bcast
     getFileValue bcast "$f"
     f="$vdir"/interfaces/lback
@@ -147,6 +156,8 @@ function _generateIONiceCommand
     local ionice_class=2
     local ionice_priority=0
 
+    test -n "$_IONICE" || return 0
+
     test -r "$vdir/ionice/class" && read ionice_class <"$vdir"/ionice/class
     test -r "$vdir/ionice/priority" && read ionice_priority <"$vdir"/ionice/priority
 
@@ -342,7 +353,8 @@ function _generateInitOptions
                panic "init-vserver.sh not found; aborting"
            fi
 
-           INITCMD_START=( env TERM=$TERM $RC_WRAP "$RUNLEVEL_START" )
+           OPTS_ENV=( "${OPTS_ENV[@]}" TERM=$TERM )
+           INITCMD_START=( $RC_WRAP "$RUNLEVEL_START" )
            INITCMD_STOP=( env -i PATH=$RC_PATH TERM=$TERM RUNLEVEL=0 /sbin/rc shutdown )
            INITCMD_PREPARE=( $_FAKE_RUNLEVEL 3 /var/run/utmp )
            ;;
@@ -784,16 +796,22 @@ function _generateSpaceOptions
 {
     local vdir="$1"
     local d="$vdir"/spaces
-
-    ( test ! -e "$d"/pid ) || \
-       OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --pid )
-
-    test ! -e "$d"/net || {
-       OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --net )
-       # network context and namespace don't make much sense
-       _HAVE_CHBIND_OPTIONS=1
-       CHBIND_CMD=()
-    }
+    local shared
+    local space
+
+    for space in pid net; do
+       if test -e "$d"/$space; then
+           getFileValue shared "$d"/$space || shared=""
+           if test -z "$shared"; then
+               OPTS_VSPACE=( "${OPTS_VSPACE[@]}" --$space )
+           elif test "$shared" = "0"; then
+               : # Do nothing
+           else
+               OPTS_VSPACE_SHARED=( "${OPTS_VSPACE_SHARED[@]}" --$space )
+               VSPACE_SHARED_CMD=( "${VSPACE_SHARED_CMD[@]}" $_VSPACE --enter "$shared" --$space -- )
+           fi
+       fi
+    done
 
     local mask
     getFileValue mask "$d"/mask || \
@@ -806,8 +824,8 @@ function prepareInit
     pushd "$1/vdir" >/dev/null
     case "$INITSTYLE" in
        sysv)
-           { find var/run  ! -type d -print0; \
-             find var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
+           { $_FIND var/run  ! -type d -print0; \
+             $_FIND var/lock ! -type d -print0; } | xargs -0r $_CHROOT_SH rm
            ;;
        plain)
            $_CHROOT_SH rm .autofsck forcefsck 2>/dev/null || :
@@ -916,6 +934,10 @@ function _mountVserverInternal
     # magic regarding the mtab file; when etc/mtab can not be touched,
     # add the '-n' flag to mount
     test -w etc -o -w etc/mtab || xflag=-n
+    if test -h etc/mtab; then
+       local l=$($_READLINK etc/mtab)
+       test "${l##/proc/}" = "$l" || xflag=-n
+    fi
     "$@" $_SECURE_MOUNT -a $xflag --chroot --fstab "$fstab" --rootfs no
     popd >/dev/null
 }
@@ -1211,7 +1233,7 @@ WARNING: There is no cachedirectory configured for this vserver;
   ln -s ../.defaults/cachebase/$VSERVER_NAME $cfgdir/cache
 "
 
-    find "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
+    $_FIND "$cfgdir" -type f -exec "$_CHECK_UNIXFILE" '{}' ';'
 
     vshelper.doSanityCheck
 
@@ -1376,7 +1398,8 @@ function _namespaceCleanup
     while read -r dev path opts; do
        test -n "$path" || continue
        for i in "$root" /dev /proc; do
-           test "${path#$i}" != "$path" && continue 2
+           path_dir="${path}/"
+           test "${path_dir#${i}/}" != "${path_dir}" && continue 2
        done
        for i in "${list[@]}" /; do
            test "$path" = "$i" && continue 2
@@ -1436,11 +1459,21 @@ function _generateCgroupOptions
     findFile file "$__CONFDIR/.defaults/cgroup/subsys" ""
     if test -n "$file"; then
        read CGROUP_SUBSYS < "$file"
+    elif $_GREP -q '^ns[[:space:]]' /proc/cgroups; then
+       # Hack for the ns subsystem, with which we are incompatible
+       CGROUP_SUBSYS=$($_SED '/^#/d;/^ns[[:space:]]/d;s/[[:space:]].*//' /proc/cgroups | \
+                       (s=""; while read x; do test -n "$s" && s="$s,"; s="$s$x"; done; echo "$s"))
     fi
     findFile file "$__CONFDIR/.defaults/cgroup/inherit" ""
     if test -n "$file"; then
        _readFileToArray CGROUP_INHERIT "$file" ""
     fi
+    findFile file "$__CONFDIR/.defaults/cgroup/base" ""
+    if test -n "$file"; then
+       read CGROUP_BASE < "$file"
+       test "$CGROUP_BASE" != "${CGROUP_BASE%/}" || \
+           CGROUP_BASE="${CGROUP_BASE}/"
+    fi
 
     return 0
 }
@@ -1449,8 +1482,12 @@ function useCgroup
 {
     hasCgroup || return 1
     test -d "$CGROUP_MNT" || return 1
+    memcg=""
+    if $_VSERVER_INFO - FEATURE memcg; then
+       memcg=1
+    fi
     test -d "$1/cgroup" -o \
-       \( -d "$__CONFDIR/.defaults/cgroup" -a \
+       \( \( -d "$__CONFDIR/.defaults/cgroup" -o -n "$memcg" \) -a \
           ! -e "$1/nocgroup" \)
 }
 
@@ -1461,34 +1498,56 @@ function _handleCgroup
     local dir
     local name
     local i
+    local j
     local parent
 
     useCgroup "$vdir" || return 0
 
     findDir dir "$vdir/cgroup" "$__CONFDIR/.defaults/cgroup" ""
-    test -d "$dir" || return 0
 
-    if test -r "$dir"/name; then
+    if test -n "$dir" -a -r "$dir"/name; then
        read name < "$dir"/name
     else
        name="$VSERVER_NAME"
     fi
 
     if test "$action" = "attach"; then
-       if mkdir "$CGROUP_MNT/$name" 2>/dev/null; then
-           parent="$CGROUP_MNT/$name"
+       if test -n "$CGROUP_BASE"; then
+           local -a dirs=()
+           i="$CGROUP_MNT/$CGROUP_BASE"
+           while test "$CGROUP_MNT" != "$i"; do
+               dirs=( "$i" "${dirs[@]}" )
+               i="${i%/*}"
+           done
+           for i in "${dirs[@]}"; do
+               if mkdir "$i" 2>/dev/null; then
+                   parent="${i%/*}"
+                   for j in "${CGROUP_INHERIT[@]}"; do
+                       test -f "$parent/$j" || continue
+                       cat "$parent/$j" > "$i/$j"
+                   done
+               fi
+           done
+       fi
+       if mkdir "$CGROUP_MNT/$CGROUP_BASE$name" 2>/dev/null; then
+           parent="$CGROUP_MNT/$CGROUP_BASE$name"
            parent="${parent%/*}"
             for i in "${CGROUP_INHERIT[@]}"; do
                test -f "$parent/$i" || continue
-               cat "$parent/$i" > "$CGROUP_MNT/$name/$i"
+               cat "$parent/$i" > "$CGROUP_MNT/$CGROUP_BASE$name/$i"
            done
 
-           shopt -s nullglob
-           for i in "$dir"/*; do
-               cat "$i" > "$CGROUP_MNT/$name/${i##*/}"
-           done
+           if test -n "$dir"; then
+               shopt -s nullglob
+               for i in "$dir"/*; do
+                   f="${i##*/}"
+                   test "$f" != mnt -a "$f" != subsys -a \
+                       "$f" != inherit -a "$f" != name || continue
+                   cat "$i" > "$CGROUP_MNT/$CGROUP_BASE$name/$f"
+               done
+           fi
        fi
-       echo "$$" > "$CGROUP_MNT/$name/tasks"
+       echo "$$" > "$CGROUP_MNT/$CGROUP_BASE$name/tasks"
     elif test "$action" = "destroy"; then
        rmdir "$CGROUP_MNT/$name" 2>/dev/null || :
     fi