Commit | Line | Data |
---|---|---|
d7e09d03 PT |
1 | /* |
2 | * GPL HEADER START | |
3 | * | |
4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 only, | |
8 | * as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * General Public License version 2 for more details (a copy is included | |
14 | * in the LICENSE file that accompanied this code). | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * version 2 along with this program; If not, see http://www.gnu.org/licenses | |
18 | * | |
19 | * Please contact Oracle Corporation, Inc., 500 Oracle Parkway, Redwood Shores, | |
20 | * CA 94065 USA or visit www.oracle.com if you need additional information or | |
21 | * have any questions. | |
22 | * | |
23 | * GPL HEADER END | |
24 | */ | |
25 | /* | |
26 | * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. | |
27 | * Use is subject to license terms. | |
28 | * | |
29 | * Copyright (c) 2011, 2012, Intel Corporation. | |
30 | */ | |
31 | /* | |
32 | * This file is part of Lustre, http://www.lustre.org/ | |
33 | * Lustre is a trademark of Oracle Corporation, Inc. | |
34 | */ | |
35 | ||
36 | #ifndef _LIBCFS_FAIL_H | |
37 | #define _LIBCFS_FAIL_H | |
38 | ||
39 | extern unsigned long cfs_fail_loc; | |
40 | extern unsigned int cfs_fail_val; | |
41 | ||
42 | extern wait_queue_head_t cfs_race_waitq; | |
43 | extern int cfs_race_state; | |
44 | ||
45 | int __cfs_fail_check_set(__u32 id, __u32 value, int set); | |
46 | int __cfs_fail_timeout_set(__u32 id, __u32 value, int ms, int set); | |
47 | ||
48 | enum { | |
49 | CFS_FAIL_LOC_NOSET = 0, | |
50 | CFS_FAIL_LOC_ORSET = 1, | |
51 | CFS_FAIL_LOC_RESET = 2, | |
52 | CFS_FAIL_LOC_VALUE = 3 | |
53 | }; | |
54 | ||
55 | /* Failure injection control */ | |
56 | #define CFS_FAIL_MASK_SYS 0x0000FF00 | |
57 | #define CFS_FAIL_MASK_LOC (0x000000FF | CFS_FAIL_MASK_SYS) | |
58 | ||
59 | #define CFS_FAILED_BIT 30 | |
60 | /* CFS_FAILED is 0x40000000 */ | |
61 | #define CFS_FAILED (1 << CFS_FAILED_BIT) | |
62 | ||
63 | #define CFS_FAIL_ONCE_BIT 31 | |
64 | /* CFS_FAIL_ONCE is 0x80000000 */ | |
65 | #define CFS_FAIL_ONCE (1 << CFS_FAIL_ONCE_BIT) | |
66 | ||
67 | /* The following flags aren't made to be combined */ | |
68 | #define CFS_FAIL_SKIP 0x20000000 /* skip N times then fail */ | |
69 | #define CFS_FAIL_SOME 0x10000000 /* only fail N times */ | |
70 | #define CFS_FAIL_RAND 0x08000000 /* fail 1/N of the times */ | |
71 | #define CFS_FAIL_USR1 0x04000000 /* user flag */ | |
72 | ||
73 | #define CFS_FAIL_PRECHECK(id) (cfs_fail_loc && \ | |
74 | (cfs_fail_loc & CFS_FAIL_MASK_LOC) == \ | |
75 | ((id) & CFS_FAIL_MASK_LOC)) | |
76 | ||
77 | static inline int cfs_fail_check_set(__u32 id, __u32 value, | |
78 | int set, int quiet) | |
79 | { | |
80 | int ret = 0; | |
81 | ||
3e9f88e6 PH |
82 | if (unlikely(CFS_FAIL_PRECHECK(id))) { |
83 | ret = __cfs_fail_check_set(id, value, set); | |
84 | if (ret) { | |
85 | if (quiet) { | |
86 | CDEBUG(D_INFO, "*** cfs_fail_loc=%x, val=%u***\n", | |
87 | id, value); | |
88 | } else { | |
89 | LCONSOLE_INFO("*** cfs_fail_loc=%x, val=%u***\n", | |
90 | id, value); | |
91 | } | |
d7e09d03 PT |
92 | } |
93 | } | |
94 | ||
95 | return ret; | |
96 | } | |
97 | ||
98 | /* If id hit cfs_fail_loc, return 1, otherwise return 0 */ | |
99 | #define CFS_FAIL_CHECK(id) \ | |
100 | cfs_fail_check_set(id, 0, CFS_FAIL_LOC_NOSET, 0) | |
101 | #define CFS_FAIL_CHECK_QUIET(id) \ | |
102 | cfs_fail_check_set(id, 0, CFS_FAIL_LOC_NOSET, 1) | |
103 | ||
104 | /* If id hit cfs_fail_loc and cfs_fail_val == (-1 or value) return 1, | |
105 | * otherwise return 0 */ | |
106 | #define CFS_FAIL_CHECK_VALUE(id, value) \ | |
107 | cfs_fail_check_set(id, value, CFS_FAIL_LOC_VALUE, 0) | |
108 | #define CFS_FAIL_CHECK_VALUE_QUIET(id, value) \ | |
109 | cfs_fail_check_set(id, value, CFS_FAIL_LOC_VALUE, 1) | |
110 | ||
111 | /* If id hit cfs_fail_loc, cfs_fail_loc |= value and return 1, | |
112 | * otherwise return 0 */ | |
113 | #define CFS_FAIL_CHECK_ORSET(id, value) \ | |
114 | cfs_fail_check_set(id, value, CFS_FAIL_LOC_ORSET, 0) | |
115 | #define CFS_FAIL_CHECK_ORSET_QUIET(id, value) \ | |
116 | cfs_fail_check_set(id, value, CFS_FAIL_LOC_ORSET, 1) | |
117 | ||
118 | /* If id hit cfs_fail_loc, cfs_fail_loc = value and return 1, | |
119 | * otherwise return 0 */ | |
120 | #define CFS_FAIL_CHECK_RESET(id, value) \ | |
121 | cfs_fail_check_set(id, value, CFS_FAIL_LOC_RESET, 0) | |
122 | #define CFS_FAIL_CHECK_RESET_QUIET(id, value) \ | |
123 | cfs_fail_check_set(id, value, CFS_FAIL_LOC_RESET, 1) | |
124 | ||
125 | static inline int cfs_fail_timeout_set(__u32 id, __u32 value, int ms, int set) | |
126 | { | |
127 | if (unlikely(CFS_FAIL_PRECHECK(id))) | |
128 | return __cfs_fail_timeout_set(id, value, ms, set); | |
4467a945 | 129 | return 0; |
d7e09d03 PT |
130 | } |
131 | ||
132 | /* If id hit cfs_fail_loc, sleep for seconds or milliseconds */ | |
133 | #define CFS_FAIL_TIMEOUT(id, secs) \ | |
134 | cfs_fail_timeout_set(id, 0, secs * 1000, CFS_FAIL_LOC_NOSET) | |
135 | ||
136 | #define CFS_FAIL_TIMEOUT_MS(id, ms) \ | |
137 | cfs_fail_timeout_set(id, 0, ms, CFS_FAIL_LOC_NOSET) | |
138 | ||
139 | /* If id hit cfs_fail_loc, cfs_fail_loc |= value and | |
140 | * sleep seconds or milliseconds */ | |
141 | #define CFS_FAIL_TIMEOUT_ORSET(id, value, secs) \ | |
142 | cfs_fail_timeout_set(id, value, secs * 1000, CFS_FAIL_LOC_ORSET) | |
143 | ||
144 | #define CFS_FAIL_TIMEOUT_MS_ORSET(id, value, ms) \ | |
145 | cfs_fail_timeout_set(id, value, ms, CFS_FAIL_LOC_ORSET) | |
146 | ||
147 | /* The idea here is to synchronise two threads to force a race. The | |
148 | * first thread that calls this with a matching fail_loc is put to | |
149 | * sleep. The next thread that calls with the same fail_loc wakes up | |
150 | * the first and continues. */ | |
151 | static inline void cfs_race(__u32 id) | |
152 | { | |
153 | ||
154 | if (CFS_FAIL_PRECHECK(id)) { | |
155 | if (unlikely(__cfs_fail_check_set(id, 0, CFS_FAIL_LOC_NOSET))) { | |
156 | int rc; | |
a393fd54 | 157 | |
d7e09d03 PT |
158 | cfs_race_state = 0; |
159 | CERROR("cfs_race id %x sleeping\n", id); | |
46ffc934 JS |
160 | rc = wait_event_interruptible(cfs_race_waitq, |
161 | cfs_race_state != 0); | |
d7e09d03 PT |
162 | CERROR("cfs_fail_race id %x awake, rc=%d\n", id, rc); |
163 | } else { | |
164 | CERROR("cfs_fail_race id %x waking\n", id); | |
165 | cfs_race_state = 1; | |
166 | wake_up(&cfs_race_waitq); | |
167 | } | |
168 | } | |
169 | } | |
a393fd54 | 170 | |
d7e09d03 PT |
171 | #define CFS_RACE(id) cfs_race(id) |
172 | ||
173 | #endif /* _LIBCFS_FAIL_H */ |