dm flakey: Properly corrupt multi-page bios.
authorSweet Tea <sweettea@redhat.com>
Tue, 13 Nov 2018 13:04:24 +0000 (08:04 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 Dec 2019 14:37:32 +0000 (15:37 +0100)
[ Upstream commit a00f5276e26636cbf72f24f79831026d2e2868e7 ]

The flakey target is documented to be able to corrupt the Nth byte in
a bio, but does not corrupt byte indices after the first biovec in the
bio. Change the corrupting function to actually corrupt the Nth byte
no matter in which biovec that index falls.

A test device generating two-page bios, atop a flakey device configured
to corrupt a byte index on the second page, verified both the failure
to corrupt before this patch and the expected corruption after this
change.

Signed-off-by: John Dorminy <jdorminy@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/md/dm-flakey.c

index 0c1ef63c3461b106173591fe6b42f92728b8ebf4..b1b68e01b889cd42823252832a572d234965a8ad 100644 (file)
@@ -282,20 +282,31 @@ static void flakey_map_bio(struct dm_target *ti, struct bio *bio)
 
 static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc)
 {
-       unsigned bio_bytes = bio_cur_bytes(bio);
-       char *data = bio_data(bio);
+       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 data returned.
+        * Overwrite the Nth byte of the bio's data, on whichever page
+        * it falls.
         */
-       if (data && bio_bytes >= fc->corrupt_bio_byte) {
-               data[fc->corrupt_bio_byte - 1] = fc->corrupt_bio_value;
-
-               DMDEBUG("Corrupting data bio=%p by writing %u to byte %u "
-                       "(rw=%c bi_opf=%u bi_sector=%llu cur_bytes=%u)\n",
-                       bio, fc->corrupt_bio_value, fc->corrupt_bio_byte,
-                       (bio_data_dir(bio) == WRITE) ? 'w' : 'r', bio->bi_opf,
-                       (unsigned long long)bio->bi_iter.bi_sector, bio_bytes);
+       bio_for_each_segment(bvec, bio, iter) {
+               if (bio_iter_len(bio, iter) > corrupt_bio_byte) {
+                       char *segment = (page_address(bio_iter_page(bio, iter))
+                                        + bio_iter_offset(bio, iter));
+                       segment[corrupt_bio_byte] = fc->corrupt_bio_value;
+                       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_data_dir(bio) == WRITE) ? 'w' : 'r', bio->bi_opf,
+                               (unsigned long long)bio->bi_iter.bi_sector, bio->bi_iter.bi_size);
+                       break;
+               }
+               corrupt_bio_byte -= bio_iter_len(bio, iter);
        }
 }