1
1
/*
2
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
5
* This file is released under the GPL.
6
6
*/
15
15
16
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
22
* Flakey: Used for testing only, simulates intermittent,
20
23
* catastrophic device failure.
@@ -26,6 +29,10 @@ struct flakey_c {
26
29
unsigned up_interval ;
27
30
unsigned down_interval ;
28
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
31
38
enum feature_flag_bits {
@@ -40,7 +47,10 @@ static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
40
47
const char * arg_name ;
41
48
42
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
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
60
r = dm_read_arg_group (_args , as , & argc , & ti -> error );
51
61
if (r )
52
- return - EINVAL ;
62
+ return r ;
53
63
54
- while (argc && ! r ) {
64
+ while (argc ) {
55
65
arg_name = dm_shift_arg (as );
56
66
argc -- ;
57
67
@@ -67,11 +77,61 @@ static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
67
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
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
141
* Feature args:
82
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
*/
84
149
static 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
243
bio -> bi_sector = flakey_map_sector (ti , bio -> bi_sector );
179
244
}
180
245
246
+ static 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
+
181
265
static int flakey_map (struct dm_target * ti , struct bio * bio ,
182
266
union map_info * map_context )
183
267
{
184
268
struct flakey_c * fc = ti -> private ;
185
269
unsigned elapsed ;
186
- unsigned rw ;
187
270
188
271
/* Are we alive ? */
189
272
elapsed = (jiffies - fc -> start_time ) / HZ ;
190
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
288
if (test_bit (DROP_WRITES , & fc -> flags )) {
197
- if (rw == WRITE ) {
198
- bio_endio (bio , 0 );
199
- return DM_MAPIO_SUBMITTED ;
200
- }
289
+ bio_endio (bio , 0 );
290
+ return DM_MAPIO_SUBMITTED ;
291
+ }
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
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
305
return - EIO ;
208
306
}
@@ -213,6 +311,24 @@ static int flakey_map(struct dm_target *ti, struct bio *bio,
213
311
return DM_MAPIO_REMAPPED ;
214
312
}
215
313
314
+ static 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
+
216
332
static int flakey_status (struct dm_target * ti , status_type_t type ,
217
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
347
fc -> down_interval );
232
348
233
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
352
if (drop_writes )
236
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
361
break ;
238
362
}
239
363
return 0 ;
@@ -275,6 +399,7 @@ static struct target_type flakey_target = {
275
399
.ctr = flakey_ctr ,
276
400
.dtr = flakey_dtr ,
277
401
.map = flakey_map ,
402
+ .end_io = flakey_end_io ,
278
403
.status = flakey_status ,
279
404
.ioctl = flakey_ioctl ,
280
405
.merge = flakey_merge ,
0 commit comments