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 *===========================================================================*/ 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 *===========================================================================*/ 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 *===========================================================================*/ 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 *===========================================================================*/ 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 *===========================================================================*/ 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 *===========================================================================*/ 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 *===========================================================================*/ 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 *===========================================================================*/ 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 *===========================================================================*/ 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 *===========================================================================*/ 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 *===========================================================================*/ 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 *===========================================================================*/ 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 *===========================================================================*/ 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