xref: /minix3/minix/drivers/storage/fbd/action.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
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