1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2003 Sistina Software (UK) Limited.
4 * Copyright (C) 2004, 2010-2011 Red Hat, Inc. All rights reserved.
6 * This file is released under the GPL.
9 #include <linux/device-mapper.h>
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>
17 #define DM_MSG_PREFIX "flakey"
19 #define PROBABILITY_BASE 1000000000
21 #define all_corrupt_bio_flags_match(bio, fc) \
22 (((bio)->bi_opf & (fc)->corrupt_bio_flags) == (fc)->corrupt_bio_flags)
25 * Flakey: Used for testing only, simulates intermittent,
26 * catastrophic device failure.
30 unsigned long start_time
;
32 unsigned int up_interval
;
33 unsigned int down_interval
;
35 unsigned int corrupt_bio_byte
;
36 unsigned int corrupt_bio_rw
;
37 unsigned int corrupt_bio_value
;
38 blk_opf_t corrupt_bio_flags
;
39 unsigned int random_read_corrupt
;
40 unsigned int random_write_corrupt
;
43 enum feature_flag_bits
{
53 static int parse_features(struct dm_arg_set
*as
, struct flakey_c
*fc
,
60 static const struct dm_arg _args
[] = {
61 {0, 11, "Invalid number of feature args"},
62 {1, UINT_MAX
, "Invalid corrupt bio byte"},
63 {0, 255, "Invalid corrupt value to write into bio byte (0-255)"},
64 {0, UINT_MAX
, "Invalid corrupt bio flags mask"},
65 {0, PROBABILITY_BASE
, "Invalid random corrupt argument"},
68 /* No feature arguments supplied. */
72 r
= dm_read_arg_group(_args
, as
, &argc
, &ti
->error
);
77 arg_name
= dm_shift_arg(as
);
81 ti
->error
= "Insufficient feature arguments";
88 if (!strcasecmp(arg_name
, "error_reads")) {
89 if (test_and_set_bit(ERROR_READS
, &fc
->flags
)) {
90 ti
->error
= "Feature error_reads duplicated";
99 if (!strcasecmp(arg_name
, "drop_writes")) {
100 if (test_and_set_bit(DROP_WRITES
, &fc
->flags
)) {
101 ti
->error
= "Feature drop_writes duplicated";
103 } else if (test_bit(ERROR_WRITES
, &fc
->flags
)) {
104 ti
->error
= "Feature drop_writes conflicts with feature error_writes";
114 if (!strcasecmp(arg_name
, "error_writes")) {
115 if (test_and_set_bit(ERROR_WRITES
, &fc
->flags
)) {
116 ti
->error
= "Feature error_writes duplicated";
119 } else if (test_bit(DROP_WRITES
, &fc
->flags
)) {
120 ti
->error
= "Feature error_writes conflicts with feature drop_writes";
128 * corrupt_bio_byte <Nth_byte> <direction> <value> <bio_flags>
130 if (!strcasecmp(arg_name
, "corrupt_bio_byte")) {
132 ti
->error
= "Feature corrupt_bio_byte requires parameters";
136 r
= dm_read_arg(_args
+ 1, as
, &fc
->corrupt_bio_byte
, &ti
->error
);
144 arg_name
= dm_shift_arg(as
);
145 if (arg_name
&& !strcasecmp(arg_name
, "w"))
146 fc
->corrupt_bio_rw
= WRITE
;
147 else if (arg_name
&& !strcasecmp(arg_name
, "r"))
148 fc
->corrupt_bio_rw
= READ
;
150 ti
->error
= "Invalid corrupt bio direction (r or w)";
156 * Value of byte (0-255) to write in place of correct one.
158 r
= dm_read_arg(_args
+ 2, as
, &fc
->corrupt_bio_value
, &ti
->error
);
164 * Only corrupt bios with these flags set.
166 BUILD_BUG_ON(sizeof(fc
->corrupt_bio_flags
) !=
167 sizeof(unsigned int));
168 r
= dm_read_arg(_args
+ 3, as
,
169 (__force
unsigned int *)&fc
->corrupt_bio_flags
,
178 if (!strcasecmp(arg_name
, "random_read_corrupt")) {
180 ti
->error
= "Feature random_read_corrupt requires a parameter";
183 r
= dm_read_arg(_args
+ 4, as
, &fc
->random_read_corrupt
, &ti
->error
);
191 if (!strcasecmp(arg_name
, "random_write_corrupt")) {
193 ti
->error
= "Feature random_write_corrupt requires a parameter";
196 r
= dm_read_arg(_args
+ 4, as
, &fc
->random_write_corrupt
, &ti
->error
);
204 ti
->error
= "Unrecognised flakey feature requested";
208 if (test_bit(DROP_WRITES
, &fc
->flags
) && (fc
->corrupt_bio_rw
== WRITE
)) {
209 ti
->error
= "drop_writes is incompatible with corrupt_bio_byte with the WRITE flag set";
212 } else if (test_bit(ERROR_WRITES
, &fc
->flags
) && (fc
->corrupt_bio_rw
== WRITE
)) {
213 ti
->error
= "error_writes is incompatible with corrupt_bio_byte with the WRITE flag set";
217 if (!fc
->corrupt_bio_byte
&& !test_bit(ERROR_READS
, &fc
->flags
) &&
218 !test_bit(DROP_WRITES
, &fc
->flags
) && !test_bit(ERROR_WRITES
, &fc
->flags
) &&
219 !fc
->random_read_corrupt
&& !fc
->random_write_corrupt
) {
220 set_bit(ERROR_WRITES
, &fc
->flags
);
221 set_bit(ERROR_READS
, &fc
->flags
);
228 * Construct a flakey mapping:
229 * <dev_path> <offset> <up interval> <down interval> [<#feature args> [<arg>]*]
233 * [corrupt_bio_byte <Nth_byte> <direction> <value> <bio_flags>]
235 * Nth_byte starts from 1 for the first byte.
236 * Direction is r for READ or w for WRITE.
237 * bio_flags is ignored if 0.
239 static int flakey_ctr(struct dm_target
*ti
, unsigned int argc
, char **argv
)
241 static const struct dm_arg _args
[] = {
242 {0, UINT_MAX
, "Invalid up interval"},
243 {0, UINT_MAX
, "Invalid down interval"},
248 unsigned long long tmpll
;
249 struct dm_arg_set as
;
257 ti
->error
= "Invalid argument count";
261 fc
= kzalloc(sizeof(*fc
), GFP_KERNEL
);
263 ti
->error
= "Cannot allocate context";
266 fc
->start_time
= jiffies
;
268 devname
= dm_shift_arg(&as
);
271 if (sscanf(dm_shift_arg(&as
), "%llu%c", &tmpll
, &dummy
) != 1 || tmpll
!= (sector_t
)tmpll
) {
272 ti
->error
= "Invalid device sector";
277 r
= dm_read_arg(_args
, &as
, &fc
->up_interval
, &ti
->error
);
281 r
= dm_read_arg(_args
, &as
, &fc
->down_interval
, &ti
->error
);
285 if (!(fc
->up_interval
+ fc
->down_interval
)) {
286 ti
->error
= "Total (up + down) interval is zero";
291 if (fc
->up_interval
+ fc
->down_interval
< fc
->up_interval
) {
292 ti
->error
= "Interval overflow";
297 r
= parse_features(&as
, fc
, ti
);
301 r
= dm_get_device(ti
, devname
, dm_table_get_mode(ti
->table
), &fc
->dev
);
303 ti
->error
= "Device lookup failed";
307 ti
->num_flush_bios
= 1;
308 ti
->num_discard_bios
= 1;
309 ti
->per_io_data_size
= sizeof(struct per_bio_data
);
318 static void flakey_dtr(struct dm_target
*ti
)
320 struct flakey_c
*fc
= ti
->private;
322 dm_put_device(ti
, fc
->dev
);
326 static sector_t
flakey_map_sector(struct dm_target
*ti
, sector_t bi_sector
)
328 struct flakey_c
*fc
= ti
->private;
330 return fc
->start
+ dm_target_offset(ti
, bi_sector
);
333 static void flakey_map_bio(struct dm_target
*ti
, struct bio
*bio
)
335 struct flakey_c
*fc
= ti
->private;
337 bio_set_dev(bio
, fc
->dev
->bdev
);
338 bio
->bi_iter
.bi_sector
= flakey_map_sector(ti
, bio
->bi_iter
.bi_sector
);
341 static void corrupt_bio_common(struct bio
*bio
, unsigned int corrupt_bio_byte
,
342 unsigned char corrupt_bio_value
)
344 struct bvec_iter iter
;
348 * Overwrite the Nth byte of the bio's data, on whichever page
351 bio_for_each_segment(bvec
, bio
, iter
) {
352 if (bio_iter_len(bio
, iter
) > corrupt_bio_byte
) {
353 unsigned char *segment
= bvec_kmap_local(&bvec
);
354 segment
[corrupt_bio_byte
] = corrupt_bio_value
;
355 kunmap_local(segment
);
356 DMDEBUG("Corrupting data bio=%p by writing %u to byte %u "
357 "(rw=%c bi_opf=%u bi_sector=%llu size=%u)\n",
358 bio
, corrupt_bio_value
, corrupt_bio_byte
,
359 (bio_data_dir(bio
) == WRITE
) ? 'w' : 'r', bio
->bi_opf
,
360 (unsigned long long)bio
->bi_iter
.bi_sector
,
361 bio
->bi_iter
.bi_size
);
364 corrupt_bio_byte
-= bio_iter_len(bio
, iter
);
368 static void corrupt_bio_data(struct bio
*bio
, struct flakey_c
*fc
)
370 unsigned int corrupt_bio_byte
= fc
->corrupt_bio_byte
- 1;
372 if (!bio_has_data(bio
))
375 corrupt_bio_common(bio
, corrupt_bio_byte
, fc
->corrupt_bio_value
);
378 static void corrupt_bio_random(struct bio
*bio
)
380 unsigned int corrupt_byte
;
381 unsigned char corrupt_value
;
383 if (!bio_has_data(bio
))
386 corrupt_byte
= get_random_u32() % bio
->bi_iter
.bi_size
;
387 corrupt_value
= get_random_u8();
389 corrupt_bio_common(bio
, corrupt_byte
, corrupt_value
);
392 static void clone_free(struct bio
*clone
)
394 struct folio_iter fi
;
396 if (clone
->bi_vcnt
> 0) { /* bio_for_each_folio_all crashes with an empty bio */
397 bio_for_each_folio_all(fi
, clone
)
405 static void clone_endio(struct bio
*clone
)
407 struct bio
*bio
= clone
->bi_private
;
408 bio
->bi_status
= clone
->bi_status
;
413 static struct bio
*clone_bio(struct dm_target
*ti
, struct flakey_c
*fc
, struct bio
*bio
)
416 unsigned size
, remaining_size
, nr_iovecs
, order
;
417 struct bvec_iter iter
= bio
->bi_iter
;
419 if (unlikely(bio
->bi_iter
.bi_size
> UIO_MAXIOV
<< PAGE_SHIFT
))
420 dm_accept_partial_bio(bio
, UIO_MAXIOV
<< PAGE_SHIFT
>> SECTOR_SHIFT
);
422 size
= bio
->bi_iter
.bi_size
;
423 nr_iovecs
= (size
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
425 clone
= bio_kmalloc(nr_iovecs
, GFP_NOIO
| __GFP_NORETRY
| __GFP_NOWARN
);
429 bio_init(clone
, fc
->dev
->bdev
, bio
->bi_inline_vecs
, nr_iovecs
, bio
->bi_opf
);
431 clone
->bi_iter
.bi_sector
= flakey_map_sector(ti
, bio
->bi_iter
.bi_sector
);
432 clone
->bi_private
= bio
;
433 clone
->bi_end_io
= clone_endio
;
435 remaining_size
= size
;
437 order
= MAX_PAGE_ORDER
;
438 while (remaining_size
) {
440 unsigned size_to_add
, to_copy
;
442 unsigned remaining_order
= __fls((remaining_size
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
);
443 order
= min(order
, remaining_order
);
446 pages
= alloc_pages(GFP_NOIO
| __GFP_NORETRY
| __GFP_NOWARN
| __GFP_COMP
, order
);
447 if (unlikely(!pages
)) {
450 goto retry_alloc_pages
;
455 size_to_add
= min((unsigned)PAGE_SIZE
<< order
, remaining_size
);
457 virt
= page_to_virt(pages
);
458 to_copy
= size_to_add
;
460 struct bio_vec bvec
= bvec_iter_bvec(bio
->bi_io_vec
, iter
);
461 unsigned this_step
= min(bvec
.bv_len
, to_copy
);
462 void *map
= bvec_kmap_local(&bvec
);
463 memcpy(virt
, map
, this_step
);
466 bvec_iter_advance(bio
->bi_io_vec
, &iter
, this_step
);
467 to_copy
-= this_step
;
471 __bio_add_page(clone
, pages
, size_to_add
, 0);
472 remaining_size
-= size_to_add
;
478 static int flakey_map(struct dm_target
*ti
, struct bio
*bio
)
480 struct flakey_c
*fc
= ti
->private;
481 unsigned int elapsed
;
482 struct per_bio_data
*pb
= dm_per_bio_data(bio
, sizeof(struct per_bio_data
));
484 pb
->bio_submitted
= false;
486 if (op_is_zone_mgmt(bio_op(bio
)))
490 elapsed
= (jiffies
- fc
->start_time
) / HZ
;
491 if (elapsed
% (fc
->up_interval
+ fc
->down_interval
) >= fc
->up_interval
) {
492 bool corrupt_fixed
, corrupt_random
;
494 * Flag this bio as submitted while down.
496 pb
->bio_submitted
= true;
499 * Error reads if neither corrupt_bio_byte or drop_writes or error_writes are set.
500 * Otherwise, flakey_end_io() will decide if the reads should be modified.
502 if (bio_data_dir(bio
) == READ
) {
503 if (test_bit(ERROR_READS
, &fc
->flags
))
504 return DM_MAPIO_KILL
;
509 * Drop or error writes?
511 if (test_bit(DROP_WRITES
, &fc
->flags
)) {
513 return DM_MAPIO_SUBMITTED
;
514 } else if (test_bit(ERROR_WRITES
, &fc
->flags
)) {
516 return DM_MAPIO_SUBMITTED
;
520 * Corrupt matching writes.
522 corrupt_fixed
= false;
523 corrupt_random
= false;
524 if (fc
->corrupt_bio_byte
&& fc
->corrupt_bio_rw
== WRITE
) {
525 if (all_corrupt_bio_flags_match(bio
, fc
))
526 corrupt_fixed
= true;
528 if (fc
->random_write_corrupt
) {
529 u64 rnd
= get_random_u64();
530 u32 rem
= do_div(rnd
, PROBABILITY_BASE
);
531 if (rem
< fc
->random_write_corrupt
)
532 corrupt_random
= true;
534 if (corrupt_fixed
|| corrupt_random
) {
535 struct bio
*clone
= clone_bio(ti
, fc
, bio
);
538 corrupt_bio_data(clone
, fc
);
540 corrupt_bio_random(clone
);
542 return DM_MAPIO_SUBMITTED
;
548 flakey_map_bio(ti
, bio
);
550 return DM_MAPIO_REMAPPED
;
553 static int flakey_end_io(struct dm_target
*ti
, struct bio
*bio
,
556 struct flakey_c
*fc
= ti
->private;
557 struct per_bio_data
*pb
= dm_per_bio_data(bio
, sizeof(struct per_bio_data
));
559 if (op_is_zone_mgmt(bio_op(bio
)))
560 return DM_ENDIO_DONE
;
562 if (!*error
&& pb
->bio_submitted
&& (bio_data_dir(bio
) == READ
)) {
563 if (fc
->corrupt_bio_byte
) {
564 if ((fc
->corrupt_bio_rw
== READ
) &&
565 all_corrupt_bio_flags_match(bio
, fc
)) {
567 * Corrupt successful matching READs while in down state.
569 corrupt_bio_data(bio
, fc
);
572 if (fc
->random_read_corrupt
) {
573 u64 rnd
= get_random_u64();
574 u32 rem
= do_div(rnd
, PROBABILITY_BASE
);
575 if (rem
< fc
->random_read_corrupt
)
576 corrupt_bio_random(bio
);
578 if (test_bit(ERROR_READS
, &fc
->flags
)) {
580 * Error read during the down_interval if drop_writes
581 * and error_writes were not configured.
583 *error
= BLK_STS_IOERR
;
587 return DM_ENDIO_DONE
;
590 static void flakey_status(struct dm_target
*ti
, status_type_t type
,
591 unsigned int status_flags
, char *result
, unsigned int maxlen
)
594 struct flakey_c
*fc
= ti
->private;
595 unsigned int error_reads
, drop_writes
, error_writes
;
598 case STATUSTYPE_INFO
:
602 case STATUSTYPE_TABLE
:
603 DMEMIT("%s %llu %u %u", fc
->dev
->name
,
604 (unsigned long long)fc
->start
, fc
->up_interval
,
607 error_reads
= test_bit(ERROR_READS
, &fc
->flags
);
608 drop_writes
= test_bit(DROP_WRITES
, &fc
->flags
);
609 error_writes
= test_bit(ERROR_WRITES
, &fc
->flags
);
610 DMEMIT(" %u", error_reads
+ drop_writes
+ error_writes
+
611 (fc
->corrupt_bio_byte
> 0) * 5 +
612 (fc
->random_read_corrupt
> 0) * 2 +
613 (fc
->random_write_corrupt
> 0) * 2);
616 DMEMIT(" error_reads");
618 DMEMIT(" drop_writes");
619 else if (error_writes
)
620 DMEMIT(" error_writes");
622 if (fc
->corrupt_bio_byte
)
623 DMEMIT(" corrupt_bio_byte %u %c %u %u",
624 fc
->corrupt_bio_byte
,
625 (fc
->corrupt_bio_rw
== WRITE
) ? 'w' : 'r',
626 fc
->corrupt_bio_value
, fc
->corrupt_bio_flags
);
628 if (fc
->random_read_corrupt
> 0)
629 DMEMIT(" random_read_corrupt %u", fc
->random_read_corrupt
);
630 if (fc
->random_write_corrupt
> 0)
631 DMEMIT(" random_write_corrupt %u", fc
->random_write_corrupt
);
641 static int flakey_prepare_ioctl(struct dm_target
*ti
, struct block_device
**bdev
)
643 struct flakey_c
*fc
= ti
->private;
645 *bdev
= fc
->dev
->bdev
;
648 * Only pass ioctls through if the device sizes match exactly.
650 if (fc
->start
|| ti
->len
!= bdev_nr_sectors((*bdev
)))
655 #ifdef CONFIG_BLK_DEV_ZONED
656 static int flakey_report_zones(struct dm_target
*ti
,
657 struct dm_report_zones_args
*args
, unsigned int nr_zones
)
659 struct flakey_c
*fc
= ti
->private;
661 return dm_report_zones(fc
->dev
->bdev
, fc
->start
,
662 flakey_map_sector(ti
, args
->next_sector
),
666 #define flakey_report_zones NULL
669 static int flakey_iterate_devices(struct dm_target
*ti
, iterate_devices_callout_fn fn
, void *data
)
671 struct flakey_c
*fc
= ti
->private;
673 return fn(ti
, fc
->dev
, fc
->start
, ti
->len
, data
);
676 static struct target_type flakey_target
= {
678 .version
= {1, 5, 0},
679 .features
= DM_TARGET_ZONED_HM
| DM_TARGET_PASSES_CRYPTO
,
680 .report_zones
= flakey_report_zones
,
681 .module
= THIS_MODULE
,
685 .end_io
= flakey_end_io
,
686 .status
= flakey_status
,
687 .prepare_ioctl
= flakey_prepare_ioctl
,
688 .iterate_devices
= flakey_iterate_devices
,
692 MODULE_DESCRIPTION(DM_NAME
" flakey target");
693 MODULE_AUTHOR("Joe Thornber <dm-devel@lists.linux.dev>");
694 MODULE_LICENSE("GPL");