1 #include <minix/drivers.h>
2 #include <sys/ioc_fbd.h>
7 /*===========================================================================*
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.
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
;
30 val
= lrand48() ^ (lrand48() << 1);
35 /*===========================================================================*
37 *===========================================================================*/
38 static size_t get_range(struct fbd_rule
*rule
, u64_t pos
, size_t *size
,
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.
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
);
57 if (skip
!= NULL
) *skip
= cvu64(0);
59 delta
= sub64(rule
->start
, pos
);
61 assert(ex64hi(delta
) == 0);
67 assert(cmp64(pos
, rule
->end
) < 0);
69 delta
= sub64(rule
->end
, pos
);
71 if (cmp64u(delta
, *size
) < 0)
72 *size
= ex64lo(delta
);
82 /*===========================================================================*
84 *===========================================================================*/
85 static void limit_range(iovec_t
*iov
, unsigned *count
, size_t size
)
87 /* Limit the given vector to the given size.
92 for (i
= 0; i
< *count
&& size
> 0; i
++) {
93 chunk
= MIN(iov
[i
].iov_size
, size
);
96 iov
[i
].iov_size
= size
;
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
))
113 buf
+= get_range(rule
, pos
, &size
, &skip
);
115 switch (rule
->params
.corrupt
.type
) {
116 case FBD_CORRUPT_ZERO
:
117 memset(buf
, 0, size
);
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. */
130 for ( ; size
>= sizeof(val
); size
-= sizeof(val
)) {
131 *((u32_t
*) buf
) = val
^ 0xdeadbeefUL
;
139 case FBD_CORRUPT_RANDOM
:
141 *buf
++ = get_rand(255);
146 printf("FBD: unknown corruption type %d\n",
147 rule
->params
.corrupt
.type
);
151 /*===========================================================================*
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
),
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.
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
);
193 choice
= get_rand(range
- 1);
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
,
219 /* On success, pretend full completion. */
221 if (*result
< 0) return;
226 /*===========================================================================*
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
;
239 printf("FBD: unknown action type %d\n", rule
->action
);
244 /*===========================================================================*
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
);
255 case FBD_ACTION_MISDIR
:
256 action_pre_misdir(rule
, iov
, count
, size
, pos
);
259 case FBD_ACTION_LOSTTORN
:
260 action_pre_losttorn(rule
, iov
, count
, size
, pos
);
264 printf("FBD: bad action type %d for PRE hook\n", rule
->action
);
268 /*===========================================================================*
270 *===========================================================================*/
271 void action_io_hook(struct fbd_rule
*rule
, char *buf
, size_t size
,
274 switch (rule
->action
) {
275 case FBD_ACTION_CORRUPT
:
276 action_io_corrupt(rule
, buf
, size
, pos
, flag
);
280 printf("FBD: bad action type %d for IO hook\n", rule
->action
);
284 /*===========================================================================*
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
);
294 case FBD_ACTION_LOSTTORN
:
295 action_post_losttorn(rule
, osize
, result
);
299 printf("FBD: bad action type %d for POST hook\n",