1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2003 Sistina Software (UK) Limited. 4 * Copyright (C) 2004, 2010-2011 Red Hat, Inc. All rights reserved. 5 * 6 * This file is released under the GPL. 7 */ 8 9 #include <linux/device-mapper.h> 10 11 #include <linux/module.h> 12 #include <linux/init.h> 13 #include <linux/blkdev.h> 14 #include <linux/bio.h> 15 #include <linux/slab.h> 16 17 #define DM_MSG_PREFIX "flakey" 18 19 #define all_corrupt_bio_flags_match(bio, fc) \ 20 (((bio)->bi_opf & (fc)->corrupt_bio_flags) == (fc)->corrupt_bio_flags) 21 22 /* 23 * Flakey: Used for testing only, simulates intermittent, 24 * catastrophic device failure. 25 */ 26 struct flakey_c { 27 struct dm_dev *dev; 28 unsigned long start_time; 29 sector_t start; 30 unsigned int up_interval; 31 unsigned int down_interval; 32 unsigned long flags; 33 unsigned int corrupt_bio_byte; 34 unsigned int corrupt_bio_rw; 35 unsigned int corrupt_bio_value; 36 blk_opf_t corrupt_bio_flags; 37 }; 38 39 enum feature_flag_bits { 40 ERROR_READS, 41 DROP_WRITES, 42 ERROR_WRITES 43 }; 44 45 struct per_bio_data { 46 bool bio_submitted; 47 }; 48 49 static int parse_features(struct dm_arg_set *as, struct flakey_c *fc, 50 struct dm_target *ti) 51 { 52 int r; 53 unsigned int argc; 54 const char *arg_name; 55 56 static const struct dm_arg _args[] = { 57 {0, 7, "Invalid number of feature args"}, 58 {1, UINT_MAX, "Invalid corrupt bio byte"}, 59 {0, 255, "Invalid corrupt value to write into bio byte (0-255)"}, 60 {0, UINT_MAX, "Invalid corrupt bio flags mask"}, 61 }; 62 63 /* No feature arguments supplied. */ 64 if (!as->argc) 65 return 0; 66 67 r = dm_read_arg_group(_args, as, &argc, &ti->error); 68 if (r) 69 return r; 70 71 while (argc) { 72 arg_name = dm_shift_arg(as); 73 argc--; 74 75 if (!arg_name) { 76 ti->error = "Insufficient feature arguments"; 77 return -EINVAL; 78 } 79 80 /* 81 * error_reads 82 */ 83 if (!strcasecmp(arg_name, "error_reads")) { 84 if (test_and_set_bit(ERROR_READS, &fc->flags)) { 85 ti->error = "Feature error_reads duplicated"; 86 return -EINVAL; 87 } 88 continue; 89 } 90 91 /* 92 * drop_writes 93 */ 94 if (!strcasecmp(arg_name, "drop_writes")) { 95 if (test_and_set_bit(DROP_WRITES, &fc->flags)) { 96 ti->error = "Feature drop_writes duplicated"; 97 return -EINVAL; 98 } else if (test_bit(ERROR_WRITES, &fc->flags)) { 99 ti->error = "Feature drop_writes conflicts with feature error_writes"; 100 return -EINVAL; 101 } 102 103 continue; 104 } 105 106 /* 107 * error_writes 108 */ 109 if (!strcasecmp(arg_name, "error_writes")) { 110 if (test_and_set_bit(ERROR_WRITES, &fc->flags)) { 111 ti->error = "Feature error_writes duplicated"; 112 return -EINVAL; 113 114 } else if (test_bit(DROP_WRITES, &fc->flags)) { 115 ti->error = "Feature error_writes conflicts with feature drop_writes"; 116 return -EINVAL; 117 } 118 119 continue; 120 } 121 122 /* 123 * corrupt_bio_byte <Nth_byte> <direction> <value> <bio_flags> 124 */ 125 if (!strcasecmp(arg_name, "corrupt_bio_byte")) { 126 if (!argc) { 127 ti->error = "Feature corrupt_bio_byte requires parameters"; 128 return -EINVAL; 129 } 130 131 r = dm_read_arg(_args + 1, as, &fc->corrupt_bio_byte, &ti->error); 132 if (r) 133 return r; 134 argc--; 135 136 /* 137 * Direction r or w? 138 */ 139 arg_name = dm_shift_arg(as); 140 if (arg_name && !strcasecmp(arg_name, "w")) 141 fc->corrupt_bio_rw = WRITE; 142 else if (arg_name && !strcasecmp(arg_name, "r")) 143 fc->corrupt_bio_rw = READ; 144 else { 145 ti->error = "Invalid corrupt bio direction (r or w)"; 146 return -EINVAL; 147 } 148 argc--; 149 150 /* 151 * Value of byte (0-255) to write in place of correct one. 152 */ 153 r = dm_read_arg(_args + 2, as, &fc->corrupt_bio_value, &ti->error); 154 if (r) 155 return r; 156 argc--; 157 158 /* 159 * Only corrupt bios with these flags set. 160 */ 161 BUILD_BUG_ON(sizeof(fc->corrupt_bio_flags) != 162 sizeof(unsigned int)); 163 r = dm_read_arg(_args + 3, as, 164 (__force unsigned int *)&fc->corrupt_bio_flags, 165 &ti->error); 166 if (r) 167 return r; 168 argc--; 169 170 continue; 171 } 172 173 ti->error = "Unrecognised flakey feature requested"; 174 return -EINVAL; 175 } 176 177 if (test_bit(DROP_WRITES, &fc->flags) && (fc->corrupt_bio_rw == WRITE)) { 178 ti->error = "drop_writes is incompatible with corrupt_bio_byte with the WRITE flag set"; 179 return -EINVAL; 180 181 } else if (test_bit(ERROR_WRITES, &fc->flags) && (fc->corrupt_bio_rw == WRITE)) { 182 ti->error = "error_writes is incompatible with corrupt_bio_byte with the WRITE flag set"; 183 return -EINVAL; 184 } 185 186 if (!fc->corrupt_bio_byte && !test_bit(ERROR_READS, &fc->flags) && 187 !test_bit(DROP_WRITES, &fc->flags) && !test_bit(ERROR_WRITES, &fc->flags)) { 188 set_bit(ERROR_WRITES, &fc->flags); 189 set_bit(ERROR_READS, &fc->flags); 190 } 191 192 return 0; 193 } 194 195 /* 196 * Construct a flakey mapping: 197 * <dev_path> <offset> <up interval> <down interval> [<#feature args> [<arg>]*] 198 * 199 * Feature args: 200 * [drop_writes] 201 * [corrupt_bio_byte <Nth_byte> <direction> <value> <bio_flags>] 202 * 203 * Nth_byte starts from 1 for the first byte. 204 * Direction is r for READ or w for WRITE. 205 * bio_flags is ignored if 0. 206 */ 207 static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv) 208 { 209 static const struct dm_arg _args[] = { 210 {0, UINT_MAX, "Invalid up interval"}, 211 {0, UINT_MAX, "Invalid down interval"}, 212 }; 213 214 int r; 215 struct flakey_c *fc; 216 unsigned long long tmpll; 217 struct dm_arg_set as; 218 const char *devname; 219 char dummy; 220 221 as.argc = argc; 222 as.argv = argv; 223 224 if (argc < 4) { 225 ti->error = "Invalid argument count"; 226 return -EINVAL; 227 } 228 229 fc = kzalloc(sizeof(*fc), GFP_KERNEL); 230 if (!fc) { 231 ti->error = "Cannot allocate context"; 232 return -ENOMEM; 233 } 234 fc->start_time = jiffies; 235 236 devname = dm_shift_arg(&as); 237 238 r = -EINVAL; 239 if (sscanf(dm_shift_arg(&as), "%llu%c", &tmpll, &dummy) != 1 || tmpll != (sector_t)tmpll) { 240 ti->error = "Invalid device sector"; 241 goto bad; 242 } 243 fc->start = tmpll; 244 245 r = dm_read_arg(_args, &as, &fc->up_interval, &ti->error); 246 if (r) 247 goto bad; 248 249 r = dm_read_arg(_args, &as, &fc->down_interval, &ti->error); 250 if (r) 251 goto bad; 252 253 if (!(fc->up_interval + fc->down_interval)) { 254 ti->error = "Total (up + down) interval is zero"; 255 r = -EINVAL; 256 goto bad; 257 } 258 259 if (fc->up_interval + fc->down_interval < fc->up_interval) { 260 ti->error = "Interval overflow"; 261 r = -EINVAL; 262 goto bad; 263 } 264 265 r = parse_features(&as, fc, ti); 266 if (r) 267 goto bad; 268 269 r = dm_get_device(ti, devname, dm_table_get_mode(ti->table), &fc->dev); 270 if (r) { 271 ti->error = "Device lookup failed"; 272 goto bad; 273 } 274 275 ti->num_flush_bios = 1; 276 ti->num_discard_bios = 1; 277 ti->per_io_data_size = sizeof(struct per_bio_data); 278 ti->private = fc; 279 return 0; 280 281 bad: 282 kfree(fc); 283 return r; 284 } 285 286 static void flakey_dtr(struct dm_target *ti) 287 { 288 struct flakey_c *fc = ti->private; 289 290 dm_put_device(ti, fc->dev); 291 kfree(fc); 292 } 293 294 static sector_t flakey_map_sector(struct dm_target *ti, sector_t bi_sector) 295 { 296 struct flakey_c *fc = ti->private; 297 298 return fc->start + dm_target_offset(ti, bi_sector); 299 } 300 301 static void flakey_map_bio(struct dm_target *ti, struct bio *bio) 302 { 303 struct flakey_c *fc = ti->private; 304 305 bio_set_dev(bio, fc->dev->bdev); 306 bio->bi_iter.bi_sector = flakey_map_sector(ti, bio->bi_iter.bi_sector); 307 } 308 309 static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc) 310 { 311 unsigned int corrupt_bio_byte = fc->corrupt_bio_byte - 1; 312 313 struct bvec_iter iter; 314 struct bio_vec bvec; 315 316 if (!bio_has_data(bio)) 317 return; 318 319 /* 320 * Overwrite the Nth byte of the bio's data, on whichever page 321 * it falls. 322 */ 323 bio_for_each_segment(bvec, bio, iter) { 324 if (bio_iter_len(bio, iter) > corrupt_bio_byte) { 325 char *segment = bvec_kmap_local(&bvec); 326 segment[corrupt_bio_byte] = fc->corrupt_bio_value; 327 kunmap_local(segment); 328 DMDEBUG("Corrupting data bio=%p by writing %u to byte %u " 329 "(rw=%c bi_opf=%u bi_sector=%llu size=%u)\n", 330 bio, fc->corrupt_bio_value, fc->corrupt_bio_byte, 331 (bio_data_dir(bio) == WRITE) ? 'w' : 'r', bio->bi_opf, 332 (unsigned long long)bio->bi_iter.bi_sector, bio->bi_iter.bi_size); 333 break; 334 } 335 corrupt_bio_byte -= bio_iter_len(bio, iter); 336 } 337 } 338 339 static void clone_free(struct bio *clone) 340 { 341 struct folio_iter fi; 342 343 if (clone->bi_vcnt > 0) { /* bio_for_each_folio_all crashes with an empty bio */ 344 bio_for_each_folio_all(fi, clone) 345 folio_put(fi.folio); 346 } 347 348 bio_uninit(clone); 349 kfree(clone); 350 } 351 352 static void clone_endio(struct bio *clone) 353 { 354 struct bio *bio = clone->bi_private; 355 bio->bi_status = clone->bi_status; 356 clone_free(clone); 357 bio_endio(bio); 358 } 359 360 static struct bio *clone_bio(struct dm_target *ti, struct flakey_c *fc, struct bio *bio) 361 { 362 struct bio *clone; 363 unsigned size, remaining_size, nr_iovecs, order; 364 struct bvec_iter iter = bio->bi_iter; 365 366 if (unlikely(bio->bi_iter.bi_size > UIO_MAXIOV << PAGE_SHIFT)) 367 dm_accept_partial_bio(bio, UIO_MAXIOV << PAGE_SHIFT >> SECTOR_SHIFT); 368 369 size = bio->bi_iter.bi_size; 370 nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; 371 372 clone = bio_kmalloc(nr_iovecs, GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN); 373 if (!clone) 374 return NULL; 375 376 bio_init(clone, fc->dev->bdev, bio->bi_inline_vecs, nr_iovecs, bio->bi_opf); 377 378 clone->bi_iter.bi_sector = flakey_map_sector(ti, bio->bi_iter.bi_sector); 379 clone->bi_private = bio; 380 clone->bi_end_io = clone_endio; 381 382 remaining_size = size; 383 384 order = MAX_ORDER - 1; 385 while (remaining_size) { 386 struct page *pages; 387 unsigned size_to_add, to_copy; 388 unsigned char *virt; 389 unsigned remaining_order = __fls((remaining_size + PAGE_SIZE - 1) >> PAGE_SHIFT); 390 order = min(order, remaining_order); 391 392 retry_alloc_pages: 393 pages = alloc_pages(GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN | __GFP_COMP, order); 394 if (unlikely(!pages)) { 395 if (order) { 396 order--; 397 goto retry_alloc_pages; 398 } 399 clone_free(clone); 400 return NULL; 401 } 402 size_to_add = min((unsigned)PAGE_SIZE << order, remaining_size); 403 404 virt = page_to_virt(pages); 405 to_copy = size_to_add; 406 do { 407 struct bio_vec bvec = bvec_iter_bvec(bio->bi_io_vec, iter); 408 unsigned this_step = min(bvec.bv_len, to_copy); 409 void *map = bvec_kmap_local(&bvec); 410 memcpy(virt, map, this_step); 411 kunmap_local(map); 412 413 bvec_iter_advance(bio->bi_io_vec, &iter, this_step); 414 to_copy -= this_step; 415 virt += this_step; 416 } while (to_copy); 417 418 __bio_add_page(clone, pages, size_to_add, 0); 419 remaining_size -= size_to_add; 420 } 421 422 return clone; 423 } 424 425 static int flakey_map(struct dm_target *ti, struct bio *bio) 426 { 427 struct flakey_c *fc = ti->private; 428 unsigned int elapsed; 429 struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data)); 430 431 pb->bio_submitted = false; 432 433 if (op_is_zone_mgmt(bio_op(bio))) 434 goto map_bio; 435 436 /* Are we alive ? */ 437 elapsed = (jiffies - fc->start_time) / HZ; 438 if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) { 439 /* 440 * Flag this bio as submitted while down. 441 */ 442 pb->bio_submitted = true; 443 444 /* 445 * Error reads if neither corrupt_bio_byte or drop_writes or error_writes are set. 446 * Otherwise, flakey_end_io() will decide if the reads should be modified. 447 */ 448 if (bio_data_dir(bio) == READ) { 449 if (test_bit(ERROR_READS, &fc->flags)) 450 return DM_MAPIO_KILL; 451 goto map_bio; 452 } 453 454 /* 455 * Drop or error writes? 456 */ 457 if (test_bit(DROP_WRITES, &fc->flags)) { 458 bio_endio(bio); 459 return DM_MAPIO_SUBMITTED; 460 } else if (test_bit(ERROR_WRITES, &fc->flags)) { 461 bio_io_error(bio); 462 return DM_MAPIO_SUBMITTED; 463 } 464 465 /* 466 * Corrupt matching writes. 467 */ 468 if (fc->corrupt_bio_byte && fc->corrupt_bio_rw == WRITE) { 469 if (all_corrupt_bio_flags_match(bio, fc)) { 470 struct bio *clone = clone_bio(ti, fc, bio); 471 if (clone) { 472 corrupt_bio_data(clone, fc); 473 submit_bio(clone); 474 return DM_MAPIO_SUBMITTED; 475 } 476 } 477 goto map_bio; 478 } 479 } 480 481 map_bio: 482 flakey_map_bio(ti, bio); 483 484 return DM_MAPIO_REMAPPED; 485 } 486 487 static int flakey_end_io(struct dm_target *ti, struct bio *bio, 488 blk_status_t *error) 489 { 490 struct flakey_c *fc = ti->private; 491 struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data)); 492 493 if (op_is_zone_mgmt(bio_op(bio))) 494 return DM_ENDIO_DONE; 495 496 if (!*error && pb->bio_submitted && (bio_data_dir(bio) == READ)) { 497 if (fc->corrupt_bio_byte) { 498 if ((fc->corrupt_bio_rw == READ) && 499 all_corrupt_bio_flags_match(bio, fc)) { 500 /* 501 * Corrupt successful matching READs while in down state. 502 */ 503 corrupt_bio_data(bio, fc); 504 } 505 } 506 if (test_bit(ERROR_READS, &fc->flags)) { 507 /* 508 * Error read during the down_interval if drop_writes 509 * and error_writes were not configured. 510 */ 511 *error = BLK_STS_IOERR; 512 } 513 } 514 515 return DM_ENDIO_DONE; 516 } 517 518 static void flakey_status(struct dm_target *ti, status_type_t type, 519 unsigned int status_flags, char *result, unsigned int maxlen) 520 { 521 unsigned int sz = 0; 522 struct flakey_c *fc = ti->private; 523 unsigned int error_reads, drop_writes, error_writes; 524 525 switch (type) { 526 case STATUSTYPE_INFO: 527 result[0] = '\0'; 528 break; 529 530 case STATUSTYPE_TABLE: 531 DMEMIT("%s %llu %u %u", fc->dev->name, 532 (unsigned long long)fc->start, fc->up_interval, 533 fc->down_interval); 534 535 error_reads = test_bit(ERROR_READS, &fc->flags); 536 drop_writes = test_bit(DROP_WRITES, &fc->flags); 537 error_writes = test_bit(ERROR_WRITES, &fc->flags); 538 DMEMIT(" %u", error_reads + drop_writes + error_writes + (fc->corrupt_bio_byte > 0) * 5); 539 540 if (error_reads) 541 DMEMIT(" error_reads"); 542 if (drop_writes) 543 DMEMIT(" drop_writes"); 544 else if (error_writes) 545 DMEMIT(" error_writes"); 546 547 if (fc->corrupt_bio_byte) 548 DMEMIT(" corrupt_bio_byte %u %c %u %u", 549 fc->corrupt_bio_byte, 550 (fc->corrupt_bio_rw == WRITE) ? 'w' : 'r', 551 fc->corrupt_bio_value, fc->corrupt_bio_flags); 552 553 break; 554 555 case STATUSTYPE_IMA: 556 result[0] = '\0'; 557 break; 558 } 559 } 560 561 static int flakey_prepare_ioctl(struct dm_target *ti, struct block_device **bdev) 562 { 563 struct flakey_c *fc = ti->private; 564 565 *bdev = fc->dev->bdev; 566 567 /* 568 * Only pass ioctls through if the device sizes match exactly. 569 */ 570 if (fc->start || ti->len != bdev_nr_sectors((*bdev))) 571 return 1; 572 return 0; 573 } 574 575 #ifdef CONFIG_BLK_DEV_ZONED 576 static int flakey_report_zones(struct dm_target *ti, 577 struct dm_report_zones_args *args, unsigned int nr_zones) 578 { 579 struct flakey_c *fc = ti->private; 580 581 return dm_report_zones(fc->dev->bdev, fc->start, 582 flakey_map_sector(ti, args->next_sector), 583 args, nr_zones); 584 } 585 #else 586 #define flakey_report_zones NULL 587 #endif 588 589 static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data) 590 { 591 struct flakey_c *fc = ti->private; 592 593 return fn(ti, fc->dev, fc->start, ti->len, data); 594 } 595 596 static struct target_type flakey_target = { 597 .name = "flakey", 598 .version = {1, 5, 0}, 599 .features = DM_TARGET_ZONED_HM | DM_TARGET_PASSES_CRYPTO, 600 .report_zones = flakey_report_zones, 601 .module = THIS_MODULE, 602 .ctr = flakey_ctr, 603 .dtr = flakey_dtr, 604 .map = flakey_map, 605 .end_io = flakey_end_io, 606 .status = flakey_status, 607 .prepare_ioctl = flakey_prepare_ioctl, 608 .iterate_devices = flakey_iterate_devices, 609 }; 610 module_dm(flakey); 611 612 MODULE_DESCRIPTION(DM_NAME " flakey target"); 613 MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>"); 614 MODULE_LICENSE("GPL"); 615