| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2003 Sistina Software (UK) Limited. | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 3 | * Copyright (C) 2004, 2010-2011 Red Hat, Inc. All rights reserved. | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 4 | * | 
|  | 5 | * This file is released under the GPL. | 
|  | 6 | */ | 
|  | 7 |  | 
|  | 8 | #include <linux/device-mapper.h> | 
|  | 9 |  | 
|  | 10 | #include <linux/module.h> | 
|  | 11 | #include <linux/init.h> | 
|  | 12 | #include <linux/blkdev.h> | 
|  | 13 | #include <linux/bio.h> | 
|  | 14 | #include <linux/slab.h> | 
|  | 15 |  | 
|  | 16 | #define DM_MSG_PREFIX "flakey" | 
|  | 17 |  | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 18 | #define all_corrupt_bio_flags_match(bio, fc)	\ | 
|  | 19 | (((bio)->bi_rw & (fc)->corrupt_bio_flags) == (fc)->corrupt_bio_flags) | 
|  | 20 |  | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 21 | /* | 
|  | 22 | * Flakey: Used for testing only, simulates intermittent, | 
|  | 23 | * catastrophic device failure. | 
|  | 24 | */ | 
|  | 25 | struct flakey_c { | 
|  | 26 | struct dm_dev *dev; | 
|  | 27 | unsigned long start_time; | 
|  | 28 | sector_t start; | 
|  | 29 | unsigned up_interval; | 
|  | 30 | unsigned down_interval; | 
| Mike Snitzer | b26f5e3 | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 31 | unsigned long flags; | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 32 | unsigned corrupt_bio_byte; | 
|  | 33 | unsigned corrupt_bio_rw; | 
|  | 34 | unsigned corrupt_bio_value; | 
|  | 35 | unsigned corrupt_bio_flags; | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 36 | }; | 
|  | 37 |  | 
| Mike Snitzer | b26f5e3 | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 38 | enum feature_flag_bits { | 
|  | 39 | DROP_WRITES | 
|  | 40 | }; | 
|  | 41 |  | 
|  | 42 | static int parse_features(struct dm_arg_set *as, struct flakey_c *fc, | 
|  | 43 | struct dm_target *ti) | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 44 | { | 
|  | 45 | int r; | 
|  | 46 | unsigned argc; | 
|  | 47 | const char *arg_name; | 
|  | 48 |  | 
|  | 49 | static struct dm_arg _args[] = { | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 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"}, | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 54 | }; | 
|  | 55 |  | 
|  | 56 | /* No feature arguments supplied. */ | 
|  | 57 | if (!as->argc) | 
|  | 58 | return 0; | 
|  | 59 |  | 
|  | 60 | r = dm_read_arg_group(_args, as, &argc, &ti->error); | 
|  | 61 | if (r) | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 62 | return r; | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 63 |  | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 64 | while (argc) { | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 65 | arg_name = dm_shift_arg(as); | 
|  | 66 | argc--; | 
|  | 67 |  | 
| Mike Snitzer | b26f5e3 | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 68 | /* | 
|  | 69 | * drop_writes | 
|  | 70 | */ | 
|  | 71 | if (!strcasecmp(arg_name, "drop_writes")) { | 
|  | 72 | if (test_and_set_bit(DROP_WRITES, &fc->flags)) { | 
|  | 73 | ti->error = "Feature drop_writes duplicated"; | 
|  | 74 | return -EINVAL; | 
|  | 75 | } | 
|  | 76 |  | 
|  | 77 | continue; | 
|  | 78 | } | 
|  | 79 |  | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 80 | /* | 
|  | 81 | * corrupt_bio_byte <Nth_byte> <direction> <value> <bio_flags> | 
|  | 82 | */ | 
|  | 83 | if (!strcasecmp(arg_name, "corrupt_bio_byte")) { | 
| Mike Snitzer | 68e58a2 | 2011-09-25 23:26:15 +0100 | [diff] [blame] | 84 | if (!argc) { | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 85 | ti->error = "Feature corrupt_bio_byte requires parameters"; | 
| Mike Snitzer | 68e58a2 | 2011-09-25 23:26:15 +0100 | [diff] [blame] | 86 | return -EINVAL; | 
|  | 87 | } | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 88 |  | 
|  | 89 | r = dm_read_arg(_args + 1, as, &fc->corrupt_bio_byte, &ti->error); | 
|  | 90 | if (r) | 
|  | 91 | return r; | 
|  | 92 | argc--; | 
|  | 93 |  | 
|  | 94 | /* | 
|  | 95 | * Direction r or w? | 
|  | 96 | */ | 
|  | 97 | arg_name = dm_shift_arg(as); | 
|  | 98 | if (!strcasecmp(arg_name, "w")) | 
|  | 99 | fc->corrupt_bio_rw = WRITE; | 
|  | 100 | else if (!strcasecmp(arg_name, "r")) | 
|  | 101 | fc->corrupt_bio_rw = READ; | 
|  | 102 | else { | 
|  | 103 | ti->error = "Invalid corrupt bio direction (r or w)"; | 
|  | 104 | return -EINVAL; | 
|  | 105 | } | 
|  | 106 | argc--; | 
|  | 107 |  | 
|  | 108 | /* | 
|  | 109 | * Value of byte (0-255) to write in place of correct one. | 
|  | 110 | */ | 
|  | 111 | r = dm_read_arg(_args + 2, as, &fc->corrupt_bio_value, &ti->error); | 
|  | 112 | if (r) | 
|  | 113 | return r; | 
|  | 114 | argc--; | 
|  | 115 |  | 
|  | 116 | /* | 
|  | 117 | * Only corrupt bios with these flags set. | 
|  | 118 | */ | 
|  | 119 | r = dm_read_arg(_args + 3, as, &fc->corrupt_bio_flags, &ti->error); | 
|  | 120 | if (r) | 
|  | 121 | return r; | 
|  | 122 | argc--; | 
|  | 123 |  | 
|  | 124 | continue; | 
|  | 125 | } | 
|  | 126 |  | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 127 | ti->error = "Unrecognised flakey feature requested"; | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 128 | return -EINVAL; | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 129 | } | 
|  | 130 |  | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 131 | if (test_bit(DROP_WRITES, &fc->flags) && (fc->corrupt_bio_rw == WRITE)) { | 
|  | 132 | ti->error = "drop_writes is incompatible with corrupt_bio_byte with the WRITE flag set"; | 
|  | 133 | return -EINVAL; | 
|  | 134 | } | 
|  | 135 |  | 
|  | 136 | return 0; | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 137 | } | 
|  | 138 |  | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 139 | /* | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 140 | * Construct a flakey mapping: | 
|  | 141 | * <dev_path> <offset> <up interval> <down interval> [<#feature args> [<arg>]*] | 
| Mike Snitzer | b26f5e3 | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 142 | * | 
|  | 143 | *   Feature args: | 
|  | 144 | *     [drop_writes] | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 145 | *     [corrupt_bio_byte <Nth_byte> <direction> <value> <bio_flags>] | 
|  | 146 | * | 
|  | 147 | *   Nth_byte starts from 1 for the first byte. | 
|  | 148 | *   Direction is r for READ or w for WRITE. | 
|  | 149 | *   bio_flags is ignored if 0. | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 150 | */ | 
|  | 151 | static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv) | 
|  | 152 | { | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 153 | static struct dm_arg _args[] = { | 
|  | 154 | {0, UINT_MAX, "Invalid up interval"}, | 
|  | 155 | {0, UINT_MAX, "Invalid down interval"}, | 
|  | 156 | }; | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 157 |  | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 158 | int r; | 
|  | 159 | struct flakey_c *fc; | 
|  | 160 | unsigned long long tmpll; | 
|  | 161 | struct dm_arg_set as; | 
|  | 162 | const char *devname; | 
|  | 163 |  | 
|  | 164 | as.argc = argc; | 
|  | 165 | as.argv = argv; | 
|  | 166 |  | 
|  | 167 | if (argc < 4) { | 
|  | 168 | ti->error = "Invalid argument count"; | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 169 | return -EINVAL; | 
|  | 170 | } | 
|  | 171 |  | 
| Mike Snitzer | b26f5e3 | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 172 | fc = kzalloc(sizeof(*fc), GFP_KERNEL); | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 173 | if (!fc) { | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 174 | ti->error = "Cannot allocate linear context"; | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 175 | return -ENOMEM; | 
|  | 176 | } | 
|  | 177 | fc->start_time = jiffies; | 
|  | 178 |  | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 179 | devname = dm_shift_arg(&as); | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 180 |  | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 181 | if (sscanf(dm_shift_arg(&as), "%llu", &tmpll) != 1) { | 
|  | 182 | ti->error = "Invalid device sector"; | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 183 | goto bad; | 
|  | 184 | } | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 185 | fc->start = tmpll; | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 186 |  | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 187 | r = dm_read_arg(_args, &as, &fc->up_interval, &ti->error); | 
|  | 188 | if (r) | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 189 | goto bad; | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 190 |  | 
|  | 191 | r = dm_read_arg(_args, &as, &fc->down_interval, &ti->error); | 
|  | 192 | if (r) | 
|  | 193 | goto bad; | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 194 |  | 
|  | 195 | if (!(fc->up_interval + fc->down_interval)) { | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 196 | ti->error = "Total (up + down) interval is zero"; | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 197 | goto bad; | 
|  | 198 | } | 
|  | 199 |  | 
|  | 200 | if (fc->up_interval + fc->down_interval < fc->up_interval) { | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 201 | ti->error = "Interval overflow"; | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 202 | goto bad; | 
|  | 203 | } | 
|  | 204 |  | 
| Mike Snitzer | b26f5e3 | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 205 | r = parse_features(&as, fc, ti); | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 206 | if (r) | 
|  | 207 | goto bad; | 
|  | 208 |  | 
|  | 209 | if (dm_get_device(ti, devname, dm_table_get_mode(ti->table), &fc->dev)) { | 
|  | 210 | ti->error = "Device lookup failed"; | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 211 | goto bad; | 
|  | 212 | } | 
|  | 213 |  | 
|  | 214 | ti->num_flush_requests = 1; | 
| Mike Snitzer | 30e4171 | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 215 | ti->num_discard_requests = 1; | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 216 | ti->private = fc; | 
|  | 217 | return 0; | 
|  | 218 |  | 
|  | 219 | bad: | 
|  | 220 | kfree(fc); | 
|  | 221 | return -EINVAL; | 
|  | 222 | } | 
|  | 223 |  | 
|  | 224 | static void flakey_dtr(struct dm_target *ti) | 
|  | 225 | { | 
|  | 226 | struct flakey_c *fc = ti->private; | 
|  | 227 |  | 
|  | 228 | dm_put_device(ti, fc->dev); | 
|  | 229 | kfree(fc); | 
|  | 230 | } | 
|  | 231 |  | 
|  | 232 | static sector_t flakey_map_sector(struct dm_target *ti, sector_t bi_sector) | 
|  | 233 | { | 
|  | 234 | struct flakey_c *fc = ti->private; | 
|  | 235 |  | 
| Mike Snitzer | 30e4171 | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 236 | return fc->start + dm_target_offset(ti, bi_sector); | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 237 | } | 
|  | 238 |  | 
|  | 239 | static void flakey_map_bio(struct dm_target *ti, struct bio *bio) | 
|  | 240 | { | 
|  | 241 | struct flakey_c *fc = ti->private; | 
|  | 242 |  | 
|  | 243 | bio->bi_bdev = fc->dev->bdev; | 
|  | 244 | if (bio_sectors(bio)) | 
|  | 245 | bio->bi_sector = flakey_map_sector(ti, bio->bi_sector); | 
|  | 246 | } | 
|  | 247 |  | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 248 | static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc) | 
|  | 249 | { | 
|  | 250 | unsigned bio_bytes = bio_cur_bytes(bio); | 
|  | 251 | char *data = bio_data(bio); | 
|  | 252 |  | 
|  | 253 | /* | 
|  | 254 | * Overwrite the Nth byte of the data returned. | 
|  | 255 | */ | 
|  | 256 | if (data && bio_bytes >= fc->corrupt_bio_byte) { | 
|  | 257 | data[fc->corrupt_bio_byte - 1] = fc->corrupt_bio_value; | 
|  | 258 |  | 
|  | 259 | DMDEBUG("Corrupting data bio=%p by writing %u to byte %u " | 
|  | 260 | "(rw=%c bi_rw=%lu bi_sector=%llu cur_bytes=%u)\n", | 
|  | 261 | bio, fc->corrupt_bio_value, fc->corrupt_bio_byte, | 
|  | 262 | (bio_data_dir(bio) == WRITE) ? 'w' : 'r', | 
|  | 263 | bio->bi_rw, (unsigned long long)bio->bi_sector, bio_bytes); | 
|  | 264 | } | 
|  | 265 | } | 
|  | 266 |  | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 267 | static int flakey_map(struct dm_target *ti, struct bio *bio, | 
|  | 268 | union map_info *map_context) | 
|  | 269 | { | 
|  | 270 | struct flakey_c *fc = ti->private; | 
|  | 271 | unsigned elapsed; | 
|  | 272 |  | 
|  | 273 | /* Are we alive ? */ | 
|  | 274 | elapsed = (jiffies - fc->start_time) / HZ; | 
| Mike Snitzer | b26f5e3 | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 275 | if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) { | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 276 | /* | 
|  | 277 | * Flag this bio as submitted while down. | 
|  | 278 | */ | 
|  | 279 | map_context->ll = 1; | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 280 |  | 
| Mike Snitzer | b26f5e3 | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 281 | /* | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 282 | * Map reads as normal. | 
|  | 283 | */ | 
|  | 284 | if (bio_data_dir(bio) == READ) | 
|  | 285 | goto map_bio; | 
|  | 286 |  | 
|  | 287 | /* | 
|  | 288 | * Drop writes? | 
| Mike Snitzer | b26f5e3 | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 289 | */ | 
|  | 290 | if (test_bit(DROP_WRITES, &fc->flags)) { | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 291 | bio_endio(bio, 0); | 
|  | 292 | return DM_MAPIO_SUBMITTED; | 
|  | 293 | } | 
|  | 294 |  | 
|  | 295 | /* | 
|  | 296 | * Corrupt matching writes. | 
|  | 297 | */ | 
|  | 298 | if (fc->corrupt_bio_byte && (fc->corrupt_bio_rw == WRITE)) { | 
|  | 299 | if (all_corrupt_bio_flags_match(bio, fc)) | 
|  | 300 | corrupt_bio_data(bio, fc); | 
| Mike Snitzer | b26f5e3 | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 301 | goto map_bio; | 
|  | 302 | } | 
|  | 303 |  | 
|  | 304 | /* | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 305 | * By default, error all I/O. | 
| Mike Snitzer | b26f5e3 | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 306 | */ | 
|  | 307 | return -EIO; | 
|  | 308 | } | 
|  | 309 |  | 
|  | 310 | map_bio: | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 311 | flakey_map_bio(ti, bio); | 
|  | 312 |  | 
|  | 313 | return DM_MAPIO_REMAPPED; | 
|  | 314 | } | 
|  | 315 |  | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 316 | static int flakey_end_io(struct dm_target *ti, struct bio *bio, | 
|  | 317 | int error, union map_info *map_context) | 
|  | 318 | { | 
|  | 319 | struct flakey_c *fc = ti->private; | 
|  | 320 | unsigned bio_submitted_while_down = map_context->ll; | 
|  | 321 |  | 
|  | 322 | /* | 
|  | 323 | * Corrupt successful READs while in down state. | 
|  | 324 | * If flags were specified, only corrupt those that match. | 
|  | 325 | */ | 
|  | 326 | if (!error && bio_submitted_while_down && | 
|  | 327 | (bio_data_dir(bio) == READ) && (fc->corrupt_bio_rw == READ) && | 
|  | 328 | all_corrupt_bio_flags_match(bio, fc)) | 
|  | 329 | corrupt_bio_data(bio, fc); | 
|  | 330 |  | 
|  | 331 | return error; | 
|  | 332 | } | 
|  | 333 |  | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 334 | static int flakey_status(struct dm_target *ti, status_type_t type, | 
|  | 335 | char *result, unsigned int maxlen) | 
|  | 336 | { | 
| Mike Snitzer | b26f5e3 | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 337 | unsigned sz = 0; | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 338 | struct flakey_c *fc = ti->private; | 
| Mike Snitzer | b26f5e3 | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 339 | unsigned drop_writes; | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 340 |  | 
|  | 341 | switch (type) { | 
|  | 342 | case STATUSTYPE_INFO: | 
|  | 343 | result[0] = '\0'; | 
|  | 344 | break; | 
|  | 345 |  | 
|  | 346 | case STATUSTYPE_TABLE: | 
| Mike Snitzer | b26f5e3 | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 347 | DMEMIT("%s %llu %u %u ", fc->dev->name, | 
|  | 348 | (unsigned long long)fc->start, fc->up_interval, | 
|  | 349 | fc->down_interval); | 
|  | 350 |  | 
|  | 351 | drop_writes = test_bit(DROP_WRITES, &fc->flags); | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 352 | DMEMIT("%u ", drop_writes + (fc->corrupt_bio_byte > 0) * 5); | 
|  | 353 |  | 
| Mike Snitzer | b26f5e3 | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 354 | if (drop_writes) | 
|  | 355 | DMEMIT("drop_writes "); | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 356 |  | 
|  | 357 | if (fc->corrupt_bio_byte) | 
|  | 358 | DMEMIT("corrupt_bio_byte %u %c %u %u ", | 
|  | 359 | fc->corrupt_bio_byte, | 
|  | 360 | (fc->corrupt_bio_rw == WRITE) ? 'w' : 'r', | 
|  | 361 | fc->corrupt_bio_value, fc->corrupt_bio_flags); | 
|  | 362 |  | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 363 | break; | 
|  | 364 | } | 
|  | 365 | return 0; | 
|  | 366 | } | 
|  | 367 |  | 
|  | 368 | static int flakey_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg) | 
|  | 369 | { | 
|  | 370 | struct flakey_c *fc = ti->private; | 
|  | 371 |  | 
|  | 372 | return __blkdev_driver_ioctl(fc->dev->bdev, fc->dev->mode, cmd, arg); | 
|  | 373 | } | 
|  | 374 |  | 
|  | 375 | static int flakey_merge(struct dm_target *ti, struct bvec_merge_data *bvm, | 
|  | 376 | struct bio_vec *biovec, int max_size) | 
|  | 377 | { | 
|  | 378 | struct flakey_c *fc = ti->private; | 
|  | 379 | struct request_queue *q = bdev_get_queue(fc->dev->bdev); | 
|  | 380 |  | 
|  | 381 | if (!q->merge_bvec_fn) | 
|  | 382 | return max_size; | 
|  | 383 |  | 
|  | 384 | bvm->bi_bdev = fc->dev->bdev; | 
|  | 385 | bvm->bi_sector = flakey_map_sector(ti, bvm->bi_sector); | 
|  | 386 |  | 
|  | 387 | return min(max_size, q->merge_bvec_fn(q, bvm, biovec)); | 
|  | 388 | } | 
|  | 389 |  | 
|  | 390 | static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data) | 
|  | 391 | { | 
|  | 392 | struct flakey_c *fc = ti->private; | 
|  | 393 |  | 
|  | 394 | return fn(ti, fc->dev, fc->start, ti->len, data); | 
|  | 395 | } | 
|  | 396 |  | 
|  | 397 | static struct target_type flakey_target = { | 
|  | 398 | .name   = "flakey", | 
| Mike Snitzer | dfd068b | 2011-08-02 12:32:05 +0100 | [diff] [blame] | 399 | .version = {1, 2, 0}, | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 400 | .module = THIS_MODULE, | 
|  | 401 | .ctr    = flakey_ctr, | 
|  | 402 | .dtr    = flakey_dtr, | 
|  | 403 | .map    = flakey_map, | 
| Mike Snitzer | a399879 | 2011-08-02 12:32:06 +0100 | [diff] [blame] | 404 | .end_io = flakey_end_io, | 
| Josef Bacik | 3407ef5 | 2011-03-24 13:54:24 +0000 | [diff] [blame] | 405 | .status = flakey_status, | 
|  | 406 | .ioctl	= flakey_ioctl, | 
|  | 407 | .merge	= flakey_merge, | 
|  | 408 | .iterate_devices = flakey_iterate_devices, | 
|  | 409 | }; | 
|  | 410 |  | 
|  | 411 | static int __init dm_flakey_init(void) | 
|  | 412 | { | 
|  | 413 | int r = dm_register_target(&flakey_target); | 
|  | 414 |  | 
|  | 415 | if (r < 0) | 
|  | 416 | DMERR("register failed %d", r); | 
|  | 417 |  | 
|  | 418 | return r; | 
|  | 419 | } | 
|  | 420 |  | 
|  | 421 | static void __exit dm_flakey_exit(void) | 
|  | 422 | { | 
|  | 423 | dm_unregister_target(&flakey_target); | 
|  | 424 | } | 
|  | 425 |  | 
|  | 426 | /* Module hooks */ | 
|  | 427 | module_init(dm_flakey_init); | 
|  | 428 | module_exit(dm_flakey_exit); | 
|  | 429 |  | 
|  | 430 | MODULE_DESCRIPTION(DM_NAME " flakey target"); | 
|  | 431 | MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>"); | 
|  | 432 | MODULE_LICENSE("GPL"); |