xref: /aosp_15_r20/external/ltp/testcases/kernel/controllers/cpuset/cpuset_regression_test.sh (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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