1 #include <minix/drivers.h>
2 #include <sys/ioc_fbd.h>
3 #include <assert.h>
4
5 #include "rule.h"
6
7 /*===========================================================================*
8 * get_rand *
9 *===========================================================================*/
get_rand(u32_t max)10 static u32_t get_rand(u32_t max)
11 {
12 /* Las Vegas algorithm for getting a random number in the range from
13 * 0 to max, inclusive.
14 */
15 u32_t val, top;
16
17 /* Get an initial random number. */
18 val = lrand48() ^ (lrand48() << 1);
19
20 /* Make 'max' exclusive. If it wraps, we can use the full width. */
21 if (++max == 0) return val;
22
23 /* Find the largest multiple of the given range, and return a random
24 * number from the range, throwing away any random numbers not below
25 * this largest multiple.
26 */
27 top = (((u32_t) -1) / max) * max;
28
29 while (val >= top)
30 val = lrand48() ^ (lrand48() << 1);
31
32 return val % max;
33 }
34
35 /*===========================================================================*
36 * get_range *
37 *===========================================================================*/
get_range(struct fbd_rule * rule,u64_t pos,size_t * size,u64_t * skip)38 static size_t get_range(struct fbd_rule *rule, u64_t pos, size_t *size,
39 u64_t *skip)
40 {
41 /* Compute the range within the given request range that is affected
42 * by the given rule, and optionally the number of bytes preceding
43 * the range that are also affected by the rule.
44 */
45 u64_t delta;
46 size_t off;
47 int to_eof;
48
49 to_eof = rule->start >= rule->end;
50
51 if (pos > rule->start) {
52 if (skip != NULL) *skip = pos - rule->start;
53
54 off = 0;
55 }
56 else {
57 if (skip != NULL) *skip = ((u64_t)(0));
58
59 delta = rule->start - pos;
60
61 assert(ex64hi(delta) == 0);
62
63 off = ex64lo(delta);
64 }
65
66 if (!to_eof) {
67 assert(pos < rule->end);
68
69 delta = rule->end - pos;
70
71 if (delta < *size)
72 *size = ex64lo(delta);
73 }
74
75 assert(*size > off);
76
77 *size -= off;
78
79 return off;
80 }
81
82 /*===========================================================================*
83 * limit_range *
84 *===========================================================================*/
limit_range(iovec_t * iov,unsigned * count,size_t size)85 static void limit_range(iovec_t *iov, unsigned *count, size_t size)
86 {
87 /* Limit the given vector to the given size.
88 */
89 size_t chunk;
90 int i;
91
92 for (i = 0; i < *count && size > 0; i++) {
93 chunk = MIN(iov[i].iov_size, size);
94
95 if (chunk == size)
96 iov[i].iov_size = size;
97
98 size -= chunk;
99 }
100
101 *count = i;
102 }
103
104 /*===========================================================================*
105 * action_io_corrupt *
106 *===========================================================================*/
action_io_corrupt(struct fbd_rule * rule,char * buf,size_t size,u64_t pos,int UNUSED (flag))107 static void action_io_corrupt(struct fbd_rule *rule, char *buf, size_t size,
108 u64_t pos, int UNUSED(flag))
109 {
110 u64_t skip;
111 u32_t val;
112
113 buf += get_range(rule, pos, &size, &skip);
114
115 switch (rule->params.corrupt.type) {
116 case FBD_CORRUPT_ZERO:
117 memset(buf, 0, size);
118 break;
119
120 case FBD_CORRUPT_PERSIST:
121 /* Non-dword-aligned positions and sizes are not supported;
122 * not by us, and not by the driver.
123 */
124 if (ex64lo(pos) & (sizeof(val) - 1)) break;
125 if (size & (sizeof(val) - 1)) break;
126
127 /* Consistently produce the same pattern for the same range. */
128 val = ex64lo(skip);
129
130 for ( ; size >= sizeof(val); size -= sizeof(val)) {
131 *((u32_t *) buf) = val ^ 0xdeadbeefUL;
132
133 val += sizeof(val);
134 buf += sizeof(val);
135 }
136
137 break;
138
139 case FBD_CORRUPT_RANDOM:
140 while (size--)
141 *buf++ = get_rand(255);
142
143 break;
144
145 default:
146 printf("FBD: unknown corruption type %d\n",
147 rule->params.corrupt.type);
148 }
149 }
150
151 /*===========================================================================*
152 * action_pre_error *
153 *===========================================================================*/
action_pre_error(struct fbd_rule * rule,iovec_t * iov,unsigned * count,size_t * size,u64_t * pos)154 static void action_pre_error(struct fbd_rule *rule, iovec_t *iov,
155 unsigned *count, size_t *size, u64_t *pos)
156 {
157 /* Limit the request to the part that precedes the matched range. */
158 *size = get_range(rule, *pos, size, NULL);
159
160 limit_range(iov, count, *size);
161 }
162
163 /*===========================================================================*
164 * action_post_error *
165 *===========================================================================*/
action_post_error(struct fbd_rule * rule,size_t UNUSED (osize),int * result)166 static void action_post_error(struct fbd_rule *rule, size_t UNUSED(osize),
167 int *result)
168 {
169 /* Upon success of the first part, return the specified error code. */
170 if (*result >= 0 && rule->params.error.code != OK)
171 *result = rule->params.error.code;
172 }
173
174 /*===========================================================================*
175 * action_pre_misdir *
176 *===========================================================================*/
action_pre_misdir(struct fbd_rule * rule,iovec_t * UNUSED (iov),unsigned * UNUSED (count),size_t * UNUSED (size),u64_t * pos)177 static void action_pre_misdir(struct fbd_rule *rule, iovec_t *UNUSED(iov),
178 unsigned *UNUSED(count), size_t *UNUSED(size), u64_t *pos)
179 {
180 /* Randomize the request position to fall within the range (and have
181 * the alignment) given by the rule.
182 */
183 u32_t range, choice;
184
185 /* Unfortunately, we cannot interpret 0 as end as "up to end of disk"
186 * here, because we have no idea about the actual disk size, and the
187 * resulting address must of course be valid..
188 */
189 range = ((rule->params.misdir.end - rule->params.misdir.start) + 1)
190 / rule->params.misdir.align;
191
192 if (range > 0)
193 choice = get_rand(range - 1);
194 else
195 choice = 0;
196
197 *pos = rule->params.misdir.start +
198 ((u64_t)choice * rule->params.misdir.align);
199 }
200
201 /*===========================================================================*
202 * action_pre_losttorn *
203 *===========================================================================*/
action_pre_losttorn(struct fbd_rule * rule,iovec_t * iov,unsigned * count,size_t * size,u64_t * UNUSED (pos))204 static void action_pre_losttorn(struct fbd_rule *rule, iovec_t *iov,
205 unsigned *count, size_t *size, u64_t *UNUSED(pos))
206 {
207 if (*size > rule->params.losttorn.lead)
208 *size = rule->params.losttorn.lead;
209
210 limit_range(iov, count, *size);
211 }
212
213 /*===========================================================================*
214 * action_post_losttorn *
215 *===========================================================================*/
action_post_losttorn(struct fbd_rule * UNUSED (rule),size_t osize,int * result)216 static void action_post_losttorn(struct fbd_rule *UNUSED(rule), size_t osize,
217 int *result)
218 {
219 /* On success, pretend full completion. */
220
221 if (*result < 0) return;
222
223 *result = osize;
224 }
225
226 /*===========================================================================*
227 * action_mask *
228 *===========================================================================*/
action_mask(struct fbd_rule * rule)229 int action_mask(struct fbd_rule *rule)
230 {
231 /* Return the hook mask for the given rule's action type. */
232
233 switch (rule->action) {
234 case FBD_ACTION_CORRUPT: return IO_HOOK;
235 case FBD_ACTION_ERROR: return PRE_HOOK | POST_HOOK;
236 case FBD_ACTION_MISDIR: return PRE_HOOK;
237 case FBD_ACTION_LOSTTORN: return PRE_HOOK | POST_HOOK;
238 default:
239 printf("FBD: unknown action type %d\n", rule->action);
240 return 0;
241 }
242 }
243
244 /*===========================================================================*
245 * action_pre_hook *
246 *===========================================================================*/
action_pre_hook(struct fbd_rule * rule,iovec_t * iov,unsigned * count,size_t * size,u64_t * pos)247 void action_pre_hook(struct fbd_rule *rule, iovec_t *iov,
248 unsigned *count, size_t *size, u64_t *pos)
249 {
250 switch (rule->action) {
251 case FBD_ACTION_ERROR:
252 action_pre_error(rule, iov, count, size, pos);
253 break;
254
255 case FBD_ACTION_MISDIR:
256 action_pre_misdir(rule, iov, count, size, pos);
257 break;
258
259 case FBD_ACTION_LOSTTORN:
260 action_pre_losttorn(rule, iov, count, size, pos);
261 break;
262
263 default:
264 printf("FBD: bad action type %d for PRE hook\n", rule->action);
265 }
266 }
267
268 /*===========================================================================*
269 * action_io_hook *
270 *===========================================================================*/
action_io_hook(struct fbd_rule * rule,char * buf,size_t size,u64_t pos,int flag)271 void action_io_hook(struct fbd_rule *rule, char *buf, size_t size,
272 u64_t pos, int flag)
273 {
274 switch (rule->action) {
275 case FBD_ACTION_CORRUPT:
276 action_io_corrupt(rule, buf, size, pos, flag);
277 break;
278
279 default:
280 printf("FBD: bad action type %d for IO hook\n", rule->action);
281 }
282 }
283
284 /*===========================================================================*
285 * action_post_hook *
286 *===========================================================================*/
action_post_hook(struct fbd_rule * rule,size_t osize,int * result)287 void action_post_hook(struct fbd_rule *rule, size_t osize, int *result)
288 {
289 switch (rule->action) {
290 case FBD_ACTION_ERROR:
291 action_post_error(rule, osize, result);
292 return;
293
294 case FBD_ACTION_LOSTTORN:
295 action_post_losttorn(rule, osize, result);
296 return;
297
298 default:
299 printf("FBD: bad action type %d for POST hook\n",
300 rule->action);
301 }
302 }
303