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