xref: /openbmc/linux/drivers/md/md-faulty.c (revision ed00aabd5eb9fb44d6aff1173234a2e911b9fead)
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 
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 
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 
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 
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 
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])) {
172*ed00aabdSChristoph 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 	}
207935fe098SMike Snitzer 	if (failit) {
208afeee514SKent Overstreet 		struct bio *b = bio_clone_fast(bio, GFP_NOIO, &mddev->bio_set);
209935fe098SMike Snitzer 
210935fe098SMike Snitzer 		bio_set_dev(b, conf->rdev->bdev);
211935fe098SMike Snitzer 		b->bi_private = bio;
212935fe098SMike Snitzer 		b->bi_end_io = faulty_fail;
213935fe098SMike Snitzer 		bio = b;
214935fe098SMike Snitzer 	} else
215935fe098SMike Snitzer 		bio_set_dev(bio, conf->rdev->bdev);
216935fe098SMike Snitzer 
217*ed00aabdSChristoph Hellwig 	submit_bio_noacct(bio);
218935fe098SMike Snitzer 	return true;
219935fe098SMike Snitzer }
220935fe098SMike Snitzer 
221935fe098SMike Snitzer static void faulty_status(struct seq_file *seq, struct mddev *mddev)
222935fe098SMike Snitzer {
223935fe098SMike Snitzer 	struct faulty_conf *conf = mddev->private;
224935fe098SMike Snitzer 	int n;
225935fe098SMike Snitzer 
226935fe098SMike Snitzer 	if ((n=atomic_read(&conf->counters[WriteTransient])) != 0)
227935fe098SMike Snitzer 		seq_printf(seq, " WriteTransient=%d(%d)",
228935fe098SMike Snitzer 			   n, conf->period[WriteTransient]);
229935fe098SMike Snitzer 
230935fe098SMike Snitzer 	if ((n=atomic_read(&conf->counters[ReadTransient])) != 0)
231935fe098SMike Snitzer 		seq_printf(seq, " ReadTransient=%d(%d)",
232935fe098SMike Snitzer 			   n, conf->period[ReadTransient]);
233935fe098SMike Snitzer 
234935fe098SMike Snitzer 	if ((n=atomic_read(&conf->counters[WritePersistent])) != 0)
235935fe098SMike Snitzer 		seq_printf(seq, " WritePersistent=%d(%d)",
236935fe098SMike Snitzer 			   n, conf->period[WritePersistent]);
237935fe098SMike Snitzer 
238935fe098SMike Snitzer 	if ((n=atomic_read(&conf->counters[ReadPersistent])) != 0)
239935fe098SMike Snitzer 		seq_printf(seq, " ReadPersistent=%d(%d)",
240935fe098SMike Snitzer 			   n, conf->period[ReadPersistent]);
241935fe098SMike Snitzer 
242935fe098SMike Snitzer 
243935fe098SMike Snitzer 	if ((n=atomic_read(&conf->counters[ReadFixable])) != 0)
244935fe098SMike Snitzer 		seq_printf(seq, " ReadFixable=%d(%d)",
245935fe098SMike Snitzer 			   n, conf->period[ReadFixable]);
246935fe098SMike Snitzer 
247935fe098SMike Snitzer 	if ((n=atomic_read(&conf->counters[WriteAll])) != 0)
248935fe098SMike Snitzer 		seq_printf(seq, " WriteAll");
249935fe098SMike Snitzer 
250935fe098SMike Snitzer 	seq_printf(seq, " nfaults=%d", conf->nfaults);
251935fe098SMike Snitzer }
252935fe098SMike Snitzer 
253935fe098SMike Snitzer 
254935fe098SMike Snitzer static int faulty_reshape(struct mddev *mddev)
255935fe098SMike Snitzer {
256935fe098SMike Snitzer 	int mode = mddev->new_layout & ModeMask;
257935fe098SMike Snitzer 	int count = mddev->new_layout >> ModeShift;
258935fe098SMike Snitzer 	struct faulty_conf *conf = mddev->private;
259935fe098SMike Snitzer 
260935fe098SMike Snitzer 	if (mddev->new_layout < 0)
261935fe098SMike Snitzer 		return 0;
262935fe098SMike Snitzer 
263935fe098SMike Snitzer 	/* new layout */
264935fe098SMike Snitzer 	if (mode == ClearFaults)
265935fe098SMike Snitzer 		conf->nfaults = 0;
266935fe098SMike Snitzer 	else if (mode == ClearErrors) {
267935fe098SMike Snitzer 		int i;
268935fe098SMike Snitzer 		for (i=0 ; i < Modes ; i++) {
269935fe098SMike Snitzer 			conf->period[i] = 0;
270935fe098SMike Snitzer 			atomic_set(&conf->counters[i], 0);
271935fe098SMike Snitzer 		}
272935fe098SMike Snitzer 	} else if (mode < Modes) {
273935fe098SMike Snitzer 		conf->period[mode] = count;
274935fe098SMike Snitzer 		if (!count) count++;
275935fe098SMike Snitzer 		atomic_set(&conf->counters[mode], count);
276935fe098SMike Snitzer 	} else
277935fe098SMike Snitzer 		return -EINVAL;
278935fe098SMike Snitzer 	mddev->new_layout = -1;
279935fe098SMike Snitzer 	mddev->layout = -1; /* makes sure further changes come through */
280935fe098SMike Snitzer 	return 0;
281935fe098SMike Snitzer }
282935fe098SMike Snitzer 
283935fe098SMike Snitzer static sector_t faulty_size(struct mddev *mddev, sector_t sectors, int raid_disks)
284935fe098SMike Snitzer {
285935fe098SMike Snitzer 	WARN_ONCE(raid_disks,
286935fe098SMike Snitzer 		  "%s does not support generic reshape\n", __func__);
287935fe098SMike Snitzer 
288935fe098SMike Snitzer 	if (sectors == 0)
289935fe098SMike Snitzer 		return mddev->dev_sectors;
290935fe098SMike Snitzer 
291935fe098SMike Snitzer 	return sectors;
292935fe098SMike Snitzer }
293935fe098SMike Snitzer 
294935fe098SMike Snitzer static int faulty_run(struct mddev *mddev)
295935fe098SMike Snitzer {
296935fe098SMike Snitzer 	struct md_rdev *rdev;
297935fe098SMike Snitzer 	int i;
298935fe098SMike Snitzer 	struct faulty_conf *conf;
299935fe098SMike Snitzer 
300935fe098SMike Snitzer 	if (md_check_no_bitmap(mddev))
301935fe098SMike Snitzer 		return -EINVAL;
302935fe098SMike Snitzer 
303935fe098SMike Snitzer 	conf = kmalloc(sizeof(*conf), GFP_KERNEL);
304935fe098SMike Snitzer 	if (!conf)
305935fe098SMike Snitzer 		return -ENOMEM;
306935fe098SMike Snitzer 
307935fe098SMike Snitzer 	for (i=0; i<Modes; i++) {
308935fe098SMike Snitzer 		atomic_set(&conf->counters[i], 0);
309935fe098SMike Snitzer 		conf->period[i] = 0;
310935fe098SMike Snitzer 	}
311935fe098SMike Snitzer 	conf->nfaults = 0;
312935fe098SMike Snitzer 
313935fe098SMike Snitzer 	rdev_for_each(rdev, mddev) {
314935fe098SMike Snitzer 		conf->rdev = rdev;
315935fe098SMike Snitzer 		disk_stack_limits(mddev->gendisk, rdev->bdev,
316935fe098SMike Snitzer 				  rdev->data_offset << 9);
317935fe098SMike Snitzer 	}
318935fe098SMike Snitzer 
319935fe098SMike Snitzer 	md_set_array_sectors(mddev, faulty_size(mddev, 0, 0));
320935fe098SMike Snitzer 	mddev->private = conf;
321935fe098SMike Snitzer 
322935fe098SMike Snitzer 	faulty_reshape(mddev);
323935fe098SMike Snitzer 
324935fe098SMike Snitzer 	return 0;
325935fe098SMike Snitzer }
326935fe098SMike Snitzer 
327935fe098SMike Snitzer static void faulty_free(struct mddev *mddev, void *priv)
328935fe098SMike Snitzer {
329935fe098SMike Snitzer 	struct faulty_conf *conf = priv;
330935fe098SMike Snitzer 
331935fe098SMike Snitzer 	kfree(conf);
332935fe098SMike Snitzer }
333935fe098SMike Snitzer 
334935fe098SMike Snitzer static struct md_personality faulty_personality =
335935fe098SMike Snitzer {
336935fe098SMike Snitzer 	.name		= "faulty",
337935fe098SMike Snitzer 	.level		= LEVEL_FAULTY,
338935fe098SMike Snitzer 	.owner		= THIS_MODULE,
339935fe098SMike Snitzer 	.make_request	= faulty_make_request,
340935fe098SMike Snitzer 	.run		= faulty_run,
341935fe098SMike Snitzer 	.free		= faulty_free,
342935fe098SMike Snitzer 	.status		= faulty_status,
343935fe098SMike Snitzer 	.check_reshape	= faulty_reshape,
344935fe098SMike Snitzer 	.size		= faulty_size,
345935fe098SMike Snitzer };
346935fe098SMike Snitzer 
347935fe098SMike Snitzer static int __init raid_init(void)
348935fe098SMike Snitzer {
349935fe098SMike Snitzer 	return register_md_personality(&faulty_personality);
350935fe098SMike Snitzer }
351935fe098SMike Snitzer 
352935fe098SMike Snitzer static void raid_exit(void)
353935fe098SMike Snitzer {
354935fe098SMike Snitzer 	unregister_md_personality(&faulty_personality);
355935fe098SMike Snitzer }
356935fe098SMike Snitzer 
357935fe098SMike Snitzer module_init(raid_init);
358935fe098SMike Snitzer module_exit(raid_exit);
359935fe098SMike Snitzer MODULE_LICENSE("GPL");
360935fe098SMike Snitzer MODULE_DESCRIPTION("Fault injection personality for MD");
361935fe098SMike Snitzer MODULE_ALIAS("md-personality-10"); /* faulty */
362935fe098SMike Snitzer MODULE_ALIAS("md-faulty");
363935fe098SMike Snitzer MODULE_ALIAS("md-level--5");
364