Blame view
drivers/md/faulty.c
8.81 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/* * faulty.c : Multiple Devices driver for Linux * * Copyright (C) 2004 Neil Brown * * fautly-device-simulator personality for md * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example /usr/src/linux/COPYING); if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * The "faulty" personality causes some requests to fail. * * Possible failure modes are: * reads fail "randomly" but succeed on retry * writes fail "randomly" but succeed on retry * reads for some address fail and then persist until a write * reads for some address fail and then persist irrespective of write * writes for some address fail and persist * all writes fail * * Different modes can be active at a time, but only * one can be set at array creation. Others can be added later. |
25985edce Fix common misspe... |
33 |
* A mode can be one-shot or recurrent with the recurrence being |
1da177e4c Linux-2.6.12-rc2 |
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
* once in every N requests. * The bottom 5 bits of the "layout" indicate the mode. The * remainder indicate a period, or 0 for one-shot. * * There is an implementation limit on the number of concurrently * persisting-faulty blocks. When a new fault is requested that would * exceed the limit, it is ignored. * All current faults can be clear using a layout of "0". * * Requests are always sent to the device. If they are to fail, * we clone the bio and insert a new b_end_io into the chain. */ #define WriteTransient 0 #define ReadTransient 1 #define WritePersistent 2 #define ReadPersistent 3 #define WriteAll 4 /* doesn't go to device */ #define ReadFixable 5 #define Modes 6 #define ClearErrors 31 #define ClearFaults 30 #define AllPersist 100 /* internal use only */ #define NoPersist 101 #define ModeMask 0x1f #define ModeShift 5 #define MaxFault 50 |
bff61975b md: move lots of ... |
65 |
#include <linux/blkdev.h> |
056075c76 md: Add module.h ... |
66 |
#include <linux/module.h> |
bff61975b md: move lots of ... |
67 |
#include <linux/raid/md_u.h> |
5a0e3ad6a include cleanup: ... |
68 |
#include <linux/slab.h> |
43b2e5d86 md: move md_k.h f... |
69 |
#include "md.h" |
bff61975b md: move lots of ... |
70 |
#include <linux/seq_file.h> |
1da177e4c Linux-2.6.12-rc2 |
71 |
|
6712ecf8f Drop 'size' argum... |
72 |
static void faulty_fail(struct bio *bio, int error) |
1da177e4c Linux-2.6.12-rc2 |
73 74 75 76 77 |
{ struct bio *b = bio->bi_private; b->bi_size = bio->bi_size; b->bi_sector = bio->bi_sector; |
6712ecf8f Drop 'size' argum... |
78 |
bio_put(bio); |
1da177e4c Linux-2.6.12-rc2 |
79 |
|
6712ecf8f Drop 'size' argum... |
80 |
bio_io_error(b); |
1da177e4c Linux-2.6.12-rc2 |
81 |
} |
8f1ae43dd md/faulty: remove... |
82 |
struct faulty_conf { |
1da177e4c Linux-2.6.12-rc2 |
83 84 85 86 87 |
int period[Modes]; atomic_t counters[Modes]; sector_t faults[MaxFault]; int modes[MaxFault]; int nfaults; |
3cb030020 md: removing type... |
88 |
struct md_rdev *rdev; |
8f1ae43dd md/faulty: remove... |
89 |
}; |
1da177e4c Linux-2.6.12-rc2 |
90 |
|
8f1ae43dd md/faulty: remove... |
91 |
static int check_mode(struct faulty_conf *conf, int mode) |
1da177e4c Linux-2.6.12-rc2 |
92 93 94 95 96 97 98 99 100 101 102 103 104 |
{ if (conf->period[mode] == 0 && atomic_read(&conf->counters[mode]) <= 0) return 0; /* no failure, no decrement */ if (atomic_dec_and_test(&conf->counters[mode])) { if (conf->period[mode]) atomic_set(&conf->counters[mode], conf->period[mode]); return 1; } return 0; } |
8f1ae43dd md/faulty: remove... |
105 |
static int check_sector(struct faulty_conf *conf, sector_t start, sector_t end, int dir) |
1da177e4c Linux-2.6.12-rc2 |
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
{ /* If we find a ReadFixable sector, we fix it ... */ int i; for (i=0; i<conf->nfaults; i++) if (conf->faults[i] >= start && conf->faults[i] < end) { /* found it ... */ switch (conf->modes[i] * 2 + dir) { case WritePersistent*2+WRITE: return 1; case ReadPersistent*2+READ: return 1; case ReadFixable*2+READ: return 1; case ReadFixable*2+WRITE: conf->modes[i] = NoPersist; return 0; case AllPersist*2+READ: case AllPersist*2+WRITE: return 1; default: return 0; } } return 0; } |
8f1ae43dd md/faulty: remove... |
128 |
static void add_sector(struct faulty_conf *conf, sector_t start, int mode) |
1da177e4c Linux-2.6.12-rc2 |
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
{ int i; int n = conf->nfaults; for (i=0; i<conf->nfaults; i++) if (conf->faults[i] == start) { switch(mode) { case NoPersist: conf->modes[i] = mode; return; case WritePersistent: if (conf->modes[i] == ReadPersistent || conf->modes[i] == ReadFixable) conf->modes[i] = AllPersist; else conf->modes[i] = WritePersistent; return; case ReadPersistent: if (conf->modes[i] == WritePersistent) conf->modes[i] = AllPersist; else conf->modes[i] = ReadPersistent; return; case ReadFixable: if (conf->modes[i] == WritePersistent || conf->modes[i] == ReadPersistent) conf->modes[i] = AllPersist; else conf->modes[i] = ReadFixable; return; } } else if (conf->modes[i] == NoPersist) n = i; if (n >= MaxFault) return; conf->faults[n] = start; conf->modes[n] = mode; if (conf->nfaults == n) conf->nfaults = n+1; } |
b4fdcb02f Merge branch 'for... |
167 |
static void make_request(struct mddev *mddev, struct bio *bio) |
1da177e4c Linux-2.6.12-rc2 |
168 |
{ |
8f1ae43dd md/faulty: remove... |
169 |
struct faulty_conf *conf = mddev->private; |
1da177e4c Linux-2.6.12-rc2 |
170 |
int failit = 0; |
802ba064c [PATCH] md: Don't... |
171 |
if (bio_data_dir(bio) == WRITE) { |
1da177e4c Linux-2.6.12-rc2 |
172 173 174 175 176 |
/* write request */ if (atomic_read(&conf->counters[WriteAll])) { /* special case - don't decrement, don't generic_make_request, * just fail immediately */ |
6712ecf8f Drop 'size' argum... |
177 |
bio_endio(bio, -EIO); |
5a7bbad27 block: remove sup... |
178 |
return; |
1da177e4c Linux-2.6.12-rc2 |
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
} if (check_sector(conf, bio->bi_sector, bio->bi_sector+(bio->bi_size>>9), WRITE)) failit = 1; if (check_mode(conf, WritePersistent)) { add_sector(conf, bio->bi_sector, WritePersistent); failit = 1; } if (check_mode(conf, WriteTransient)) failit = 1; } else { /* read request */ if (check_sector(conf, bio->bi_sector, bio->bi_sector + (bio->bi_size>>9), READ)) failit = 1; if (check_mode(conf, ReadTransient)) failit = 1; if (check_mode(conf, ReadPersistent)) { add_sector(conf, bio->bi_sector, ReadPersistent); failit = 1; } if (check_mode(conf, ReadFixable)) { add_sector(conf, bio->bi_sector, ReadFixable); failit = 1; } } if (failit) { |
a167f6632 md: use separate ... |
207 |
struct bio *b = bio_clone_mddev(bio, GFP_NOIO, mddev); |
5a7bbad27 block: remove sup... |
208 |
|
1da177e4c Linux-2.6.12-rc2 |
209 210 211 |
b->bi_bdev = conf->rdev->bdev; b->bi_private = bio; b->bi_end_io = faulty_fail; |
5a7bbad27 block: remove sup... |
212 213 |
bio = b; } else |
1da177e4c Linux-2.6.12-rc2 |
214 |
bio->bi_bdev = conf->rdev->bdev; |
5a7bbad27 block: remove sup... |
215 216 |
generic_make_request(bio); |
1da177e4c Linux-2.6.12-rc2 |
217 |
} |
fd01b88c7 md: remove typede... |
218 |
static void status(struct seq_file *seq, struct mddev *mddev) |
1da177e4c Linux-2.6.12-rc2 |
219 |
{ |
8f1ae43dd md/faulty: remove... |
220 |
struct faulty_conf *conf = mddev->private; |
1da177e4c Linux-2.6.12-rc2 |
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
int n; if ((n=atomic_read(&conf->counters[WriteTransient])) != 0) seq_printf(seq, " WriteTransient=%d(%d)", n, conf->period[WriteTransient]); if ((n=atomic_read(&conf->counters[ReadTransient])) != 0) seq_printf(seq, " ReadTransient=%d(%d)", n, conf->period[ReadTransient]); if ((n=atomic_read(&conf->counters[WritePersistent])) != 0) seq_printf(seq, " WritePersistent=%d(%d)", n, conf->period[WritePersistent]); if ((n=atomic_read(&conf->counters[ReadPersistent])) != 0) seq_printf(seq, " ReadPersistent=%d(%d)", n, conf->period[ReadPersistent]); if ((n=atomic_read(&conf->counters[ReadFixable])) != 0) seq_printf(seq, " ReadFixable=%d(%d)", n, conf->period[ReadFixable]); if ((n=atomic_read(&conf->counters[WriteAll])) != 0) seq_printf(seq, " WriteAll"); seq_printf(seq, " nfaults=%d", conf->nfaults); } |
fd01b88c7 md: remove typede... |
249 |
static int reshape(struct mddev *mddev) |
1da177e4c Linux-2.6.12-rc2 |
250 |
{ |
597a711b6 md: remove unnece... |
251 252 |
int mode = mddev->new_layout & ModeMask; int count = mddev->new_layout >> ModeShift; |
8f1ae43dd md/faulty: remove... |
253 |
struct faulty_conf *conf = mddev->private; |
1da177e4c Linux-2.6.12-rc2 |
254 |
|
597a711b6 md: remove unnece... |
255 256 |
if (mddev->new_layout < 0) return 0; |
1da177e4c Linux-2.6.12-rc2 |
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
/* new layout */ if (mode == ClearFaults) conf->nfaults = 0; else if (mode == ClearErrors) { int i; for (i=0 ; i < Modes ; i++) { conf->period[i] = 0; atomic_set(&conf->counters[i], 0); } } else if (mode < Modes) { conf->period[mode] = count; if (!count) count++; atomic_set(&conf->counters[mode], count); } else return -EINVAL; |
597a711b6 md: remove unnece... |
273 |
mddev->new_layout = -1; |
1da177e4c Linux-2.6.12-rc2 |
274 275 276 |
mddev->layout = -1; /* makes sure further changes come through */ return 0; } |
fd01b88c7 md: remove typede... |
277 |
static sector_t faulty_size(struct mddev *mddev, sector_t sectors, int raid_disks) |
80c3a6ce4 md: add 'size' as... |
278 279 280 281 282 283 284 285 286 287 |
{ WARN_ONCE(raid_disks, "%s does not support generic reshape ", __func__); if (sectors == 0) return mddev->dev_sectors; return sectors; } |
fd01b88c7 md: remove typede... |
288 |
static int run(struct mddev *mddev) |
1da177e4c Linux-2.6.12-rc2 |
289 |
{ |
3cb030020 md: removing type... |
290 |
struct md_rdev *rdev; |
1da177e4c Linux-2.6.12-rc2 |
291 |
int i; |
8f1ae43dd md/faulty: remove... |
292 |
struct faulty_conf *conf; |
1da177e4c Linux-2.6.12-rc2 |
293 |
|
0894cc306 md: Move check fo... |
294 295 296 297 |
if (md_check_no_bitmap(mddev)) return -EINVAL; conf = kmalloc(sizeof(*conf), GFP_KERNEL); |
08ff39f1c md: check for mem... |
298 299 |
if (!conf) return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
300 301 302 303 304 305 |
for (i=0; i<Modes; i++) { atomic_set(&conf->counters[i], 0); conf->period[i] = 0; } conf->nfaults = 0; |
159ec1fc0 md: use list_for_... |
306 |
list_for_each_entry(rdev, &mddev->disks, same_set) |
1da177e4c Linux-2.6.12-rc2 |
307 |
conf->rdev = rdev; |
1f403624b md: centralize ->... |
308 |
md_set_array_sectors(mddev, faulty_size(mddev, 0, 0)); |
1da177e4c Linux-2.6.12-rc2 |
309 |
mddev->private = conf; |
50ac168a6 md: merge reconfi... |
310 |
reshape(mddev); |
1da177e4c Linux-2.6.12-rc2 |
311 312 313 |
return 0; } |
fd01b88c7 md: remove typede... |
314 |
static int stop(struct mddev *mddev) |
1da177e4c Linux-2.6.12-rc2 |
315 |
{ |
8f1ae43dd md/faulty: remove... |
316 |
struct faulty_conf *conf = mddev->private; |
1da177e4c Linux-2.6.12-rc2 |
317 318 319 320 321 |
kfree(conf); mddev->private = NULL; return 0; } |
84fc4b56d md: rename "mdk_p... |
322 |
static struct md_personality faulty_personality = |
1da177e4c Linux-2.6.12-rc2 |
323 324 |
{ .name = "faulty", |
2604b703b [PATCH] md: remov... |
325 |
.level = LEVEL_FAULTY, |
1da177e4c Linux-2.6.12-rc2 |
326 327 328 329 330 |
.owner = THIS_MODULE, .make_request = make_request, .run = run, .stop = stop, .status = status, |
50ac168a6 md: merge reconfi... |
331 |
.check_reshape = reshape, |
80c3a6ce4 md: add 'size' as... |
332 |
.size = faulty_size, |
1da177e4c Linux-2.6.12-rc2 |
333 334 335 336 |
}; static int __init raid_init(void) { |
2604b703b [PATCH] md: remov... |
337 |
return register_md_personality(&faulty_personality); |
1da177e4c Linux-2.6.12-rc2 |
338 339 340 341 |
} static void raid_exit(void) { |
2604b703b [PATCH] md: remov... |
342 |
unregister_md_personality(&faulty_personality); |
1da177e4c Linux-2.6.12-rc2 |
343 344 345 346 347 |
} module_init(raid_init); module_exit(raid_exit); MODULE_LICENSE("GPL"); |
0efb9e619 md: add MODULE_DE... |
348 |
MODULE_DESCRIPTION("Fault injection personality for MD"); |
1da177e4c Linux-2.6.12-rc2 |
349 |
MODULE_ALIAS("md-personality-10"); /* faulty */ |
d9d166c2a [PATCH] md: allow... |
350 |
MODULE_ALIAS("md-faulty"); |
2604b703b [PATCH] md: remov... |
351 |
MODULE_ALIAS("md-level--5"); |