diff options
| -rw-r--r-- | Documentation/device-mapper/dm-flakey.txt | 29 | ||||
| -rw-r--r-- | drivers/md/dm-flakey.c | 63 |
2 files changed, 78 insertions, 14 deletions
diff --git a/Documentation/device-mapper/dm-flakey.txt b/Documentation/device-mapper/dm-flakey.txt index c8efdfd19a65..1b66c868ee7e 100644 --- a/Documentation/device-mapper/dm-flakey.txt +++ b/Documentation/device-mapper/dm-flakey.txt | |||
| @@ -1,17 +1,34 @@ | |||
| 1 | dm-flakey | 1 | dm-flakey |
| 2 | ========= | 2 | ========= |
| 3 | 3 | ||
| 4 | This target is the same as the linear target except that it returns I/O | 4 | This target is the same as the linear target except that it exhibits |
| 5 | errors periodically. It's been found useful in simulating failing | 5 | unreliable behaviour periodically. It's been found useful in simulating |
| 6 | devices for testing purposes. | 6 | failing devices for testing purposes. |
| 7 | 7 | ||
| 8 | Starting from the time the table is loaded, the device is available for | 8 | Starting from the time the table is loaded, the device is available for |
| 9 | <up interval> seconds, then returns errors for <down interval> seconds, | 9 | <up interval> seconds, then exhibits unreliable behaviour for <down |
| 10 | and then this cycle repeats. | 10 | interval> seconds, and then this cycle repeats. |
| 11 | 11 | ||
| 12 | Parameters: <dev path> <offset> <up interval> <down interval> | 12 | Also, consider using this in combination with the dm-delay target too, |
| 13 | which can delay reads and writes and/or send them to different | ||
| 14 | underlying devices. | ||
| 15 | |||
| 16 | Table parameters | ||
| 17 | ---------------- | ||
| 18 | <dev path> <offset> <up interval> <down interval> \ | ||
| 19 | [<num_features> [<feature arguments>]] | ||
| 20 | |||
| 21 | Mandatory parameters: | ||
| 13 | <dev path>: Full pathname to the underlying block-device, or a | 22 | <dev path>: Full pathname to the underlying block-device, or a |
| 14 | "major:minor" device-number. | 23 | "major:minor" device-number. |
| 15 | <offset>: Starting sector within the device. | 24 | <offset>: Starting sector within the device. |
| 16 | <up interval>: Number of seconds device is available. | 25 | <up interval>: Number of seconds device is available. |
| 17 | <down interval>: Number of seconds device returns errors. | 26 | <down interval>: Number of seconds device returns errors. |
| 27 | |||
| 28 | Optional feature parameters: | ||
| 29 | If no feature parameters are present, during the periods of | ||
| 30 | unreliability, all I/O returns errors. | ||
| 31 | |||
| 32 | drop_writes: | ||
| 33 | All write I/O is silently ignored. | ||
| 34 | Read I/O is handled correctly. | ||
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c index dd963dc3ca08..e7c4c2a64f4b 100644 --- a/drivers/md/dm-flakey.c +++ b/drivers/md/dm-flakey.c | |||
| @@ -25,16 +25,22 @@ struct flakey_c { | |||
| 25 | sector_t start; | 25 | sector_t start; |
| 26 | unsigned up_interval; | 26 | unsigned up_interval; |
| 27 | unsigned down_interval; | 27 | unsigned down_interval; |
| 28 | unsigned long flags; | ||
| 28 | }; | 29 | }; |
| 29 | 30 | ||
| 30 | static int parse_features(struct dm_arg_set *as, struct dm_target *ti) | 31 | enum feature_flag_bits { |
| 32 | DROP_WRITES | ||
| 33 | }; | ||
| 34 | |||
| 35 | static int parse_features(struct dm_arg_set *as, struct flakey_c *fc, | ||
| 36 | struct dm_target *ti) | ||
| 31 | { | 37 | { |
| 32 | int r; | 38 | int r; |
| 33 | unsigned argc; | 39 | unsigned argc; |
| 34 | const char *arg_name; | 40 | const char *arg_name; |
| 35 | 41 | ||
| 36 | static struct dm_arg _args[] = { | 42 | static struct dm_arg _args[] = { |
| 37 | {0, 0, "Invalid number of feature args"}, | 43 | {0, 1, "Invalid number of feature args"}, |
| 38 | }; | 44 | }; |
| 39 | 45 | ||
| 40 | /* No feature arguments supplied. */ | 46 | /* No feature arguments supplied. */ |
| @@ -49,6 +55,18 @@ static int parse_features(struct dm_arg_set *as, struct dm_target *ti) | |||
| 49 | arg_name = dm_shift_arg(as); | 55 | arg_name = dm_shift_arg(as); |
| 50 | argc--; | 56 | argc--; |
| 51 | 57 | ||
| 58 | /* | ||
| 59 | * drop_writes | ||
| 60 | */ | ||
| 61 | if (!strcasecmp(arg_name, "drop_writes")) { | ||
| 62 | if (test_and_set_bit(DROP_WRITES, &fc->flags)) { | ||
| 63 | ti->error = "Feature drop_writes duplicated"; | ||
| 64 | return -EINVAL; | ||
| 65 | } | ||
| 66 | |||
| 67 | continue; | ||
| 68 | } | ||
| 69 | |||
| 52 | ti->error = "Unrecognised flakey feature requested"; | 70 | ti->error = "Unrecognised flakey feature requested"; |
| 53 | r = -EINVAL; | 71 | r = -EINVAL; |
| 54 | } | 72 | } |
| @@ -59,6 +77,9 @@ static int parse_features(struct dm_arg_set *as, struct dm_target *ti) | |||
| 59 | /* | 77 | /* |
| 60 | * Construct a flakey mapping: | 78 | * Construct a flakey mapping: |
| 61 | * <dev_path> <offset> <up interval> <down interval> [<#feature args> [<arg>]*] | 79 | * <dev_path> <offset> <up interval> <down interval> [<#feature args> [<arg>]*] |
| 80 | * | ||
| 81 | * Feature args: | ||
| 82 | * [drop_writes] | ||
| 62 | */ | 83 | */ |
| 63 | static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv) | 84 | static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv) |
| 64 | { | 85 | { |
| @@ -81,7 +102,7 @@ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
| 81 | return -EINVAL; | 102 | return -EINVAL; |
| 82 | } | 103 | } |
| 83 | 104 | ||
| 84 | fc = kmalloc(sizeof(*fc), GFP_KERNEL); | 105 | fc = kzalloc(sizeof(*fc), GFP_KERNEL); |
| 85 | if (!fc) { | 106 | if (!fc) { |
| 86 | ti->error = "Cannot allocate linear context"; | 107 | ti->error = "Cannot allocate linear context"; |
| 87 | return -ENOMEM; | 108 | return -ENOMEM; |
| @@ -114,7 +135,7 @@ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
| 114 | goto bad; | 135 | goto bad; |
| 115 | } | 136 | } |
| 116 | 137 | ||
| 117 | r = parse_features(&as, ti); | 138 | r = parse_features(&as, fc, ti); |
| 118 | if (r) | 139 | if (r) |
| 119 | goto bad; | 140 | goto bad; |
| 120 | 141 | ||
| @@ -162,12 +183,31 @@ static int flakey_map(struct dm_target *ti, struct bio *bio, | |||
| 162 | { | 183 | { |
| 163 | struct flakey_c *fc = ti->private; | 184 | struct flakey_c *fc = ti->private; |
| 164 | unsigned elapsed; | 185 | unsigned elapsed; |
| 186 | unsigned rw; | ||
| 165 | 187 | ||
| 166 | /* Are we alive ? */ | 188 | /* Are we alive ? */ |
| 167 | elapsed = (jiffies - fc->start_time) / HZ; | 189 | elapsed = (jiffies - fc->start_time) / HZ; |
| 168 | if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) | 190 | if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) { |
| 191 | rw = bio_data_dir(bio); | ||
| 192 | |||
| 193 | /* | ||
| 194 | * Drop writes. Map reads as normal. | ||
| 195 | */ | ||
| 196 | if (test_bit(DROP_WRITES, &fc->flags)) { | ||
| 197 | if (rw == WRITE) { | ||
| 198 | bio_endio(bio, 0); | ||
| 199 | return DM_MAPIO_SUBMITTED; | ||
| 200 | } | ||
| 201 | goto map_bio; | ||
| 202 | } | ||
| 203 | |||
| 204 | /* | ||
| 205 | * Default setting errors all I/O. | ||
| 206 | */ | ||
| 169 | return -EIO; | 207 | return -EIO; |
| 208 | } | ||
| 170 | 209 | ||
| 210 | map_bio: | ||
| 171 | flakey_map_bio(ti, bio); | 211 | flakey_map_bio(ti, bio); |
| 172 | 212 | ||
| 173 | return DM_MAPIO_REMAPPED; | 213 | return DM_MAPIO_REMAPPED; |
| @@ -176,7 +216,9 @@ static int flakey_map(struct dm_target *ti, struct bio *bio, | |||
| 176 | static int flakey_status(struct dm_target *ti, status_type_t type, | 216 | static int flakey_status(struct dm_target *ti, status_type_t type, |
| 177 | char *result, unsigned int maxlen) | 217 | char *result, unsigned int maxlen) |
| 178 | { | 218 | { |
| 219 | unsigned sz = 0; | ||
| 179 | struct flakey_c *fc = ti->private; | 220 | struct flakey_c *fc = ti->private; |
| 221 | unsigned drop_writes; | ||
| 180 | 222 | ||
| 181 | switch (type) { | 223 | switch (type) { |
| 182 | case STATUSTYPE_INFO: | 224 | case STATUSTYPE_INFO: |
| @@ -184,9 +226,14 @@ static int flakey_status(struct dm_target *ti, status_type_t type, | |||
| 184 | break; | 226 | break; |
| 185 | 227 | ||
| 186 | case STATUSTYPE_TABLE: | 228 | case STATUSTYPE_TABLE: |
| 187 | snprintf(result, maxlen, "%s %llu %u %u", fc->dev->name, | 229 | DMEMIT("%s %llu %u %u ", fc->dev->name, |
| 188 | (unsigned long long)fc->start, fc->up_interval, | 230 | (unsigned long long)fc->start, fc->up_interval, |
| 189 | fc->down_interval); | 231 | fc->down_interval); |
| 232 | |||
| 233 | drop_writes = test_bit(DROP_WRITES, &fc->flags); | ||
| 234 | DMEMIT("%u ", drop_writes); | ||
| 235 | if (drop_writes) | ||
| 236 | DMEMIT("drop_writes "); | ||
| 190 | break; | 237 | break; |
| 191 | } | 238 | } |
| 192 | return 0; | 239 | return 0; |
