Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

dm-flakey: make corrupting read bios work

dm-flakey corrupts the read bios in the endio function. However, the
corrupt_bio_* functions checked bio_has_data() to see if there was data
to corrupt. Since this was the endio function, there was no data left to
complete, so bio_has_data() was always false. Fix this by saving a copy
of the bio's bi_iter in flakey_map(), and using this to initialize the
iter for corrupting the read bios. This patch also skips cloning the bio
for write bios with no data.

Reported-by: Kent Overstreet <kent.overstreet@linux.dev>
Fixes: a3998799fb4df ("dm flakey: add corrupt_bio_byte feature")
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>

authored by

Benjamin Marzinski and committed by
Mikulas Patocka
13e79076 4319f0aa

+28 -26
+28 -26
drivers/md/dm-flakey.c
··· 47 47 }; 48 48 49 49 struct per_bio_data { 50 - bool bio_submitted; 50 + bool bio_can_corrupt; 51 + struct bvec_iter saved_iter; 51 52 }; 52 53 53 54 static int parse_features(struct dm_arg_set *as, struct flakey_c *fc, ··· 355 354 } 356 355 357 356 static void corrupt_bio_common(struct bio *bio, unsigned int corrupt_bio_byte, 358 - unsigned char corrupt_bio_value) 357 + unsigned char corrupt_bio_value, 358 + struct bvec_iter start) 359 359 { 360 360 struct bvec_iter iter; 361 361 struct bio_vec bvec; ··· 365 363 * Overwrite the Nth byte of the bio's data, on whichever page 366 364 * it falls. 367 365 */ 368 - bio_for_each_segment(bvec, bio, iter) { 366 + __bio_for_each_segment(bvec, bio, iter, start) { 369 367 if (bio_iter_len(bio, iter) > corrupt_bio_byte) { 370 368 unsigned char *segment = bvec_kmap_local(&bvec); 371 369 segment[corrupt_bio_byte] = corrupt_bio_value; ··· 374 372 "(rw=%c bi_opf=%u bi_sector=%llu size=%u)\n", 375 373 bio, corrupt_bio_value, corrupt_bio_byte, 376 374 (bio_data_dir(bio) == WRITE) ? 'w' : 'r', bio->bi_opf, 377 - (unsigned long long)bio->bi_iter.bi_sector, 378 - bio->bi_iter.bi_size); 375 + (unsigned long long)start.bi_sector, 376 + start.bi_size); 379 377 break; 380 378 } 381 379 corrupt_bio_byte -= bio_iter_len(bio, iter); 382 380 } 383 381 } 384 382 385 - static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc) 383 + static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc, 384 + struct bvec_iter start) 386 385 { 387 386 unsigned int corrupt_bio_byte = fc->corrupt_bio_byte - 1; 388 387 389 - if (!bio_has_data(bio)) 390 - return; 391 - 392 - corrupt_bio_common(bio, corrupt_bio_byte, fc->corrupt_bio_value); 388 + corrupt_bio_common(bio, corrupt_bio_byte, fc->corrupt_bio_value, start); 393 389 } 394 390 395 - static void corrupt_bio_random(struct bio *bio) 391 + static void corrupt_bio_random(struct bio *bio, struct bvec_iter start) 396 392 { 397 393 unsigned int corrupt_byte; 398 394 unsigned char corrupt_value; 399 395 400 - if (!bio_has_data(bio)) 401 - return; 402 - 403 - corrupt_byte = get_random_u32() % bio->bi_iter.bi_size; 396 + corrupt_byte = get_random_u32() % start.bi_size; 404 397 corrupt_value = get_random_u8(); 405 398 406 - corrupt_bio_common(bio, corrupt_byte, corrupt_value); 399 + corrupt_bio_common(bio, corrupt_byte, corrupt_value, start); 407 400 } 408 401 409 402 static void clone_free(struct bio *clone) ··· 493 496 unsigned int elapsed; 494 497 struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data)); 495 498 496 - pb->bio_submitted = false; 499 + pb->bio_can_corrupt = false; 497 500 498 501 if (op_is_zone_mgmt(bio_op(bio))) 499 502 goto map_bio; ··· 502 505 elapsed = (jiffies - fc->start_time) / HZ; 503 506 if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) { 504 507 bool corrupt_fixed, corrupt_random; 505 - /* 506 - * Flag this bio as submitted while down. 507 - */ 508 - pb->bio_submitted = true; 508 + 509 + if (bio_has_data(bio)) { 510 + pb->bio_can_corrupt = true; 511 + pb->saved_iter = bio->bi_iter; 512 + } 509 513 510 514 /* 511 515 * If ERROR_READS isn't set flakey_end_io() will decide if the ··· 529 531 return DM_MAPIO_SUBMITTED; 530 532 } 531 533 534 + if (!pb->bio_can_corrupt) 535 + goto map_bio; 532 536 /* 533 537 * Corrupt matching writes. 534 538 */ ··· 550 550 struct bio *clone = clone_bio(ti, fc, bio); 551 551 if (clone) { 552 552 if (corrupt_fixed) 553 - corrupt_bio_data(clone, fc); 553 + corrupt_bio_data(clone, fc, 554 + clone->bi_iter); 554 555 if (corrupt_random) 555 - corrupt_bio_random(clone); 556 + corrupt_bio_random(clone, 557 + clone->bi_iter); 556 558 submit_bio(clone); 557 559 return DM_MAPIO_SUBMITTED; 558 560 } ··· 576 574 if (op_is_zone_mgmt(bio_op(bio))) 577 575 return DM_ENDIO_DONE; 578 576 579 - if (!*error && pb->bio_submitted && (bio_data_dir(bio) == READ)) { 577 + if (!*error && pb->bio_can_corrupt && (bio_data_dir(bio) == READ)) { 580 578 if (fc->corrupt_bio_byte) { 581 579 if ((fc->corrupt_bio_rw == READ) && 582 580 all_corrupt_bio_flags_match(bio, fc)) { 583 581 /* 584 582 * Corrupt successful matching READs while in down state. 585 583 */ 586 - corrupt_bio_data(bio, fc); 584 + corrupt_bio_data(bio, fc, pb->saved_iter); 587 585 } 588 586 } 589 587 if (fc->random_read_corrupt) { 590 588 u64 rnd = get_random_u64(); 591 589 u32 rem = do_div(rnd, PROBABILITY_BASE); 592 590 if (rem < fc->random_read_corrupt) 593 - corrupt_bio_random(bio); 591 + corrupt_bio_random(bio, pb->saved_iter); 594 592 } 595 593 } 596 594