Root/drivers/md/faulty.c

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

Archive Download this file



interactive