1#!/bin/sh 2# SPDX-License-Identifier: GPL-2.0-or-later 3# Copyright (c) Linux Test Project, 2016-2022 4# Copyright (c) 2015 Fujitsu Ltd. 5# Author: Zeng Linggang <[email protected]> 6# 7# This is a regression test for commit: 8# http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=bb2bc55 9# 10# A newly created cpuset group crashed the kernel, if exclusive was set to 1, 11# before a cpuset was set. 12 13TST_SETUP=setup 14TST_CLEANUP=cleanup 15TST_TESTFUNC=do_test 16TST_NEEDS_ROOT=1 17TST_NEEDS_TMPDIR=1 18TST_MIN_KVER="3.18" 19 20LOCAL_MOUNTPOINT="cpuset_test" 21BACKUP_DIRECTORY="cpuset_backup" 22 23cpu_num= 24root_cpuset_dir= 25cpu_exclusive="cpuset.cpu_exclusive" 26cpus="cpuset.cpus" 27old_cpu_exclusive_value=1 28 29# Check if there are cpuset groups 30cpuset_has_groups() 31{ 32 find ${root_cpuset_dir} -mindepth 1 -type d -exec echo 1 \; -quit 33} 34 35# cpuset_find_parent_first <what> 36# Do a parent first find of <what> 37cpuset_find_parent_first() 38{ 39 local what=$1 40 41 find . -mindepth 2 -name ${what} | 42 awk '{print length($0) " " $0}' | 43 sort -n | cut -d " " -f 2- 44} 45 46# cpuset_find_child_first <what> 47# Do a child first find of <what> 48cpuset_find_child_first() 49{ 50 local what=$1 51 52 find . -mindepth 2 -name ${what} | 53 awk '{print length($0) " " $0}' | 54 sort -nr | cut -d " " -f 2- 55} 56 57# cpuset_backup_and_update <backup_dir> <what> 58# Create backup of the values of a specific file (<what>) 59# in all cpuset groups and set the value to 1 60# The backup is written to <backup_dir> in the same structure 61# as in the cpuset filesystem 62cpuset_backup_and_update() 63{ 64 local backup_dir=$1 65 local what=$2 66 local old_dir=$PWD 67 local cpu_max=$((cpu_num - 1)) 68 local res 69 70 cd ${root_cpuset_dir} 71 72 73 cpuset_find_parent_first ${what} | 74 while read -r file; do 75 [ "$(cat "${file}")" = "" ] && continue 76 77 mkdir -p "$(dirname "${backup_dir}/${file}")" 78 cat "${file}" > "${backup_dir}/${file}" 79 echo "0-$cpu_max" > "${file}" || exit 1 80 done 81 if [ $? -ne 0 ]; then 82 cd $old_dir 83 return 1 84 fi 85 86 cpuset_find_child_first ${what} | 87 while read -r file; do 88 [ "$(cat "${file}")" = "" ] && continue 89 echo "1" > "${file}" 90 done 91 res=$? 92 93 cd $old_dir 94 95 return $res 96} 97 98# cpuset_restore <backup_dir> <what> 99# Restores the value of a file (<what>) in all cpuset 100# groups from the backup created by cpuset_backup_and_update 101cpuset_restore() 102{ 103 local backup_dir=$1 104 local what=$2 105 local old_dir=$PWD 106 local cpu_max=$((cpu_num - 1)) 107 108 cd ${backup_dir} 109 110 cpuset_find_parent_first ${what} | 111 while read -r file; do 112 echo "0-$cpu_max" > "${root_cpuset_dir}/${file}" 113 done 114 115 cpuset_find_child_first ${what} | 116 while read -r file; do 117 cat "${file}" > "${root_cpuset_dir}/${file}" 118 done 119 120 cd $old_dir 121} 122 123setup() 124{ 125 cgroup_require "cpuset" 126 cgroup_version=$(cgroup_get_version "cpuset") 127 root_cpuset_dir=$(cgroup_get_mountpoint "cpuset") 128 testpath=$(cgroup_get_test_path "cpuset") 129 task_list=$(cgroup_get_task_list "cpuset") 130 131 tst_res TINFO "test starts with cgroup version $cgroup_version" 132 133 if [ "$cgroup_version" = "2" ]; then 134 tst_brk TCONF "cgroup v2 found, skipping test" 135 return 136 fi 137 138 if ! [ -f ${root_cpuset_dir}/${cpu_exclusive} ]; then 139 cpu_exclusive=cpu_exclusive 140 cpus=cpus 141 fi 142 143 if ! [ -f ${root_cpuset_dir}/${cpu_exclusive} ]; then 144 tst_brk TBROK "Both cpuset.cpu_exclusive and cpu_exclusive do not exist" 145 fi 146 147 # Ensure that we can use cpu 0 exclusively 148 if [ "$(cpuset_has_groups)" = "1" ]; then 149 cpu_num=$(tst_getconf _NPROCESSORS_ONLN) 150 if [ $cpu_num -lt 2 ]; then 151 tst_brk TCONF "There are already cpuset groups, so at least two cpus are required." 152 fi 153 154 # Use cpu 1 for all existing cpuset cgroups 155 mkdir ${BACKUP_DIRECTORY} 156 cpuset_backup_and_update "${PWD}/${BACKUP_DIRECTORY}" ${cpus} 157 [ $? -ne 0 ] && tst_brk TBROK "Unable to prepare existing cpuset cgroups" 158 fi 159 160 old_cpu_exclusive_value=$(cat ${root_cpuset_dir}/${cpu_exclusive}) 161 if [ "${old_cpu_exclusive_value}" != "1" ];then 162 echo 1 > ${root_cpuset_dir}/${cpu_exclusive} 163 [ $? -ne 0 ] && tst_brk TBROK "'echo 1 > ${root_cpuset_dir}/${cpu_exclusive}' failed" 164 fi 165} 166 167cleanup() 168{ 169 if [ -d "${root_cpuset_dir}/testdir" ]; then 170 rmdir ${root_cpuset_dir}/testdir 171 fi 172 173 if [ -d "${BACKUP_DIRECTORY}" ]; then 174 cpuset_restore "${PWD}/${BACKUP_DIRECTORY}" ${cpus} 175 fi 176 177 if [ "$old_cpu_exclusive_value" != 1 ]; then 178 # Need to flush, or write may fail with: "Device or resource busy" 179 sync 180 echo ${old_cpu_exclusive_value} > ${root_cpuset_dir}/${cpu_exclusive} 181 fi 182 183 cgroup_cleanup 184} 185 186do_test() 187{ 188 local cpu_exclusive_tmp cpus_value 189 190 ROD_SILENT mkdir ${root_cpuset_dir}/testdir 191 192 # Creat an exclusive cpuset. 193 if ! echo 1 > ${root_cpuset_dir}/testdir/${cpu_exclusive}; then 194 tst_res TFAIL "'echo 1 > ${root_cpuset_dir}/testdir/${cpu_exclusive}' failed" 195 return 196 fi 197 198 cpu_exclusive_tmp=$(cat ${root_cpuset_dir}/testdir/${cpu_exclusive}) 199 if [ "${cpu_exclusive_tmp}" != "1" ]; then 200 tst_res TFAIL "${cpu_exclusive} is '${cpu_exclusive_tmp}', expected '1'" 201 return 202 fi 203 204 # This may trigger the kernel crash 205 if ! echo 0 > ${root_cpuset_dir}/testdir/${cpus}; then 206 tst_res TFAIL "'echo 0 > ${root_cpuset_dir}/testdir/${cpus}' failed" 207 return 208 fi 209 210 cpus_value=$(cat ${root_cpuset_dir}/testdir/${cpus}) 211 if [ "${cpus_value}" != "0" ]; then 212 tst_res TFAIL "${cpus} is '${cpus_value}', expected '0'" 213 return 214 fi 215 216 tst_res TPASS "Bug is not reproducible" 217} 218 219. cgroup_lib.sh 220tst_run 221