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