]> git.baikalelectronics.ru Git - kernel.git/commitdiff
dm flakey: introduce "error_writes" feature
authorMike Snitzer <snitzer@redhat.com>
Tue, 13 Dec 2016 19:54:50 +0000 (14:54 -0500)
committerMike Snitzer <snitzer@redhat.com>
Tue, 13 Dec 2016 20:01:31 +0000 (15:01 -0500)
Recent dm-flakey fixes, to have reads error out during the "down"
interval, made it so that the previous read behaviour is no longer
available.

It is useful to have reads complete like normal but have writes error
out, so make it possible again with a new "error_writes" feature.

Signed-off-by: Mike Snitzer <snitzer@redhat.com>
drivers/md/dm-flakey.c

index 3643cba713518e9fdba01662c3516491bdb7d047..13305a182611080902cc944e45baf835818ebe38 100644 (file)
@@ -36,7 +36,8 @@ struct flakey_c {
 };
 
 enum feature_flag_bits {
-       DROP_WRITES
+       DROP_WRITES,
+       ERROR_WRITES
 };
 
 struct per_bio_data {
@@ -76,6 +77,25 @@ static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
                        if (test_and_set_bit(DROP_WRITES, &fc->flags)) {
                                ti->error = "Feature drop_writes duplicated";
                                return -EINVAL;
+                       } else if (test_bit(ERROR_WRITES, &fc->flags)) {
+                               ti->error = "Feature drop_writes conflicts with feature error_writes";
+                               return -EINVAL;
+                       }
+
+                       continue;
+               }
+
+               /*
+                * error_writes
+                */
+               if (!strcasecmp(arg_name, "error_writes")) {
+                       if (test_and_set_bit(ERROR_WRITES, &fc->flags)) {
+                               ti->error = "Feature error_writes duplicated";
+                               return -EINVAL;
+
+                       } else if (test_bit(DROP_WRITES, &fc->flags)) {
+                               ti->error = "Feature error_writes conflicts with feature drop_writes";
+                               return -EINVAL;
                        }
 
                        continue;
@@ -135,6 +155,10 @@ static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
        if (test_bit(DROP_WRITES, &fc->flags) && (fc->corrupt_bio_rw == WRITE)) {
                ti->error = "drop_writes is incompatible with corrupt_bio_byte with the WRITE flag set";
                return -EINVAL;
+
+       } else if (test_bit(ERROR_WRITES, &fc->flags) && (fc->corrupt_bio_rw == WRITE)) {
+               ti->error = "error_writes is incompatible with corrupt_bio_byte with the WRITE flag set";
+               return -EINVAL;
        }
 
        return 0;
@@ -291,22 +315,27 @@ static int flakey_map(struct dm_target *ti, struct bio *bio)
                pb->bio_submitted = true;
 
                /*
-                * Error reads if neither corrupt_bio_byte or drop_writes are set.
+                * Error reads if neither corrupt_bio_byte or drop_writes or error_writes are set.
                 * Otherwise, flakey_end_io() will decide if the reads should be modified.
                 */
                if (bio_data_dir(bio) == READ) {
-                       if (!fc->corrupt_bio_byte && !test_bit(DROP_WRITES, &fc->flags))
+                       if (!fc->corrupt_bio_byte && !test_bit(DROP_WRITES, &fc->flags) &&
+                           !test_bit(ERROR_WRITES, &fc->flags))
                                return -EIO;
                        goto map_bio;
                }
 
                /*
-                * Drop writes?
+                * Drop or error writes?
                 */
                if (test_bit(DROP_WRITES, &fc->flags)) {
                        bio_endio(bio);
                        return DM_MAPIO_SUBMITTED;
                }
+               else if (test_bit(ERROR_WRITES, &fc->flags)) {
+                       bio_io_error(bio);
+                       return DM_MAPIO_SUBMITTED;
+               }
 
                /*
                 * Corrupt matching writes.
@@ -342,10 +371,11 @@ static int flakey_end_io(struct dm_target *ti, struct bio *bio, int error)
                         */
                        corrupt_bio_data(bio, fc);
 
-               } else if (!test_bit(DROP_WRITES, &fc->flags)) {
+               } else if (!test_bit(DROP_WRITES, &fc->flags) &&
+                          !test_bit(ERROR_WRITES, &fc->flags)) {
                        /*
                         * Error read during the down_interval if drop_writes
-                        * wasn't configured.
+                        * and error_writes were not configured.
                         */
                        return -EIO;
                }
@@ -359,7 +389,7 @@ static void flakey_status(struct dm_target *ti, status_type_t type,
 {
        unsigned sz = 0;
        struct flakey_c *fc = ti->private;
-       unsigned drop_writes;
+       unsigned drop_writes, error_writes;
 
        switch (type) {
        case STATUSTYPE_INFO:
@@ -372,10 +402,13 @@ static void flakey_status(struct dm_target *ti, status_type_t type,
                       fc->down_interval);
 
                drop_writes = test_bit(DROP_WRITES, &fc->flags);
-               DMEMIT("%u ", drop_writes + (fc->corrupt_bio_byte > 0) * 5);
+               error_writes = test_bit(ERROR_WRITES, &fc->flags);
+               DMEMIT("%u ", drop_writes + error_writes + (fc->corrupt_bio_byte > 0) * 5);
 
                if (drop_writes)
                        DMEMIT("drop_writes ");
+               else if (error_writes)
+                       DMEMIT("error_writes ");
 
                if (fc->corrupt_bio_byte)
                        DMEMIT("corrupt_bio_byte %u %c %u %u ",
@@ -412,7 +445,7 @@ static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_
 
 static struct target_type flakey_target = {
        .name   = "flakey",
-       .version = {1, 3, 1},
+       .version = {1, 4, 0},
        .module = THIS_MODULE,
        .ctr    = flakey_ctr,
        .dtr    = flakey_dtr,