1af1a8899SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2935fe098SMike Snitzer /*
3935fe098SMike Snitzer * faulty.c : Multiple Devices driver for Linux
4935fe098SMike Snitzer *
5935fe098SMike Snitzer * Copyright (C) 2004 Neil Brown
6935fe098SMike Snitzer *
7935fe098SMike Snitzer * fautly-device-simulator personality for md
8935fe098SMike Snitzer */
9935fe098SMike Snitzer
10935fe098SMike Snitzer
11935fe098SMike Snitzer /*
12935fe098SMike Snitzer * The "faulty" personality causes some requests to fail.
13935fe098SMike Snitzer *
14935fe098SMike Snitzer * Possible failure modes are:
15935fe098SMike Snitzer * reads fail "randomly" but succeed on retry
16935fe098SMike Snitzer * writes fail "randomly" but succeed on retry
17935fe098SMike Snitzer * reads for some address fail and then persist until a write
18935fe098SMike Snitzer * reads for some address fail and then persist irrespective of write
19935fe098SMike Snitzer * writes for some address fail and persist
20935fe098SMike Snitzer * all writes fail
21935fe098SMike Snitzer *
22935fe098SMike Snitzer * Different modes can be active at a time, but only
23935fe098SMike Snitzer * one can be set at array creation. Others can be added later.
24935fe098SMike Snitzer * A mode can be one-shot or recurrent with the recurrence being
25935fe098SMike Snitzer * once in every N requests.
26935fe098SMike Snitzer * The bottom 5 bits of the "layout" indicate the mode. The
27935fe098SMike Snitzer * remainder indicate a period, or 0 for one-shot.
28935fe098SMike Snitzer *
29935fe098SMike Snitzer * There is an implementation limit on the number of concurrently
30935fe098SMike Snitzer * persisting-faulty blocks. When a new fault is requested that would
31935fe098SMike Snitzer * exceed the limit, it is ignored.
32935fe098SMike Snitzer * All current faults can be clear using a layout of "0".
33935fe098SMike Snitzer *
34935fe098SMike Snitzer * Requests are always sent to the device. If they are to fail,
35935fe098SMike Snitzer * we clone the bio and insert a new b_end_io into the chain.
36935fe098SMike Snitzer */
37935fe098SMike Snitzer
38935fe098SMike Snitzer #define WriteTransient 0
39935fe098SMike Snitzer #define ReadTransient 1
40935fe098SMike Snitzer #define WritePersistent 2
41935fe098SMike Snitzer #define ReadPersistent 3
42935fe098SMike Snitzer #define WriteAll 4 /* doesn't go to device */
43935fe098SMike Snitzer #define ReadFixable 5
44935fe098SMike Snitzer #define Modes 6
45935fe098SMike Snitzer
46935fe098SMike Snitzer #define ClearErrors 31
47935fe098SMike Snitzer #define ClearFaults 30
48935fe098SMike Snitzer
49935fe098SMike Snitzer #define AllPersist 100 /* internal use only */
50935fe098SMike Snitzer #define NoPersist 101
51935fe098SMike Snitzer
52935fe098SMike Snitzer #define ModeMask 0x1f
53935fe098SMike Snitzer #define ModeShift 5
54935fe098SMike Snitzer
55935fe098SMike Snitzer #define MaxFault 50
56935fe098SMike Snitzer #include <linux/blkdev.h>
57935fe098SMike Snitzer #include <linux/module.h>
58935fe098SMike Snitzer #include <linux/raid/md_u.h>
59935fe098SMike Snitzer #include <linux/slab.h>
60935fe098SMike Snitzer #include "md.h"
61935fe098SMike Snitzer #include <linux/seq_file.h>
62935fe098SMike Snitzer
63935fe098SMike Snitzer
faulty_fail(struct bio * bio)64935fe098SMike Snitzer static void faulty_fail(struct bio *bio)
65935fe098SMike Snitzer {
66935fe098SMike Snitzer struct bio *b = bio->bi_private;
67935fe098SMike Snitzer
68935fe098SMike Snitzer b->bi_iter.bi_size = bio->bi_iter.bi_size;
69935fe098SMike Snitzer b->bi_iter.bi_sector = bio->bi_iter.bi_sector;
70935fe098SMike Snitzer
71935fe098SMike Snitzer bio_put(bio);
72935fe098SMike Snitzer
73935fe098SMike Snitzer bio_io_error(b);
74935fe098SMike Snitzer }
75935fe098SMike Snitzer
76935fe098SMike Snitzer struct faulty_conf {
77935fe098SMike Snitzer int period[Modes];
78935fe098SMike Snitzer atomic_t counters[Modes];
79935fe098SMike Snitzer sector_t faults[MaxFault];
80935fe098SMike Snitzer int modes[MaxFault];
81935fe098SMike Snitzer int nfaults;
82935fe098SMike Snitzer struct md_rdev *rdev;
83935fe098SMike Snitzer };
84935fe098SMike Snitzer
check_mode(struct faulty_conf * conf,int mode)85935fe098SMike Snitzer static int check_mode(struct faulty_conf *conf, int mode)
86935fe098SMike Snitzer {
87935fe098SMike Snitzer if (conf->period[mode] == 0 &&
88935fe098SMike Snitzer atomic_read(&conf->counters[mode]) <= 0)
89935fe098SMike Snitzer return 0; /* no failure, no decrement */
90935fe098SMike Snitzer
91935fe098SMike Snitzer
92935fe098SMike Snitzer if (atomic_dec_and_test(&conf->counters[mode])) {
93935fe098SMike Snitzer if (conf->period[mode])
94935fe098SMike Snitzer atomic_set(&conf->counters[mode], conf->period[mode]);
95935fe098SMike Snitzer return 1;
96935fe098SMike Snitzer }
97935fe098SMike Snitzer return 0;
98935fe098SMike Snitzer }
99935fe098SMike Snitzer
check_sector(struct faulty_conf * conf,sector_t start,sector_t end,int dir)100935fe098SMike Snitzer static int check_sector(struct faulty_conf *conf, sector_t start, sector_t end, int dir)
101935fe098SMike Snitzer {
102935fe098SMike Snitzer /* If we find a ReadFixable sector, we fix it ... */
103935fe098SMike Snitzer int i;
104935fe098SMike Snitzer for (i=0; i<conf->nfaults; i++)
105935fe098SMike Snitzer if (conf->faults[i] >= start &&
106935fe098SMike Snitzer conf->faults[i] < end) {
107935fe098SMike Snitzer /* found it ... */
108935fe098SMike Snitzer switch (conf->modes[i] * 2 + dir) {
109935fe098SMike Snitzer case WritePersistent*2+WRITE: return 1;
110935fe098SMike Snitzer case ReadPersistent*2+READ: return 1;
111935fe098SMike Snitzer case ReadFixable*2+READ: return 1;
112935fe098SMike Snitzer case ReadFixable*2+WRITE:
113935fe098SMike Snitzer conf->modes[i] = NoPersist;
114935fe098SMike Snitzer return 0;
115935fe098SMike Snitzer case AllPersist*2+READ:
116935fe098SMike Snitzer case AllPersist*2+WRITE: return 1;
117935fe098SMike Snitzer default:
118935fe098SMike Snitzer return 0;
119935fe098SMike Snitzer }
120935fe098SMike Snitzer }
121935fe098SMike Snitzer return 0;
122935fe098SMike Snitzer }
123935fe098SMike Snitzer
add_sector(struct faulty_conf * conf,sector_t start,int mode)124935fe098SMike Snitzer static void add_sector(struct faulty_conf *conf, sector_t start, int mode)
125935fe098SMike Snitzer {
126935fe098SMike Snitzer int i;
127935fe098SMike Snitzer int n = conf->nfaults;
128935fe098SMike Snitzer for (i=0; i<conf->nfaults; i++)
129935fe098SMike Snitzer if (conf->faults[i] == start) {
130935fe098SMike Snitzer switch(mode) {
131935fe098SMike Snitzer case NoPersist: conf->modes[i] = mode; return;
132935fe098SMike Snitzer case WritePersistent:
133935fe098SMike Snitzer if (conf->modes[i] == ReadPersistent ||
134935fe098SMike Snitzer conf->modes[i] == ReadFixable)
135935fe098SMike Snitzer conf->modes[i] = AllPersist;
136935fe098SMike Snitzer else
137935fe098SMike Snitzer conf->modes[i] = WritePersistent;
138935fe098SMike Snitzer return;
139935fe098SMike Snitzer case ReadPersistent:
140935fe098SMike Snitzer if (conf->modes[i] == WritePersistent)
141935fe098SMike Snitzer conf->modes[i] = AllPersist;
142935fe098SMike Snitzer else
143935fe098SMike Snitzer conf->modes[i] = ReadPersistent;
144935fe098SMike Snitzer return;
145935fe098SMike Snitzer case ReadFixable:
146935fe098SMike Snitzer if (conf->modes[i] == WritePersistent ||
147935fe098SMike Snitzer conf->modes[i] == ReadPersistent)
148935fe098SMike Snitzer conf->modes[i] = AllPersist;
149935fe098SMike Snitzer else
150935fe098SMike Snitzer conf->modes[i] = ReadFixable;
151935fe098SMike Snitzer return;
152935fe098SMike Snitzer }
153935fe098SMike Snitzer } else if (conf->modes[i] == NoPersist)
154935fe098SMike Snitzer n = i;
155935fe098SMike Snitzer
156935fe098SMike Snitzer if (n >= MaxFault)
157935fe098SMike Snitzer return;
158935fe098SMike Snitzer conf->faults[n] = start;
159935fe098SMike Snitzer conf->modes[n] = mode;
160935fe098SMike Snitzer if (conf->nfaults == n)
161935fe098SMike Snitzer conf->nfaults = n+1;
162935fe098SMike Snitzer }
163935fe098SMike Snitzer
faulty_make_request(struct mddev * mddev,struct bio * bio)164935fe098SMike Snitzer static bool faulty_make_request(struct mddev *mddev, struct bio *bio)
165935fe098SMike Snitzer {
166935fe098SMike Snitzer struct faulty_conf *conf = mddev->private;
167935fe098SMike Snitzer int failit = 0;
168935fe098SMike Snitzer
169935fe098SMike Snitzer if (bio_data_dir(bio) == WRITE) {
170935fe098SMike Snitzer /* write request */
171935fe098SMike Snitzer if (atomic_read(&conf->counters[WriteAll])) {
172ed00aabdSChristoph Hellwig /* special case - don't decrement, don't submit_bio_noacct,
173935fe098SMike Snitzer * just fail immediately
174935fe098SMike Snitzer */
175935fe098SMike Snitzer bio_io_error(bio);
176935fe098SMike Snitzer return true;
177935fe098SMike Snitzer }
178935fe098SMike Snitzer
179935fe098SMike Snitzer if (check_sector(conf, bio->bi_iter.bi_sector,
180935fe098SMike Snitzer bio_end_sector(bio), WRITE))
181935fe098SMike Snitzer failit = 1;
182935fe098SMike Snitzer if (check_mode(conf, WritePersistent)) {
183935fe098SMike Snitzer add_sector(conf, bio->bi_iter.bi_sector,
184935fe098SMike Snitzer WritePersistent);
185935fe098SMike Snitzer failit = 1;
186935fe098SMike Snitzer }
187935fe098SMike Snitzer if (check_mode(conf, WriteTransient))
188935fe098SMike Snitzer failit = 1;
189935fe098SMike Snitzer } else {
190935fe098SMike Snitzer /* read request */
191935fe098SMike Snitzer if (check_sector(conf, bio->bi_iter.bi_sector,
192935fe098SMike Snitzer bio_end_sector(bio), READ))
193935fe098SMike Snitzer failit = 1;
194935fe098SMike Snitzer if (check_mode(conf, ReadTransient))
195935fe098SMike Snitzer failit = 1;
196935fe098SMike Snitzer if (check_mode(conf, ReadPersistent)) {
197935fe098SMike Snitzer add_sector(conf, bio->bi_iter.bi_sector,
198935fe098SMike Snitzer ReadPersistent);
199935fe098SMike Snitzer failit = 1;
200935fe098SMike Snitzer }
201935fe098SMike Snitzer if (check_mode(conf, ReadFixable)) {
202935fe098SMike Snitzer add_sector(conf, bio->bi_iter.bi_sector,
203935fe098SMike Snitzer ReadFixable);
204935fe098SMike Snitzer failit = 1;
205935fe098SMike Snitzer }
206935fe098SMike Snitzer }
207*dd9a6860SYu Kuai
208*dd9a6860SYu Kuai md_account_bio(mddev, &bio);
209935fe098SMike Snitzer if (failit) {
210abfc426dSChristoph Hellwig struct bio *b = bio_alloc_clone(conf->rdev->bdev, bio, GFP_NOIO,
211abfc426dSChristoph Hellwig &mddev->bio_set);
212935fe098SMike Snitzer
213935fe098SMike Snitzer b->bi_private = bio;
214935fe098SMike Snitzer b->bi_end_io = faulty_fail;
215935fe098SMike Snitzer bio = b;
216935fe098SMike Snitzer } else
217935fe098SMike Snitzer bio_set_dev(bio, conf->rdev->bdev);
218935fe098SMike Snitzer
219ed00aabdSChristoph Hellwig submit_bio_noacct(bio);
220935fe098SMike Snitzer return true;
221935fe098SMike Snitzer }
222935fe098SMike Snitzer
faulty_status(struct seq_file * seq,struct mddev * mddev)223935fe098SMike Snitzer static void faulty_status(struct seq_file *seq, struct mddev *mddev)
224935fe098SMike Snitzer {
225935fe098SMike Snitzer struct faulty_conf *conf = mddev->private;
226935fe098SMike Snitzer int n;
227935fe098SMike Snitzer
228935fe098SMike Snitzer if ((n=atomic_read(&conf->counters[WriteTransient])) != 0)
229935fe098SMike Snitzer seq_printf(seq, " WriteTransient=%d(%d)",
230935fe098SMike Snitzer n, conf->period[WriteTransient]);
231935fe098SMike Snitzer
232935fe098SMike Snitzer if ((n=atomic_read(&conf->counters[ReadTransient])) != 0)
233935fe098SMike Snitzer seq_printf(seq, " ReadTransient=%d(%d)",
234935fe098SMike Snitzer n, conf->period[ReadTransient]);
235935fe098SMike Snitzer
236935fe098SMike Snitzer if ((n=atomic_read(&conf->counters[WritePersistent])) != 0)
237935fe098SMike Snitzer seq_printf(seq, " WritePersistent=%d(%d)",
238935fe098SMike Snitzer n, conf->period[WritePersistent]);
239935fe098SMike Snitzer
240935fe098SMike Snitzer if ((n=atomic_read(&conf->counters[ReadPersistent])) != 0)
241935fe098SMike Snitzer seq_printf(seq, " ReadPersistent=%d(%d)",
242935fe098SMike Snitzer n, conf->period[ReadPersistent]);
243935fe098SMike Snitzer
244935fe098SMike Snitzer
245935fe098SMike Snitzer if ((n=atomic_read(&conf->counters[ReadFixable])) != 0)
246935fe098SMike Snitzer seq_printf(seq, " ReadFixable=%d(%d)",
247935fe098SMike Snitzer n, conf->period[ReadFixable]);
248935fe098SMike Snitzer
249935fe098SMike Snitzer if ((n=atomic_read(&conf->counters[WriteAll])) != 0)
250935fe098SMike Snitzer seq_printf(seq, " WriteAll");
251935fe098SMike Snitzer
252935fe098SMike Snitzer seq_printf(seq, " nfaults=%d", conf->nfaults);
253935fe098SMike Snitzer }
254935fe098SMike Snitzer
255935fe098SMike Snitzer
faulty_reshape(struct mddev * mddev)256935fe098SMike Snitzer static int faulty_reshape(struct mddev *mddev)
257935fe098SMike Snitzer {
258935fe098SMike Snitzer int mode = mddev->new_layout & ModeMask;
259935fe098SMike Snitzer int count = mddev->new_layout >> ModeShift;
260935fe098SMike Snitzer struct faulty_conf *conf = mddev->private;
261935fe098SMike Snitzer
262935fe098SMike Snitzer if (mddev->new_layout < 0)
263935fe098SMike Snitzer return 0;
264935fe098SMike Snitzer
265935fe098SMike Snitzer /* new layout */
266935fe098SMike Snitzer if (mode == ClearFaults)
267935fe098SMike Snitzer conf->nfaults = 0;
268935fe098SMike Snitzer else if (mode == ClearErrors) {
269935fe098SMike Snitzer int i;
270935fe098SMike Snitzer for (i=0 ; i < Modes ; i++) {
271935fe098SMike Snitzer conf->period[i] = 0;
272935fe098SMike Snitzer atomic_set(&conf->counters[i], 0);
273935fe098SMike Snitzer }
274935fe098SMike Snitzer } else if (mode < Modes) {
275935fe098SMike Snitzer conf->period[mode] = count;
276935fe098SMike Snitzer if (!count) count++;
277935fe098SMike Snitzer atomic_set(&conf->counters[mode], count);
278935fe098SMike Snitzer } else
279935fe098SMike Snitzer return -EINVAL;
280935fe098SMike Snitzer mddev->new_layout = -1;
281935fe098SMike Snitzer mddev->layout = -1; /* makes sure further changes come through */
282935fe098SMike Snitzer return 0;
283935fe098SMike Snitzer }
284935fe098SMike Snitzer
faulty_size(struct mddev * mddev,sector_t sectors,int raid_disks)285935fe098SMike Snitzer static sector_t faulty_size(struct mddev *mddev, sector_t sectors, int raid_disks)
286935fe098SMike Snitzer {
287935fe098SMike Snitzer WARN_ONCE(raid_disks,
288935fe098SMike Snitzer "%s does not support generic reshape\n", __func__);
289935fe098SMike Snitzer
290935fe098SMike Snitzer if (sectors == 0)
291935fe098SMike Snitzer return mddev->dev_sectors;
292935fe098SMike Snitzer
293935fe098SMike Snitzer return sectors;
294935fe098SMike Snitzer }
295935fe098SMike Snitzer
faulty_run(struct mddev * mddev)296935fe098SMike Snitzer static int faulty_run(struct mddev *mddev)
297935fe098SMike Snitzer {
298935fe098SMike Snitzer struct md_rdev *rdev;
299935fe098SMike Snitzer int i;
300935fe098SMike Snitzer struct faulty_conf *conf;
301935fe098SMike Snitzer
302935fe098SMike Snitzer if (md_check_no_bitmap(mddev))
303935fe098SMike Snitzer return -EINVAL;
304935fe098SMike Snitzer
305935fe098SMike Snitzer conf = kmalloc(sizeof(*conf), GFP_KERNEL);
306935fe098SMike Snitzer if (!conf)
307935fe098SMike Snitzer return -ENOMEM;
308935fe098SMike Snitzer
309935fe098SMike Snitzer for (i=0; i<Modes; i++) {
310935fe098SMike Snitzer atomic_set(&conf->counters[i], 0);
311935fe098SMike Snitzer conf->period[i] = 0;
312935fe098SMike Snitzer }
313935fe098SMike Snitzer conf->nfaults = 0;
314935fe098SMike Snitzer
315935fe098SMike Snitzer rdev_for_each(rdev, mddev) {
316935fe098SMike Snitzer conf->rdev = rdev;
317935fe098SMike Snitzer disk_stack_limits(mddev->gendisk, rdev->bdev,
318935fe098SMike Snitzer rdev->data_offset << 9);
319935fe098SMike Snitzer }
320935fe098SMike Snitzer
321935fe098SMike Snitzer md_set_array_sectors(mddev, faulty_size(mddev, 0, 0));
322935fe098SMike Snitzer mddev->private = conf;
323935fe098SMike Snitzer
324935fe098SMike Snitzer faulty_reshape(mddev);
325935fe098SMike Snitzer
326935fe098SMike Snitzer return 0;
327935fe098SMike Snitzer }
328935fe098SMike Snitzer
faulty_free(struct mddev * mddev,void * priv)329935fe098SMike Snitzer static void faulty_free(struct mddev *mddev, void *priv)
330935fe098SMike Snitzer {
331935fe098SMike Snitzer struct faulty_conf *conf = priv;
332935fe098SMike Snitzer
333935fe098SMike Snitzer kfree(conf);
334935fe098SMike Snitzer }
335935fe098SMike Snitzer
336935fe098SMike Snitzer static struct md_personality faulty_personality =
337935fe098SMike Snitzer {
338935fe098SMike Snitzer .name = "faulty",
339935fe098SMike Snitzer .level = LEVEL_FAULTY,
340935fe098SMike Snitzer .owner = THIS_MODULE,
341935fe098SMike Snitzer .make_request = faulty_make_request,
342935fe098SMike Snitzer .run = faulty_run,
343935fe098SMike Snitzer .free = faulty_free,
344935fe098SMike Snitzer .status = faulty_status,
345935fe098SMike Snitzer .check_reshape = faulty_reshape,
346935fe098SMike Snitzer .size = faulty_size,
347935fe098SMike Snitzer };
348935fe098SMike Snitzer
raid_init(void)349935fe098SMike Snitzer static int __init raid_init(void)
350935fe098SMike Snitzer {
351935fe098SMike Snitzer return register_md_personality(&faulty_personality);
352935fe098SMike Snitzer }
353935fe098SMike Snitzer
raid_exit(void)354935fe098SMike Snitzer static void raid_exit(void)
355935fe098SMike Snitzer {
356935fe098SMike Snitzer unregister_md_personality(&faulty_personality);
357935fe098SMike Snitzer }
358935fe098SMike Snitzer
359935fe098SMike Snitzer module_init(raid_init);
360935fe098SMike Snitzer module_exit(raid_exit);
361935fe098SMike Snitzer MODULE_LICENSE("GPL");
362608f52e3SGuoqing Jiang MODULE_DESCRIPTION("Fault injection personality for MD (deprecated)");
363935fe098SMike Snitzer MODULE_ALIAS("md-personality-10"); /* faulty */
364935fe098SMike Snitzer MODULE_ALIAS("md-faulty");
365935fe098SMike Snitzer MODULE_ALIAS("md-level--5");
366