1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# NAME
5#	failcmd.sh - run a command with injecting slab/page allocation failures
6#
7# SYNOPSIS
8#	failcmd.sh --help
9#	failcmd.sh [<options>] command [arguments]
10#
11# DESCRIPTION
12#	Run command with injecting slab/page allocation failures by fault
13#	injection.
14#
15#	NOTE: you need to run this script as root.
16#
17
18usage()
19{
20	cat >&2 <<EOF
21Usage: $0 [options] command [arguments]
22
23OPTIONS
24	-p percent
25	--probability=percent
26		likelihood of failure injection, in percent.
27		Default value is 1
28
29	-t value
30	--times=value
31		specifies how many times failures may happen at most.
32		Default value is 1
33
34	--oom-kill-allocating-task=value
35		set /proc/sys/vm/oom_kill_allocating_task to specified value
36		before running the command.
37		Default value is 1
38
39	-h, --help
40		Display a usage message and exit
41
42	--interval=value, --space=value, --verbose=value, --task-filter=value,
43	--stacktrace-depth=value, --require-start=value, --require-end=value,
44	--reject-start=value, --reject-end=value, --ignore-gfp-wait=value
45		See Documentation/fault-injection/fault-injection.rst for more
46		information
47
48	failslab options:
49	--cache-filter=value
50
51	fail_page_alloc options:
52	--ignore-gfp-highmem=value, --min-order=value
53
54ENVIRONMENT
55	FAILCMD_TYPE
56		The following values for FAILCMD_TYPE are recognized:
57
58		failslab
59			inject slab allocation failures
60		fail_page_alloc
61			inject page allocation failures
62
63		If FAILCMD_TYPE is not defined, then failslab is used.
64EOF
65}
66
67if [ $UID != 0 ]; then
68	echo must be run as root >&2
69	exit 1
70fi
71
72DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3}'`
73
74if [ ! -d "$DEBUGFS" ]; then
75	echo debugfs is not mounted >&2
76	exit 1
77fi
78
79FAILCMD_TYPE=${FAILCMD_TYPE:-failslab}
80FAULTATTR=$DEBUGFS/$FAILCMD_TYPE
81
82if [ ! -d $FAULTATTR ]; then
83	echo $FAILCMD_TYPE is not available >&2
84	exit 1
85fi
86
87LONGOPTS=probability:,interval:,times:,space:,verbose:,task-filter:
88LONGOPTS=$LONGOPTS,stacktrace-depth:,require-start:,require-end:
89LONGOPTS=$LONGOPTS,reject-start:,reject-end:,oom-kill-allocating-task:,help
90
91if [ $FAILCMD_TYPE = failslab ]; then
92	LONGOPTS=$LONGOPTS,ignore-gfp-wait:,cache-filter:
93elif [ $FAILCMD_TYPE = fail_page_alloc ]; then
94	LONGOPTS=$LONGOPTS,ignore-gfp-wait:,ignore-gfp-highmem:,min-order:
95fi
96
97TEMP=`getopt -o p:i:t:s:v:h --long $LONGOPTS -n 'failcmd.sh' -- "$@"`
98
99if [ $? != 0 ]; then
100	usage
101	exit 1
102fi
103
104eval set -- "$TEMP"
105
106fault_attr_default()
107{
108	echo N > $FAULTATTR/task-filter
109	echo 0 > $FAULTATTR/probability
110	echo 1 > $FAULTATTR/times
111}
112
113fault_attr_default
114
115oom_kill_allocating_task_saved=`cat /proc/sys/vm/oom_kill_allocating_task`
116
117restore_values()
118{
119	fault_attr_default
120	echo $oom_kill_allocating_task_saved \
121		> /proc/sys/vm/oom_kill_allocating_task
122}
123
124#
125# Default options
126#
127declare -i oom_kill_allocating_task=1
128declare task_filter=Y
129declare -i probability=1
130declare -i times=1
131
132while true; do
133	case "$1" in
134	-p|--probability)
135		probability=$2
136		shift 2
137		;;
138	-i|--interval)
139		echo $2 > $FAULTATTR/interval
140		shift 2
141		;;
142	-t|--times)
143		times=$2
144		shift 2
145		;;
146	-s|--space)
147		echo $2 > $FAULTATTR/space
148		shift 2
149		;;
150	-v|--verbose)
151		echo $2 > $FAULTATTR/verbose
152		shift 2
153		;;
154	--task-filter)
155		task_filter=$2
156		shift 2
157		;;
158	--stacktrace-depth)
159		echo $2 > $FAULTATTR/stacktrace-depth
160		shift 2
161		;;
162	--require-start)
163		echo $2 > $FAULTATTR/require-start
164		shift 2
165		;;
166	--require-end)
167		echo $2 > $FAULTATTR/require-end
168		shift 2
169		;;
170	--reject-start)
171		echo $2 > $FAULTATTR/reject-start
172		shift 2
173		;;
174	--reject-end)
175		echo $2 > $FAULTATTR/reject-end
176		shift 2
177		;;
178	--oom-kill-allocating-task)
179		oom_kill_allocating_task=$2
180		shift 2
181		;;
182	--ignore-gfp-wait)
183		echo $2 > $FAULTATTR/ignore-gfp-wait
184		shift 2
185		;;
186	--cache-filter)
187		echo $2 > $FAULTATTR/cache_filter
188		shift 2
189		;;
190	--ignore-gfp-highmem)
191		echo $2 > $FAULTATTR/ignore-gfp-highmem
192		shift 2
193		;;
194	--min-order)
195		echo $2 > $FAULTATTR/min-order
196		shift 2
197		;;
198	-h|--help)
199		usage
200		exit 0
201		shift
202		;;
203	--)
204		shift
205		break
206		;;
207	esac
208done
209
210[ -z "$1" ] && exit 0
211
212echo $oom_kill_allocating_task > /proc/sys/vm/oom_kill_allocating_task
213echo $task_filter > $FAULTATTR/task-filter
214echo $probability > $FAULTATTR/probability
215echo $times > $FAULTATTR/times
216
217trap "restore_values" SIGINT SIGTERM EXIT
218
219cmd="echo 1 > /proc/self/make-it-fail && exec $@"
220bash -c "$cmd"
221