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