1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * This is for all the tests related to refcount bugs (e.g. overflow,
4*4882a593Smuzhiyun * underflow, reaching zero untested, etc).
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun #include "lkdtm.h"
7*4882a593Smuzhiyun #include <linux/refcount.h>
8*4882a593Smuzhiyun
overflow_check(refcount_t * ref)9*4882a593Smuzhiyun static void overflow_check(refcount_t *ref)
10*4882a593Smuzhiyun {
11*4882a593Smuzhiyun switch (refcount_read(ref)) {
12*4882a593Smuzhiyun case REFCOUNT_SATURATED:
13*4882a593Smuzhiyun pr_info("Overflow detected: saturated\n");
14*4882a593Smuzhiyun break;
15*4882a593Smuzhiyun case REFCOUNT_MAX:
16*4882a593Smuzhiyun pr_warn("Overflow detected: unsafely reset to max\n");
17*4882a593Smuzhiyun break;
18*4882a593Smuzhiyun default:
19*4882a593Smuzhiyun pr_err("Fail: refcount wrapped to %d\n", refcount_read(ref));
20*4882a593Smuzhiyun }
21*4882a593Smuzhiyun }
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun /*
24*4882a593Smuzhiyun * A refcount_inc() above the maximum value of the refcount implementation,
25*4882a593Smuzhiyun * should at least saturate, and at most also WARN.
26*4882a593Smuzhiyun */
lkdtm_REFCOUNT_INC_OVERFLOW(void)27*4882a593Smuzhiyun void lkdtm_REFCOUNT_INC_OVERFLOW(void)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX - 1);
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun pr_info("attempting good refcount_inc() without overflow\n");
32*4882a593Smuzhiyun refcount_dec(&over);
33*4882a593Smuzhiyun refcount_inc(&over);
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun pr_info("attempting bad refcount_inc() overflow\n");
36*4882a593Smuzhiyun refcount_inc(&over);
37*4882a593Smuzhiyun refcount_inc(&over);
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun overflow_check(&over);
40*4882a593Smuzhiyun }
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /* refcount_add() should behave just like refcount_inc() above. */
lkdtm_REFCOUNT_ADD_OVERFLOW(void)43*4882a593Smuzhiyun void lkdtm_REFCOUNT_ADD_OVERFLOW(void)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX - 1);
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun pr_info("attempting good refcount_add() without overflow\n");
48*4882a593Smuzhiyun refcount_dec(&over);
49*4882a593Smuzhiyun refcount_dec(&over);
50*4882a593Smuzhiyun refcount_dec(&over);
51*4882a593Smuzhiyun refcount_dec(&over);
52*4882a593Smuzhiyun refcount_add(4, &over);
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun pr_info("attempting bad refcount_add() overflow\n");
55*4882a593Smuzhiyun refcount_add(4, &over);
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun overflow_check(&over);
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun /* refcount_inc_not_zero() should behave just like refcount_inc() above. */
lkdtm_REFCOUNT_INC_NOT_ZERO_OVERFLOW(void)61*4882a593Smuzhiyun void lkdtm_REFCOUNT_INC_NOT_ZERO_OVERFLOW(void)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX);
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun pr_info("attempting bad refcount_inc_not_zero() overflow\n");
66*4882a593Smuzhiyun if (!refcount_inc_not_zero(&over))
67*4882a593Smuzhiyun pr_warn("Weird: refcount_inc_not_zero() reported zero\n");
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun overflow_check(&over);
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /* refcount_add_not_zero() should behave just like refcount_inc() above. */
lkdtm_REFCOUNT_ADD_NOT_ZERO_OVERFLOW(void)73*4882a593Smuzhiyun void lkdtm_REFCOUNT_ADD_NOT_ZERO_OVERFLOW(void)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX);
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun pr_info("attempting bad refcount_add_not_zero() overflow\n");
78*4882a593Smuzhiyun if (!refcount_add_not_zero(6, &over))
79*4882a593Smuzhiyun pr_warn("Weird: refcount_add_not_zero() reported zero\n");
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun overflow_check(&over);
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
check_zero(refcount_t * ref)84*4882a593Smuzhiyun static void check_zero(refcount_t *ref)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun switch (refcount_read(ref)) {
87*4882a593Smuzhiyun case REFCOUNT_SATURATED:
88*4882a593Smuzhiyun pr_info("Zero detected: saturated\n");
89*4882a593Smuzhiyun break;
90*4882a593Smuzhiyun case REFCOUNT_MAX:
91*4882a593Smuzhiyun pr_warn("Zero detected: unsafely reset to max\n");
92*4882a593Smuzhiyun break;
93*4882a593Smuzhiyun case 0:
94*4882a593Smuzhiyun pr_warn("Still at zero: refcount_inc/add() must not inc-from-0\n");
95*4882a593Smuzhiyun break;
96*4882a593Smuzhiyun default:
97*4882a593Smuzhiyun pr_err("Fail: refcount went crazy: %d\n", refcount_read(ref));
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun /*
102*4882a593Smuzhiyun * A refcount_dec(), as opposed to a refcount_dec_and_test(), when it hits
103*4882a593Smuzhiyun * zero it should either saturate (when inc-from-zero isn't protected)
104*4882a593Smuzhiyun * or stay at zero (when inc-from-zero is protected) and should WARN for both.
105*4882a593Smuzhiyun */
lkdtm_REFCOUNT_DEC_ZERO(void)106*4882a593Smuzhiyun void lkdtm_REFCOUNT_DEC_ZERO(void)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun refcount_t zero = REFCOUNT_INIT(2);
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun pr_info("attempting good refcount_dec()\n");
111*4882a593Smuzhiyun refcount_dec(&zero);
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun pr_info("attempting bad refcount_dec() to zero\n");
114*4882a593Smuzhiyun refcount_dec(&zero);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun check_zero(&zero);
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
check_negative(refcount_t * ref,int start)119*4882a593Smuzhiyun static void check_negative(refcount_t *ref, int start)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun /*
122*4882a593Smuzhiyun * refcount_t refuses to move a refcount at all on an
123*4882a593Smuzhiyun * over-sub, so we have to track our starting position instead of
124*4882a593Smuzhiyun * looking only at zero-pinning.
125*4882a593Smuzhiyun */
126*4882a593Smuzhiyun if (refcount_read(ref) == start) {
127*4882a593Smuzhiyun pr_warn("Still at %d: refcount_inc/add() must not inc-from-0\n",
128*4882a593Smuzhiyun start);
129*4882a593Smuzhiyun return;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun switch (refcount_read(ref)) {
133*4882a593Smuzhiyun case REFCOUNT_SATURATED:
134*4882a593Smuzhiyun pr_info("Negative detected: saturated\n");
135*4882a593Smuzhiyun break;
136*4882a593Smuzhiyun case REFCOUNT_MAX:
137*4882a593Smuzhiyun pr_warn("Negative detected: unsafely reset to max\n");
138*4882a593Smuzhiyun break;
139*4882a593Smuzhiyun default:
140*4882a593Smuzhiyun pr_err("Fail: refcount went crazy: %d\n", refcount_read(ref));
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun /* A refcount_dec() going negative should saturate and may WARN. */
lkdtm_REFCOUNT_DEC_NEGATIVE(void)145*4882a593Smuzhiyun void lkdtm_REFCOUNT_DEC_NEGATIVE(void)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun refcount_t neg = REFCOUNT_INIT(0);
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun pr_info("attempting bad refcount_dec() below zero\n");
150*4882a593Smuzhiyun refcount_dec(&neg);
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun check_negative(&neg, 0);
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun /*
156*4882a593Smuzhiyun * A refcount_dec_and_test() should act like refcount_dec() above when
157*4882a593Smuzhiyun * going negative.
158*4882a593Smuzhiyun */
lkdtm_REFCOUNT_DEC_AND_TEST_NEGATIVE(void)159*4882a593Smuzhiyun void lkdtm_REFCOUNT_DEC_AND_TEST_NEGATIVE(void)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun refcount_t neg = REFCOUNT_INIT(0);
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun pr_info("attempting bad refcount_dec_and_test() below zero\n");
164*4882a593Smuzhiyun if (refcount_dec_and_test(&neg))
165*4882a593Smuzhiyun pr_warn("Weird: refcount_dec_and_test() reported zero\n");
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun check_negative(&neg, 0);
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun /*
171*4882a593Smuzhiyun * A refcount_sub_and_test() should act like refcount_dec_and_test()
172*4882a593Smuzhiyun * above when going negative.
173*4882a593Smuzhiyun */
lkdtm_REFCOUNT_SUB_AND_TEST_NEGATIVE(void)174*4882a593Smuzhiyun void lkdtm_REFCOUNT_SUB_AND_TEST_NEGATIVE(void)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun refcount_t neg = REFCOUNT_INIT(3);
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun pr_info("attempting bad refcount_sub_and_test() below zero\n");
179*4882a593Smuzhiyun if (refcount_sub_and_test(5, &neg))
180*4882a593Smuzhiyun pr_warn("Weird: refcount_sub_and_test() reported zero\n");
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun check_negative(&neg, 3);
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun
check_from_zero(refcount_t * ref)185*4882a593Smuzhiyun static void check_from_zero(refcount_t *ref)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun switch (refcount_read(ref)) {
188*4882a593Smuzhiyun case 0:
189*4882a593Smuzhiyun pr_info("Zero detected: stayed at zero\n");
190*4882a593Smuzhiyun break;
191*4882a593Smuzhiyun case REFCOUNT_SATURATED:
192*4882a593Smuzhiyun pr_info("Zero detected: saturated\n");
193*4882a593Smuzhiyun break;
194*4882a593Smuzhiyun case REFCOUNT_MAX:
195*4882a593Smuzhiyun pr_warn("Zero detected: unsafely reset to max\n");
196*4882a593Smuzhiyun break;
197*4882a593Smuzhiyun default:
198*4882a593Smuzhiyun pr_info("Fail: zero not detected, incremented to %d\n",
199*4882a593Smuzhiyun refcount_read(ref));
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun /*
204*4882a593Smuzhiyun * A refcount_inc() from zero should pin to zero or saturate and may WARN.
205*4882a593Smuzhiyun */
lkdtm_REFCOUNT_INC_ZERO(void)206*4882a593Smuzhiyun void lkdtm_REFCOUNT_INC_ZERO(void)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun refcount_t zero = REFCOUNT_INIT(0);
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun pr_info("attempting safe refcount_inc_not_zero() from zero\n");
211*4882a593Smuzhiyun if (!refcount_inc_not_zero(&zero)) {
212*4882a593Smuzhiyun pr_info("Good: zero detected\n");
213*4882a593Smuzhiyun if (refcount_read(&zero) == 0)
214*4882a593Smuzhiyun pr_info("Correctly stayed at zero\n");
215*4882a593Smuzhiyun else
216*4882a593Smuzhiyun pr_err("Fail: refcount went past zero!\n");
217*4882a593Smuzhiyun } else {
218*4882a593Smuzhiyun pr_err("Fail: Zero not detected!?\n");
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun pr_info("attempting bad refcount_inc() from zero\n");
222*4882a593Smuzhiyun refcount_inc(&zero);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun check_from_zero(&zero);
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun /*
228*4882a593Smuzhiyun * A refcount_add() should act like refcount_inc() above when starting
229*4882a593Smuzhiyun * at zero.
230*4882a593Smuzhiyun */
lkdtm_REFCOUNT_ADD_ZERO(void)231*4882a593Smuzhiyun void lkdtm_REFCOUNT_ADD_ZERO(void)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun refcount_t zero = REFCOUNT_INIT(0);
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun pr_info("attempting safe refcount_add_not_zero() from zero\n");
236*4882a593Smuzhiyun if (!refcount_add_not_zero(3, &zero)) {
237*4882a593Smuzhiyun pr_info("Good: zero detected\n");
238*4882a593Smuzhiyun if (refcount_read(&zero) == 0)
239*4882a593Smuzhiyun pr_info("Correctly stayed at zero\n");
240*4882a593Smuzhiyun else
241*4882a593Smuzhiyun pr_err("Fail: refcount went past zero\n");
242*4882a593Smuzhiyun } else {
243*4882a593Smuzhiyun pr_err("Fail: Zero not detected!?\n");
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun pr_info("attempting bad refcount_add() from zero\n");
247*4882a593Smuzhiyun refcount_add(3, &zero);
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun check_from_zero(&zero);
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
check_saturated(refcount_t * ref)252*4882a593Smuzhiyun static void check_saturated(refcount_t *ref)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun switch (refcount_read(ref)) {
255*4882a593Smuzhiyun case REFCOUNT_SATURATED:
256*4882a593Smuzhiyun pr_info("Saturation detected: still saturated\n");
257*4882a593Smuzhiyun break;
258*4882a593Smuzhiyun case REFCOUNT_MAX:
259*4882a593Smuzhiyun pr_warn("Saturation detected: unsafely reset to max\n");
260*4882a593Smuzhiyun break;
261*4882a593Smuzhiyun default:
262*4882a593Smuzhiyun pr_err("Fail: refcount went crazy: %d\n", refcount_read(ref));
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun /*
267*4882a593Smuzhiyun * A refcount_inc() from a saturated value should at most warn about
268*4882a593Smuzhiyun * being saturated already.
269*4882a593Smuzhiyun */
lkdtm_REFCOUNT_INC_SATURATED(void)270*4882a593Smuzhiyun void lkdtm_REFCOUNT_INC_SATURATED(void)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED);
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun pr_info("attempting bad refcount_inc() from saturated\n");
275*4882a593Smuzhiyun refcount_inc(&sat);
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun check_saturated(&sat);
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun /* Should act like refcount_inc() above from saturated. */
lkdtm_REFCOUNT_DEC_SATURATED(void)281*4882a593Smuzhiyun void lkdtm_REFCOUNT_DEC_SATURATED(void)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED);
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun pr_info("attempting bad refcount_dec() from saturated\n");
286*4882a593Smuzhiyun refcount_dec(&sat);
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun check_saturated(&sat);
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun /* Should act like refcount_inc() above from saturated. */
lkdtm_REFCOUNT_ADD_SATURATED(void)292*4882a593Smuzhiyun void lkdtm_REFCOUNT_ADD_SATURATED(void)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED);
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun pr_info("attempting bad refcount_dec() from saturated\n");
297*4882a593Smuzhiyun refcount_add(8, &sat);
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun check_saturated(&sat);
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun /* Should act like refcount_inc() above from saturated. */
lkdtm_REFCOUNT_INC_NOT_ZERO_SATURATED(void)303*4882a593Smuzhiyun void lkdtm_REFCOUNT_INC_NOT_ZERO_SATURATED(void)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED);
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun pr_info("attempting bad refcount_inc_not_zero() from saturated\n");
308*4882a593Smuzhiyun if (!refcount_inc_not_zero(&sat))
309*4882a593Smuzhiyun pr_warn("Weird: refcount_inc_not_zero() reported zero\n");
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun check_saturated(&sat);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun /* Should act like refcount_inc() above from saturated. */
lkdtm_REFCOUNT_ADD_NOT_ZERO_SATURATED(void)315*4882a593Smuzhiyun void lkdtm_REFCOUNT_ADD_NOT_ZERO_SATURATED(void)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED);
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun pr_info("attempting bad refcount_add_not_zero() from saturated\n");
320*4882a593Smuzhiyun if (!refcount_add_not_zero(7, &sat))
321*4882a593Smuzhiyun pr_warn("Weird: refcount_add_not_zero() reported zero\n");
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun check_saturated(&sat);
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun /* Should act like refcount_inc() above from saturated. */
lkdtm_REFCOUNT_DEC_AND_TEST_SATURATED(void)327*4882a593Smuzhiyun void lkdtm_REFCOUNT_DEC_AND_TEST_SATURATED(void)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED);
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun pr_info("attempting bad refcount_dec_and_test() from saturated\n");
332*4882a593Smuzhiyun if (refcount_dec_and_test(&sat))
333*4882a593Smuzhiyun pr_warn("Weird: refcount_dec_and_test() reported zero\n");
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun check_saturated(&sat);
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun /* Should act like refcount_inc() above from saturated. */
lkdtm_REFCOUNT_SUB_AND_TEST_SATURATED(void)339*4882a593Smuzhiyun void lkdtm_REFCOUNT_SUB_AND_TEST_SATURATED(void)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED);
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun pr_info("attempting bad refcount_sub_and_test() from saturated\n");
344*4882a593Smuzhiyun if (refcount_sub_and_test(8, &sat))
345*4882a593Smuzhiyun pr_warn("Weird: refcount_sub_and_test() reported zero\n");
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun check_saturated(&sat);
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun /* Used to time the existing atomic_t when used for reference counting */
lkdtm_ATOMIC_TIMING(void)351*4882a593Smuzhiyun void lkdtm_ATOMIC_TIMING(void)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun unsigned int i;
354*4882a593Smuzhiyun atomic_t count = ATOMIC_INIT(1);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun for (i = 0; i < INT_MAX - 1; i++)
357*4882a593Smuzhiyun atomic_inc(&count);
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun for (i = INT_MAX; i > 0; i--)
360*4882a593Smuzhiyun if (atomic_dec_and_test(&count))
361*4882a593Smuzhiyun break;
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun if (i != 1)
364*4882a593Smuzhiyun pr_err("atomic timing: out of sync up/down cycle: %u\n", i - 1);
365*4882a593Smuzhiyun else
366*4882a593Smuzhiyun pr_info("atomic timing: done\n");
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun /*
370*4882a593Smuzhiyun * This can be compared to ATOMIC_TIMING when implementing fast refcount
371*4882a593Smuzhiyun * protections. Looking at the number of CPU cycles tells the real story
372*4882a593Smuzhiyun * about performance. For example:
373*4882a593Smuzhiyun * cd /sys/kernel/debug/provoke-crash
374*4882a593Smuzhiyun * perf stat -B -- cat <(echo REFCOUNT_TIMING) > DIRECT
375*4882a593Smuzhiyun */
lkdtm_REFCOUNT_TIMING(void)376*4882a593Smuzhiyun void lkdtm_REFCOUNT_TIMING(void)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun unsigned int i;
379*4882a593Smuzhiyun refcount_t count = REFCOUNT_INIT(1);
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun for (i = 0; i < INT_MAX - 1; i++)
382*4882a593Smuzhiyun refcount_inc(&count);
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun for (i = INT_MAX; i > 0; i--)
385*4882a593Smuzhiyun if (refcount_dec_and_test(&count))
386*4882a593Smuzhiyun break;
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun if (i != 1)
389*4882a593Smuzhiyun pr_err("refcount: out of sync up/down cycle: %u\n", i - 1);
390*4882a593Smuzhiyun else
391*4882a593Smuzhiyun pr_info("refcount timing: done\n");
392*4882a593Smuzhiyun }
393