The random_read_corrupt and random_write_corrupt options corrupt random
byte in a bio with a given probability. The corruptions only happen in the
"down" interval.

Signed-off-by: Mikulas Patocka <mpato...@redhat.com>

---
 Documentation/admin-guide/device-mapper/dm-flakey.rst |   10 +
 drivers/md/dm-flakey.c                                |  118 ++++++++++++++----
 2 files changed, 108 insertions(+), 20 deletions(-)

Index: linux-2.6/drivers/md/dm-flakey.c
===================================================================
--- linux-2.6.orig/drivers/md/dm-flakey.c
+++ linux-2.6/drivers/md/dm-flakey.c
@@ -16,6 +16,8 @@
 
 #define DM_MSG_PREFIX "flakey"
 
+#define PROBABILITY_BASE       1000000000
+
 #define all_corrupt_bio_flags_match(bio, fc)   \
        (((bio)->bi_opf & (fc)->corrupt_bio_flags) == (fc)->corrupt_bio_flags)
 
@@ -34,6 +36,8 @@ struct flakey_c {
        unsigned int corrupt_bio_rw;
        unsigned int corrupt_bio_value;
        blk_opf_t corrupt_bio_flags;
+       unsigned int random_read_corrupt;
+       unsigned int random_write_corrupt;
 };
 
 enum feature_flag_bits {
@@ -54,10 +58,11 @@ static int parse_features(struct dm_arg_
        const char *arg_name;
 
        static const struct dm_arg _args[] = {
-               {0, 7, "Invalid number of feature args"},
+               {0, 11, "Invalid number of feature args"},
                {1, UINT_MAX, "Invalid corrupt bio byte"},
                {0, 255, "Invalid corrupt value to write into bio byte 
(0-255)"},
                {0, UINT_MAX, "Invalid corrupt bio flags mask"},
+               {0, PROBABILITY_BASE, "Invalid random corrupt argument"},
        };
 
        /* No feature arguments supplied. */
@@ -170,6 +175,32 @@ static int parse_features(struct dm_arg_
                        continue;
                }
 
+               if (!strcasecmp(arg_name, "random_read_corrupt")) {
+                       if (!argc) {
+                               ti->error = "Feature random_read_corrupt 
requires a parameter";
+                               return -EINVAL;
+                       }
+                       r = dm_read_arg(_args + 4, as, 
&fc->random_read_corrupt, &ti->error);
+                       if (r)
+                               return r;
+                       argc--;
+
+                       continue;
+               }
+
+               if (!strcasecmp(arg_name, "random_write_corrupt")) {
+                       if (!argc) {
+                               ti->error = "Feature random_write_corrupt 
requires a parameter";
+                               return -EINVAL;
+                       }
+                       r = dm_read_arg(_args + 4, as, 
&fc->random_write_corrupt, &ti->error);
+                       if (r)
+                               return r;
+                       argc--;
+
+                       continue;
+               }
+
                ti->error = "Unrecognised flakey feature requested";
                return -EINVAL;
        }
@@ -184,7 +215,8 @@ static int parse_features(struct dm_arg_
        }
 
        if (!fc->corrupt_bio_byte && !test_bit(ERROR_READS, &fc->flags) &&
-           !test_bit(DROP_WRITES, &fc->flags) && !test_bit(ERROR_WRITES, 
&fc->flags)) {
+           !test_bit(DROP_WRITES, &fc->flags) && !test_bit(ERROR_WRITES, 
&fc->flags) &&
+           !fc->random_read_corrupt && !fc->random_write_corrupt) {
                set_bit(ERROR_WRITES, &fc->flags);
                set_bit(ERROR_READS, &fc->flags);
        }
@@ -306,28 +338,23 @@ static void flakey_map_bio(struct dm_tar
        bio->bi_iter.bi_sector = flakey_map_sector(ti, bio->bi_iter.bi_sector);
 }
 
-static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc)
+static void corrupt_bio_common(struct bio *bio, unsigned int corrupt_bio_byte, 
unsigned char corrupt_bio_value)
 {
-       unsigned int corrupt_bio_byte = fc->corrupt_bio_byte - 1;
-
        struct bvec_iter iter;
        struct bio_vec bvec;
 
-       if (!bio_has_data(bio))
-               return;
-
        /*
         * Overwrite the Nth byte of the bio's data, on whichever page
         * it falls.
         */
        bio_for_each_segment(bvec, bio, iter) {
                if (bio_iter_len(bio, iter) > corrupt_bio_byte) {
-                       char *segment = bvec_kmap_local(&bvec);
-                       segment[corrupt_bio_byte] = fc->corrupt_bio_value;
+                       unsigned char *segment = bvec_kmap_local(&bvec);
+                       segment[corrupt_bio_byte] = corrupt_bio_value;
                        kunmap_local(segment);
                        DMDEBUG("Corrupting data bio=%p by writing %u to byte 
%u "
                                "(rw=%c bi_opf=%u bi_sector=%llu size=%u)\n",
-                               bio, fc->corrupt_bio_value, 
fc->corrupt_bio_byte,
+                               bio, corrupt_bio_value, corrupt_bio_byte,
                                (bio_data_dir(bio) == WRITE) ? 'w' : 'r', 
bio->bi_opf,
                                (unsigned long long)bio->bi_iter.bi_sector, 
bio->bi_iter.bi_size);
                        break;
@@ -336,6 +363,30 @@ static void corrupt_bio_data(struct bio
        }
 }
 
+static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc)
+{
+       unsigned int corrupt_bio_byte = fc->corrupt_bio_byte - 1;
+
+       if (!bio_has_data(bio))
+               return;
+
+       corrupt_bio_common(bio, corrupt_bio_byte, fc->corrupt_bio_value);
+}
+
+static void corrupt_bio_random(struct bio *bio)
+{
+       unsigned int corrupt_byte;
+       unsigned char corrupt_value;
+
+       if (!bio_has_data(bio))
+               return;
+
+       corrupt_byte = get_random_u32() % bio->bi_iter.bi_size;
+       corrupt_value = get_random_u8();
+
+       corrupt_bio_common(bio, corrupt_byte, corrupt_value);
+}
+
 static void clone_free(struct bio *clone)
 {
        struct folio_iter fi;
@@ -436,6 +487,7 @@ static int flakey_map(struct dm_target *
        /* Are we alive ? */
        elapsed = (jiffies - fc->start_time) / HZ;
        if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) 
{
+               bool corrupt_fixed, corrupt_random;
                /*
                 * Flag this bio as submitted while down.
                 */
@@ -465,16 +517,28 @@ static int flakey_map(struct dm_target *
                /*
                 * Corrupt matching writes.
                 */
+               corrupt_fixed = false;
+               corrupt_random = false;
                if (fc->corrupt_bio_byte && fc->corrupt_bio_rw == WRITE) {
-                       if (all_corrupt_bio_flags_match(bio, fc)) {
-                               struct bio *clone = clone_bio(ti, fc, bio);
-                               if (clone) {
+                       if (all_corrupt_bio_flags_match(bio, fc))
+                               corrupt_fixed = true;
+               }
+               if (fc->random_write_corrupt) {
+                       u64 rnd = get_random_u64();
+                       u32 rem = do_div(rnd, PROBABILITY_BASE);
+                       if (rem < fc->random_write_corrupt)
+                               corrupt_random = true;
+               }
+               if (corrupt_fixed || corrupt_random) {
+                       struct bio *clone = clone_bio(ti, fc, bio);
+                       if (clone) {
+                               if (corrupt_fixed)
                                        corrupt_bio_data(clone, fc);
-                                       submit_bio(clone);
-                                       return DM_MAPIO_SUBMITTED;
-                               }
-                       }
-                       goto map_bio;
+                               if (corrupt_random)
+                                       corrupt_bio_random(clone);
+                               submit_bio(clone);
+                               return DM_MAPIO_SUBMITTED;
+                       }
                }
        }
 
@@ -503,6 +567,12 @@ static int flakey_end_io(struct dm_targe
                                corrupt_bio_data(bio, fc);
                        }
                }
+               if (fc->random_read_corrupt) {
+                       u64 rnd = get_random_u64();
+                       u32 rem = do_div(rnd, PROBABILITY_BASE);
+                       if (rem < fc->random_read_corrupt)
+                               corrupt_bio_random(bio);
+               }
                if (test_bit(ERROR_READS, &fc->flags)) {
                        /*
                         * Error read during the down_interval if drop_writes
@@ -535,7 +605,10 @@ static void flakey_status(struct dm_targ
                error_reads = test_bit(ERROR_READS, &fc->flags);
                drop_writes = test_bit(DROP_WRITES, &fc->flags);
                error_writes = test_bit(ERROR_WRITES, &fc->flags);
-               DMEMIT(" %u", error_reads + drop_writes + error_writes + 
(fc->corrupt_bio_byte > 0) * 5);
+               DMEMIT(" %u", error_reads + drop_writes + error_writes +
+                       (fc->corrupt_bio_byte > 0) * 5 +
+                       (fc->random_read_corrupt > 0) * 2 +
+                       (fc->random_write_corrupt > 0) * 2);
 
                if (error_reads)
                        DMEMIT(" error_reads");
@@ -550,6 +623,11 @@ static void flakey_status(struct dm_targ
                               (fc->corrupt_bio_rw == WRITE) ? 'w' : 'r',
                               fc->corrupt_bio_value, fc->corrupt_bio_flags);
 
+               if (fc->random_read_corrupt > 0)
+                       DMEMIT(" %u", fc->random_read_corrupt);
+               if (fc->random_write_corrupt > 0)
+                       DMEMIT(" %u", fc->random_write_corrupt);
+
                break;
 
        case STATUSTYPE_IMA:
Index: linux-2.6/Documentation/admin-guide/device-mapper/dm-flakey.rst
===================================================================
--- linux-2.6.orig/Documentation/admin-guide/device-mapper/dm-flakey.rst
+++ linux-2.6/Documentation/admin-guide/device-mapper/dm-flakey.rst
@@ -67,6 +67,16 @@ Optional feature parameters:
        Perform the replacement only if bio->bi_opf has all the
        selected flags set.
 
+  random_read_corrupt <probability>
+       During <down interval>, replace random byte in a read bio
+       with a random value. probability is an integer between
+       0 and 1000000000 meaning 0% to 100% probability of corruption.
+
+  random_write_corrupt <probability>
+       During <down interval>, replace random byte in a write bio
+       with a random value. probability is an integer between
+       0 and 1000000000 meaning 0% to 100% probability of corruption.
+
 Examples:
 
 Replaces the 32nd byte of READ bios with the value 1::

--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel

Reply via email to