aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorMike Snitzer <snitzer@redhat.com>2011-08-02 07:32:06 -0400
committerAlasdair G Kergon <agk@redhat.com>2011-08-02 07:32:06 -0400
commita3998799fb4df0b0af8271a7d50c4269032397aa (patch)
tree2a0dc0a082519afd70cc991da36f620bc21272fe /drivers/md
parentb26f5e3d7127487e934758c1fbe05d683b082cb0 (diff)
dm flakey: add corrupt_bio_byte feature
Add corrupt_bio_byte feature to simulate corruption by overwriting a byte at a specified position with a specified value during intervals when the device is "down". Signed-off-by: Mike Snitzer <snitzer@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/dm-flakey.c155
1 files changed, 140 insertions, 15 deletions
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c
index e7c4c2a64f4b..89f73ca22cfa 100644
--- a/drivers/md/dm-flakey.c
+++ b/drivers/md/dm-flakey.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * Copyright (C) 2003 Sistina Software (UK) Limited. 2 * Copyright (C) 2003 Sistina Software (UK) Limited.
3 * Copyright (C) 2004, 2010 Red Hat, Inc. All rights reserved. 3 * Copyright (C) 2004, 2010-2011 Red Hat, Inc. All rights reserved.
4 * 4 *
5 * This file is released under the GPL. 5 * This file is released under the GPL.
6 */ 6 */
@@ -15,6 +15,9 @@
15 15
16#define DM_MSG_PREFIX "flakey" 16#define DM_MSG_PREFIX "flakey"
17 17
18#define all_corrupt_bio_flags_match(bio, fc) \
19 (((bio)->bi_rw & (fc)->corrupt_bio_flags) == (fc)->corrupt_bio_flags)
20
18/* 21/*
19 * Flakey: Used for testing only, simulates intermittent, 22 * Flakey: Used for testing only, simulates intermittent,
20 * catastrophic device failure. 23 * catastrophic device failure.
@@ -26,6 +29,10 @@ struct flakey_c {
26 unsigned up_interval; 29 unsigned up_interval;
27 unsigned down_interval; 30 unsigned down_interval;
28 unsigned long flags; 31 unsigned long flags;
32 unsigned corrupt_bio_byte;
33 unsigned corrupt_bio_rw;
34 unsigned corrupt_bio_value;
35 unsigned corrupt_bio_flags;
29}; 36};
30 37
31enum feature_flag_bits { 38enum feature_flag_bits {
@@ -40,7 +47,10 @@ static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
40 const char *arg_name; 47 const char *arg_name;
41 48
42 static struct dm_arg _args[] = { 49 static struct dm_arg _args[] = {
43 {0, 1, "Invalid number of feature args"}, 50 {0, 6, "Invalid number of feature args"},
51 {1, UINT_MAX, "Invalid corrupt bio byte"},
52 {0, 255, "Invalid corrupt value to write into bio byte (0-255)"},
53 {0, UINT_MAX, "Invalid corrupt bio flags mask"},
44 }; 54 };
45 55
46 /* No feature arguments supplied. */ 56 /* No feature arguments supplied. */
@@ -49,9 +59,9 @@ static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
49 59
50 r = dm_read_arg_group(_args, as, &argc, &ti->error); 60 r = dm_read_arg_group(_args, as, &argc, &ti->error);
51 if (r) 61 if (r)
52 return -EINVAL; 62 return r;
53 63
54 while (argc && !r) { 64 while (argc) {
55 arg_name = dm_shift_arg(as); 65 arg_name = dm_shift_arg(as);
56 argc--; 66 argc--;
57 67
@@ -67,11 +77,61 @@ static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
67 continue; 77 continue;
68 } 78 }
69 79
80 /*
81 * corrupt_bio_byte <Nth_byte> <direction> <value> <bio_flags>
82 */
83 if (!strcasecmp(arg_name, "corrupt_bio_byte")) {
84 if (!argc)
85 ti->error = "Feature corrupt_bio_byte requires parameters";
86
87 r = dm_read_arg(_args + 1, as, &fc->corrupt_bio_byte, &ti->error);
88 if (r)
89 return r;
90 argc--;
91
92 /*
93 * Direction r or w?
94 */
95 arg_name = dm_shift_arg(as);
96 if (!strcasecmp(arg_name, "w"))
97 fc->corrupt_bio_rw = WRITE;
98 else if (!strcasecmp(arg_name, "r"))
99 fc->corrupt_bio_rw = READ;
100 else {
101 ti->error = "Invalid corrupt bio direction (r or w)";
102 return -EINVAL;
103 }
104 argc--;
105
106 /*
107 * Value of byte (0-255) to write in place of correct one.
108 */
109 r = dm_read_arg(_args + 2, as, &fc->corrupt_bio_value, &ti->error);
110 if (r)
111 return r;
112 argc--;
113
114 /*
115 * Only corrupt bios with these flags set.
116 */
117 r = dm_read_arg(_args + 3, as, &fc->corrupt_bio_flags, &ti->error);
118 if (r)
119 return r;
120 argc--;
121
122 continue;
123 }
124
70 ti->error = "Unrecognised flakey feature requested"; 125 ti->error = "Unrecognised flakey feature requested";
71 r = -EINVAL; 126 return -EINVAL;
72 } 127 }
73 128
74 return r; 129 if (test_bit(DROP_WRITES, &fc->flags) && (fc->corrupt_bio_rw == WRITE)) {
130 ti->error = "drop_writes is incompatible with corrupt_bio_byte with the WRITE flag set";
131 return -EINVAL;
132 }
133
134 return 0;
75} 135}
76 136
77/* 137/*
@@ -80,6 +140,11 @@ static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
80 * 140 *
81 * Feature args: 141 * Feature args:
82 * [drop_writes] 142 * [drop_writes]
143 * [corrupt_bio_byte <Nth_byte> <direction> <value> <bio_flags>]
144 *
145 * Nth_byte starts from 1 for the first byte.
146 * Direction is r for READ or w for WRITE.
147 * bio_flags is ignored if 0.
83 */ 148 */
84static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv) 149static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)
85{ 150{
@@ -178,31 +243,64 @@ static void flakey_map_bio(struct dm_target *ti, struct bio *bio)
178 bio->bi_sector = flakey_map_sector(ti, bio->bi_sector); 243 bio->bi_sector = flakey_map_sector(ti, bio->bi_sector);
179} 244}
180 245
246static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc)
247{
248 unsigned bio_bytes = bio_cur_bytes(bio);
249 char *data = bio_data(bio);
250
251 /*
252 * Overwrite the Nth byte of the data returned.
253 */
254 if (data && bio_bytes >= fc->corrupt_bio_byte) {
255 data[fc->corrupt_bio_byte - 1] = fc->corrupt_bio_value;
256
257 DMDEBUG("Corrupting data bio=%p by writing %u to byte %u "
258 "(rw=%c bi_rw=%lu bi_sector=%llu cur_bytes=%u)\n",
259 bio, fc->corrupt_bio_value, fc->corrupt_bio_byte,
260 (bio_data_dir(bio) == WRITE) ? 'w' : 'r',
261 bio->bi_rw, (unsigned long long)bio->bi_sector, bio_bytes);
262 }
263}
264
181static int flakey_map(struct dm_target *ti, struct bio *bio, 265static int flakey_map(struct dm_target *ti, struct bio *bio,
182 union map_info *map_context) 266 union map_info *map_context)
183{ 267{
184 struct flakey_c *fc = ti->private; 268 struct flakey_c *fc = ti->private;
185 unsigned elapsed; 269 unsigned elapsed;
186 unsigned rw;
187 270
188 /* Are we alive ? */ 271 /* Are we alive ? */
189 elapsed = (jiffies - fc->start_time) / HZ; 272 elapsed = (jiffies - fc->start_time) / HZ;
190 if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) { 273 if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) {
191 rw = bio_data_dir(bio); 274 /*
275 * Flag this bio as submitted while down.
276 */
277 map_context->ll = 1;
278
279 /*
280 * Map reads as normal.
281 */
282 if (bio_data_dir(bio) == READ)
283 goto map_bio;
192 284
193 /* 285 /*
194 * Drop writes. Map reads as normal. 286 * Drop writes?
195 */ 287 */
196 if (test_bit(DROP_WRITES, &fc->flags)) { 288 if (test_bit(DROP_WRITES, &fc->flags)) {
197 if (rw == WRITE) { 289 bio_endio(bio, 0);
198 bio_endio(bio, 0); 290 return DM_MAPIO_SUBMITTED;
199 return DM_MAPIO_SUBMITTED; 291 }
200 } 292
293 /*
294 * Corrupt matching writes.
295 */
296 if (fc->corrupt_bio_byte && (fc->corrupt_bio_rw == WRITE)) {
297 if (all_corrupt_bio_flags_match(bio, fc))
298 corrupt_bio_data(bio, fc);
201 goto map_bio; 299 goto map_bio;
202 } 300 }
203 301
204 /* 302 /*
205 * Default setting errors all I/O. 303 * By default, error all I/O.
206 */ 304 */
207 return -EIO; 305 return -EIO;
208 } 306 }
@@ -213,6 +311,24 @@ map_bio:
213 return DM_MAPIO_REMAPPED; 311 return DM_MAPIO_REMAPPED;
214} 312}
215 313
314static int flakey_end_io(struct dm_target *ti, struct bio *bio,
315 int error, union map_info *map_context)
316{
317 struct flakey_c *fc = ti->private;
318 unsigned bio_submitted_while_down = map_context->ll;
319
320 /*
321 * Corrupt successful READs while in down state.
322 * If flags were specified, only corrupt those that match.
323 */
324 if (!error && bio_submitted_while_down &&
325 (bio_data_dir(bio) == READ) && (fc->corrupt_bio_rw == READ) &&
326 all_corrupt_bio_flags_match(bio, fc))
327 corrupt_bio_data(bio, fc);
328
329 return error;
330}
331
216static int flakey_status(struct dm_target *ti, status_type_t type, 332static int flakey_status(struct dm_target *ti, status_type_t type,
217 char *result, unsigned int maxlen) 333 char *result, unsigned int maxlen)
218{ 334{
@@ -231,9 +347,17 @@ static int flakey_status(struct dm_target *ti, status_type_t type,
231 fc->down_interval); 347 fc->down_interval);
232 348
233 drop_writes = test_bit(DROP_WRITES, &fc->flags); 349 drop_writes = test_bit(DROP_WRITES, &fc->flags);
234 DMEMIT("%u ", drop_writes); 350 DMEMIT("%u ", drop_writes + (fc->corrupt_bio_byte > 0) * 5);
351
235 if (drop_writes) 352 if (drop_writes)
236 DMEMIT("drop_writes "); 353 DMEMIT("drop_writes ");
354
355 if (fc->corrupt_bio_byte)
356 DMEMIT("corrupt_bio_byte %u %c %u %u ",
357 fc->corrupt_bio_byte,
358 (fc->corrupt_bio_rw == WRITE) ? 'w' : 'r',
359 fc->corrupt_bio_value, fc->corrupt_bio_flags);
360
237 break; 361 break;
238 } 362 }
239 return 0; 363 return 0;
@@ -275,6 +399,7 @@ static struct target_type flakey_target = {
275 .ctr = flakey_ctr, 399 .ctr = flakey_ctr,
276 .dtr = flakey_dtr, 400 .dtr = flakey_dtr,
277 .map = flakey_map, 401 .map = flakey_map,
402 .end_io = flakey_end_io,
278 .status = flakey_status, 403 .status = flakey_status,
279 .ioctl = flakey_ioctl, 404 .ioctl = flakey_ioctl,
280 .merge = flakey_merge, 405 .merge = flakey_merge,