Blame view

drivers/md/faulty.c 8.81 KB
1da177e4c   Linus Torvalds   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   Lucas De Marchi   Fix common misspe...
33
   * A mode can be one-shot or recurrent with the recurrence being
1da177e4c   Linus Torvalds   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   NeilBrown   md: move lots of ...
65
  #include <linux/blkdev.h>
056075c76   Paul Gortmaker   md: Add module.h ...
66
  #include <linux/module.h>
bff61975b   NeilBrown   md: move lots of ...
67
  #include <linux/raid/md_u.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
68
  #include <linux/slab.h>
43b2e5d86   NeilBrown   md: move md_k.h f...
69
  #include "md.h"
bff61975b   NeilBrown   md: move lots of ...
70
  #include <linux/seq_file.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71

6712ecf8f   NeilBrown   Drop 'size' argum...
72
  static void faulty_fail(struct bio *bio, int error)
1da177e4c   Linus Torvalds   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   NeilBrown   Drop 'size' argum...
78
  	bio_put(bio);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79

6712ecf8f   NeilBrown   Drop 'size' argum...
80
  	bio_io_error(b);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
  }
8f1ae43dd   NeilBrown   md/faulty: remove...
82
  struct faulty_conf {
1da177e4c   Linus Torvalds   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   NeilBrown   md: removing type...
88
  	struct md_rdev *rdev;
8f1ae43dd   NeilBrown   md/faulty: remove...
89
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90

8f1ae43dd   NeilBrown   md/faulty: remove...
91
  static int check_mode(struct faulty_conf *conf, int mode)
1da177e4c   Linus Torvalds   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   NeilBrown   md/faulty: remove...
105
  static int check_sector(struct faulty_conf *conf, sector_t start, sector_t end, int dir)
1da177e4c   Linus Torvalds   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   NeilBrown   md/faulty: remove...
128
  static void add_sector(struct faulty_conf *conf, sector_t start, int mode)
1da177e4c   Linus Torvalds   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   Linus Torvalds   Merge branch 'for...
167
  static void make_request(struct mddev *mddev, struct bio *bio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  {
8f1ae43dd   NeilBrown   md/faulty: remove...
169
  	struct faulty_conf *conf = mddev->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
  	int failit = 0;
802ba064c   NeilBrown   [PATCH] md: Don't...
171
  	if (bio_data_dir(bio) == WRITE) {
1da177e4c   Linus Torvalds   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   NeilBrown   Drop 'size' argum...
177
  			bio_endio(bio, -EIO);
5a7bbad27   Christoph Hellwig   block: remove sup...
178
  			return;
1da177e4c   Linus Torvalds   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   NeilBrown   md: use separate ...
207
  		struct bio *b = bio_clone_mddev(bio, GFP_NOIO, mddev);
5a7bbad27   Christoph Hellwig   block: remove sup...
208

1da177e4c   Linus Torvalds   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   Christoph Hellwig   block: remove sup...
212
213
  		bio = b;
  	} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
  		bio->bi_bdev = conf->rdev->bdev;
5a7bbad27   Christoph Hellwig   block: remove sup...
215
216
  
  	generic_make_request(bio);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  }
fd01b88c7   NeilBrown   md: remove typede...
218
  static void status(struct seq_file *seq, struct mddev *mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
  {
8f1ae43dd   NeilBrown   md/faulty: remove...
220
  	struct faulty_conf *conf = mddev->private;
1da177e4c   Linus Torvalds   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   NeilBrown   md: remove typede...
249
  static int reshape(struct mddev *mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
  {
597a711b6   NeilBrown   md: remove unnece...
251
252
  	int mode = mddev->new_layout & ModeMask;
  	int count = mddev->new_layout >> ModeShift;
8f1ae43dd   NeilBrown   md/faulty: remove...
253
  	struct faulty_conf *conf = mddev->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254

597a711b6   NeilBrown   md: remove unnece...
255
256
  	if (mddev->new_layout < 0)
  		return 0;
1da177e4c   Linus Torvalds   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   NeilBrown   md: remove unnece...
273
  	mddev->new_layout = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
276
  	mddev->layout = -1; /* makes sure further changes come through */
  	return 0;
  }
fd01b88c7   NeilBrown   md: remove typede...
277
  static sector_t faulty_size(struct mddev *mddev, sector_t sectors, int raid_disks)
80c3a6ce4   Dan Williams   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   NeilBrown   md: remove typede...
288
  static int run(struct mddev *mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
  {
3cb030020   NeilBrown   md: removing type...
290
  	struct md_rdev *rdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
  	int i;
8f1ae43dd   NeilBrown   md/faulty: remove...
292
  	struct faulty_conf *conf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293

0894cc306   Andre Noll   md: Move check fo...
294
295
296
297
  	if (md_check_no_bitmap(mddev))
  		return -EINVAL;
  
  	conf = kmalloc(sizeof(*conf), GFP_KERNEL);
08ff39f1c   Sven Wegener   md: check for mem...
298
299
  	if (!conf)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   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   Cheng Renquan   md: use list_for_...
306
  	list_for_each_entry(rdev, &mddev->disks, same_set)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
  		conf->rdev = rdev;
1f403624b   Dan Williams   md: centralize ->...
308
  	md_set_array_sectors(mddev, faulty_size(mddev, 0, 0));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
  	mddev->private = conf;
50ac168a6   NeilBrown   md: merge reconfi...
310
  	reshape(mddev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
313
  
  	return 0;
  }
fd01b88c7   NeilBrown   md: remove typede...
314
  static int stop(struct mddev *mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
  {
8f1ae43dd   NeilBrown   md/faulty: remove...
316
  	struct faulty_conf *conf = mddev->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
318
319
320
321
  
  	kfree(conf);
  	mddev->private = NULL;
  	return 0;
  }
84fc4b56d   NeilBrown   md: rename "mdk_p...
322
  static struct md_personality faulty_personality =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
  {
  	.name		= "faulty",
2604b703b   NeilBrown   [PATCH] md: remov...
325
  	.level		= LEVEL_FAULTY,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
329
330
  	.owner		= THIS_MODULE,
  	.make_request	= make_request,
  	.run		= run,
  	.stop		= stop,
  	.status		= status,
50ac168a6   NeilBrown   md: merge reconfi...
331
  	.check_reshape	= reshape,
80c3a6ce4   Dan Williams   md: add 'size' as...
332
  	.size		= faulty_size,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
335
336
  };
  
  static int __init raid_init(void)
  {
2604b703b   NeilBrown   [PATCH] md: remov...
337
  	return register_md_personality(&faulty_personality);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
339
340
341
  }
  
  static void raid_exit(void)
  {
2604b703b   NeilBrown   [PATCH] md: remov...
342
  	unregister_md_personality(&faulty_personality);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
344
345
346
347
  }
  
  module_init(raid_init);
  module_exit(raid_exit);
  MODULE_LICENSE("GPL");
0efb9e619   NeilBrown   md: add MODULE_DE...
348
  MODULE_DESCRIPTION("Fault injection personality for MD");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
  MODULE_ALIAS("md-personality-10"); /* faulty */
d9d166c2a   NeilBrown   [PATCH] md: allow...
350
  MODULE_ALIAS("md-faulty");
2604b703b   NeilBrown   [PATCH] md: remov...
351
  MODULE_ALIAS("md-level--5");