__aeabi_ldivmod: fix sign logic
[minix.git] / drivers / fbd / action.c
blobdd7d93c1c058bdbf47e764b871ff92e575ded21f
1 #include <minix/drivers.h>
2 #include <sys/ioc_fbd.h>
3 #include <assert.h>
5 #include "rule.h"
7 /*===========================================================================*
8 * get_rand *
9 *===========================================================================*/
10 static u32_t get_rand(u32_t max)
12 /* Las Vegas algorithm for getting a random number in the range from
13 * 0 to max, inclusive.
15 u32_t val, top;
17 /* Get an initial random number. */
18 val = lrand48() ^ (lrand48() << 1);
20 /* Make 'max' exclusive. If it wraps, we can use the full width. */
21 if (++max == 0) return val;
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.
27 top = (((u32_t) -1) / max) * max;
29 while (val >= top)
30 val = lrand48() ^ (lrand48() << 1);
32 return val % max;
35 /*===========================================================================*
36 * get_range *
37 *===========================================================================*/
38 static size_t get_range(struct fbd_rule *rule, u64_t pos, size_t *size,
39 u64_t *skip)
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.
45 u64_t delta;
46 size_t off;
47 int to_eof;
49 to_eof = cmp64(rule->start, rule->end) >= 0;
51 if (cmp64(pos, rule->start) > 0) {
52 if (skip != NULL) *skip = sub64(pos, rule->start);
54 off = 0;
56 else {
57 if (skip != NULL) *skip = cvu64(0);
59 delta = sub64(rule->start, pos);
61 assert(ex64hi(delta) == 0);
63 off = ex64lo(delta);
66 if (!to_eof) {
67 assert(cmp64(pos, rule->end) < 0);
69 delta = sub64(rule->end, pos);
71 if (cmp64u(delta, *size) < 0)
72 *size = ex64lo(delta);
75 assert(*size > off);
77 *size -= off;
79 return off;
82 /*===========================================================================*
83 * limit_range *
84 *===========================================================================*/
85 static void limit_range(iovec_t *iov, unsigned *count, size_t size)
87 /* Limit the given vector to the given size.
89 size_t chunk;
90 int i;
92 for (i = 0; i < *count && size > 0; i++) {
93 chunk = MIN(iov[i].iov_size, size);
95 if (chunk == size)
96 iov[i].iov_size = size;
98 size -= chunk;
101 *count = i;
104 /*===========================================================================*
105 * action_io_corrupt *
106 *===========================================================================*/
107 static void action_io_corrupt(struct fbd_rule *rule, char *buf, size_t size,
108 u64_t pos, int UNUSED(flag))
110 u64_t skip;
111 u32_t val;
113 buf += get_range(rule, pos, &size, &skip);
115 switch (rule->params.corrupt.type) {
116 case FBD_CORRUPT_ZERO:
117 memset(buf, 0, size);
118 break;
120 case FBD_CORRUPT_PERSIST:
121 /* Non-dword-aligned positions and sizes are not supported;
122 * not by us, and not by the driver.
124 if (ex64lo(pos) & (sizeof(val) - 1)) break;
125 if (size & (sizeof(val) - 1)) break;
127 /* Consistently produce the same pattern for the same range. */
128 val = ex64lo(skip);
130 for ( ; size >= sizeof(val); size -= sizeof(val)) {
131 *((u32_t *) buf) = val ^ 0xdeadbeefUL;
133 val += sizeof(val);
134 buf += sizeof(val);
137 break;
139 case FBD_CORRUPT_RANDOM:
140 while (size--)
141 *buf++ = get_rand(255);
143 break;
145 default:
146 printf("FBD: unknown corruption type %d\n",
147 rule->params.corrupt.type);
151 /*===========================================================================*
152 * action_pre_error *
153 *===========================================================================*/
154 static void action_pre_error(struct fbd_rule *rule, iovec_t *iov,
155 unsigned *count, size_t *size, u64_t *pos)
157 /* Limit the request to the part that precedes the matched range. */
158 *size = get_range(rule, *pos, size, NULL);
160 limit_range(iov, count, *size);
163 /*===========================================================================*
164 * action_post_error *
165 *===========================================================================*/
166 static void action_post_error(struct fbd_rule *rule, size_t UNUSED(osize),
167 int *result)
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;
174 /*===========================================================================*
175 * action_pre_misdir *
176 *===========================================================================*/
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)
180 /* Randomize the request position to fall within the range (and have
181 * the alignment) given by the rule.
183 u32_t range, choice;
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..
189 range = div64u(add64u(sub64(rule->params.misdir.end,
190 rule->params.misdir.start), 1), rule->params.misdir.align);
192 if (range > 0)
193 choice = get_rand(range - 1);
194 else
195 choice = 0;
197 *pos = add64(rule->params.misdir.start,
198 mul64u(choice, rule->params.misdir.align));
201 /*===========================================================================*
202 * action_pre_losttorn *
203 *===========================================================================*/
204 static void action_pre_losttorn(struct fbd_rule *rule, iovec_t *iov,
205 unsigned *count, size_t *size, u64_t *UNUSED(pos))
207 if (*size > rule->params.losttorn.lead)
208 *size = rule->params.losttorn.lead;
210 limit_range(iov, count, *size);
213 /*===========================================================================*
214 * action_post_losttorn *
215 *===========================================================================*/
216 static void action_post_losttorn(struct fbd_rule *UNUSED(rule), size_t osize,
217 int *result)
219 /* On success, pretend full completion. */
221 if (*result < 0) return;
223 *result = osize;
226 /*===========================================================================*
227 * action_mask *
228 *===========================================================================*/
229 int action_mask(struct fbd_rule *rule)
231 /* Return the hook mask for the given rule's action type. */
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;
244 /*===========================================================================*
245 * action_pre_hook *
246 *===========================================================================*/
247 void action_pre_hook(struct fbd_rule *rule, iovec_t *iov,
248 unsigned *count, size_t *size, u64_t *pos)
250 switch (rule->action) {
251 case FBD_ACTION_ERROR:
252 action_pre_error(rule, iov, count, size, pos);
253 break;
255 case FBD_ACTION_MISDIR:
256 action_pre_misdir(rule, iov, count, size, pos);
257 break;
259 case FBD_ACTION_LOSTTORN:
260 action_pre_losttorn(rule, iov, count, size, pos);
261 break;
263 default:
264 printf("FBD: bad action type %d for PRE hook\n", rule->action);
268 /*===========================================================================*
269 * action_io_hook *
270 *===========================================================================*/
271 void action_io_hook(struct fbd_rule *rule, char *buf, size_t size,
272 u64_t pos, int flag)
274 switch (rule->action) {
275 case FBD_ACTION_CORRUPT:
276 action_io_corrupt(rule, buf, size, pos, flag);
277 break;
279 default:
280 printf("FBD: bad action type %d for IO hook\n", rule->action);
284 /*===========================================================================*
285 * action_post_hook *
286 *===========================================================================*/
287 void action_post_hook(struct fbd_rule *rule, size_t osize, int *result)
289 switch (rule->action) {
290 case FBD_ACTION_ERROR:
291 action_post_error(rule, osize, result);
292 return;
294 case FBD_ACTION_LOSTTORN:
295 action_post_losttorn(rule, osize, result);
296 return;
298 default:
299 printf("FBD: bad action type %d for POST hook\n",
300 rule->action);