Blame view

drivers/md/md.c 214 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
  /*
     md.c : Multiple Devices driver for Linux
  	  Copyright (C) 1998, 1999, 2000 Ingo Molnar
  
       completely rewritten, based on the MD driver code from Marc Zyngier
  
     Changes:
  
     - RAID-1/RAID-5 extensions by Miguel de Icaza, Gadi Oxman, Ingo Molnar
     - RAID-6 extensions by H. Peter Anvin <hpa@zytor.com>
     - boot support for linear and striped mode by Harald Hoyer <HarryH@Royal.Net>
     - kerneld support by Boris Tobotras <boris@xtalk.msk.su>
     - kmod support by: Cyrus Durgin
     - RAID0 bugfixes: Mark Anthony Lisher <markal@iname.com>
     - Devfs support by Richard Gooch <rgooch@atnf.csiro.au>
  
     - lots of fixes and improvements to the RAID1/RAID5 and generic
       RAID code (such as request based resynchronization):
  
       Neil Brown <neilb@cse.unsw.edu.au>.
32a7627cf   NeilBrown   [PATCH] md: optim...
21
22
     - persistent bitmap code
       Copyright (C) 2003-2004, Paul Clements, SteelEye Technology, Inc.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
28
29
30
31
     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.
  */
a6fb0934f   NeilBrown   [PATCH] md: use k...
32
  #include <linux/kthread.h>
bff61975b   NeilBrown   md: move lots of ...
33
  #include <linux/blkdev.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  #include <linux/sysctl.h>
bff61975b   NeilBrown   md: move lots of ...
35
  #include <linux/seq_file.h>
2a48fc0ab   Arnd Bergmann   block: autoconver...
36
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  #include <linux/buffer_head.h> /* for invalidate_bdev */
d7603b7e3   NeilBrown   [PATCH] md: make ...
38
  #include <linux/poll.h>
16f17b39f   NeilBrown   [PATCH] md: incre...
39
  #include <linux/ctype.h>
e7d2860b6   AndrĂ© Goddard Rosa   tree-wide: conver...
40
  #include <linux/string.h>
fb4d8c76e   NeilBrown   md: Remove unnece...
41
42
43
  #include <linux/hdreg.h>
  #include <linux/proc_fs.h>
  #include <linux/random.h>
056075c76   Paul Gortmaker   md: Add module.h ...
44
  #include <linux/module.h>
fb4d8c76e   NeilBrown   md: Remove unnece...
45
  #include <linux/reboot.h>
32a7627cf   NeilBrown   [PATCH] md: optim...
46
  #include <linux/file.h>
aa98aa319   Arnd Bergmann   md: move compat_i...
47
  #include <linux/compat.h>
255707274   Stephen Rothwell   md: build failure...
48
  #include <linux/delay.h>
bff61975b   NeilBrown   md: move lots of ...
49
50
  #include <linux/raid/md_p.h>
  #include <linux/raid/md_u.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
51
  #include <linux/slab.h>
43b2e5d86   NeilBrown   md: move md_k.h f...
52
  #include "md.h"
ef740c372   Christoph Hellwig   md: move headers ...
53
  #include "bitmap.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  #ifndef MODULE
d710e1381   NeilBrown   md: remove space ...
56
  static void autostart_arrays(int part);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
  #endif
01f96c0a9   NeilBrown   md: Avoid waking ...
58
59
60
61
62
  /* pers_list is a list of registered personalities protected
   * by pers_lock.
   * pers_lock does extra service to protect accesses to
   * mddev->thread when the mutex cannot be held.
   */
2604b703b   NeilBrown   [PATCH] md: remov...
63
  static LIST_HEAD(pers_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  static DEFINE_SPINLOCK(pers_lock);
5e56341d0   Adrian Bunk   [PATCH] md: make ...
65
  static void md_print_devices(void);
90b08710e   Bernd Schubert   md: allow paralle...
66
  static DECLARE_WAIT_QUEUE_HEAD(resync_wait);
e804ac780   Tejun Heo   md: fix and updat...
67
68
  static struct workqueue_struct *md_wq;
  static struct workqueue_struct *md_misc_wq;
90b08710e   Bernd Schubert   md: allow paralle...
69

5e56341d0   Adrian Bunk   [PATCH] md: make ...
70
71
  #define MD_BUG(x...) { printk("md: bug in file %s, line %d
  ", __FILE__, __LINE__); md_print_devices(); }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
  /*
1e50915fe   Robert Becker   raid: improve MD/...
73
74
75
76
77
78
   * Default number of read corrections we'll attempt on an rdev
   * before ejecting it from the array. We divide the read error
   * count by 2 for every hour elapsed between read errors.
   */
  #define MD_DEFAULT_MAX_CORRECTED_READ_ERRORS 20
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
81
   * Current RAID-1,4,5 parallel reconstruction 'guaranteed speed limit'
   * is 1000 KB/sec, so the extra system load does not show up that much.
   * Increase it if you want to have more _guaranteed_ speed. Note that
338cec325   Adrian Bunk   [PATCH] merge som...
82
   * the RAID driver will use the maximum available bandwidth if the IO
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
86
87
   * subsystem is idle. There is also an 'absolute maximum' reconstruction
   * speed limit - in case reconstruction slows down your system despite
   * idle IO detection.
   *
   * you can change it via /proc/sys/dev/raid/speed_limit_min and _max.
88202a0c8   NeilBrown   [PATCH] md: allow...
88
   * or /sys/block/mdX/md/sync_speed_{min,max}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
91
92
   */
  
  static int sysctl_speed_limit_min = 1000;
  static int sysctl_speed_limit_max = 200000;
fd01b88c7   NeilBrown   md: remove typede...
93
  static inline int speed_min(struct mddev *mddev)
88202a0c8   NeilBrown   [PATCH] md: allow...
94
95
96
97
  {
  	return mddev->sync_speed_min ?
  		mddev->sync_speed_min : sysctl_speed_limit_min;
  }
fd01b88c7   NeilBrown   md: remove typede...
98
  static inline int speed_max(struct mddev *mddev)
88202a0c8   NeilBrown   [PATCH] md: allow...
99
100
101
102
  {
  	return mddev->sync_speed_max ?
  		mddev->sync_speed_max : sysctl_speed_limit_max;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
106
107
  
  static struct ctl_table_header *raid_table_header;
  
  static ctl_table raid_table[] = {
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
  		.procname	= "speed_limit_min",
  		.data		= &sysctl_speed_limit_min,
  		.maxlen		= sizeof(int),
80ca3a44f   NeilBrown   [PATCH] md: unify...
111
  		.mode		= S_IRUGO|S_IWUSR,
6d4561110   Eric W. Biederman   sysctl: Drop & in...
112
  		.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
  	},
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
117
  		.procname	= "speed_limit_max",
  		.data		= &sysctl_speed_limit_max,
  		.maxlen		= sizeof(int),
80ca3a44f   NeilBrown   [PATCH] md: unify...
118
  		.mode		= S_IRUGO|S_IWUSR,
6d4561110   Eric W. Biederman   sysctl: Drop & in...
119
  		.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
  	},
894d24911   Eric W. Biederman   sysctl drivers: R...
121
  	{ }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
125
  };
  
  static ctl_table raid_dir_table[] = {
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
  		.procname	= "raid",
  		.maxlen		= 0,
80ca3a44f   NeilBrown   [PATCH] md: unify...
128
  		.mode		= S_IRUGO|S_IXUGO,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
  		.child		= raid_table,
  	},
894d24911   Eric W. Biederman   sysctl drivers: R...
131
  	{ }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
135
  };
  
  static ctl_table raid_root_table[] = {
  	{
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
139
140
  		.procname	= "dev",
  		.maxlen		= 0,
  		.mode		= 0555,
  		.child		= raid_dir_table,
  	},
894d24911   Eric W. Biederman   sysctl drivers: R...
141
  	{  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
  };
83d5cde47   Alexey Dobriyan   const: make block...
143
  static const struct block_device_operations md_fops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144

f91de92ed   NeilBrown   [PATCH] md: allow...
145
  static int start_readonly;
a167f6632   NeilBrown   md: use separate ...
146
147
148
149
150
151
  /* bio_clone_mddev
   * like bio_clone, but with a local bio set
   */
  
  static void mddev_bio_destructor(struct bio *bio)
  {
fd01b88c7   NeilBrown   md: remove typede...
152
  	struct mddev *mddev, **mddevp;
a167f6632   NeilBrown   md: use separate ...
153
154
155
156
157
158
159
160
  
  	mddevp = (void*)bio;
  	mddev = mddevp[-1];
  
  	bio_free(bio, mddev->bio_set);
  }
  
  struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs,
fd01b88c7   NeilBrown   md: remove typede...
161
  			    struct mddev *mddev)
a167f6632   NeilBrown   md: use separate ...
162
163
  {
  	struct bio *b;
fd01b88c7   NeilBrown   md: remove typede...
164
  	struct mddev **mddevp;
a167f6632   NeilBrown   md: use separate ...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
  
  	if (!mddev || !mddev->bio_set)
  		return bio_alloc(gfp_mask, nr_iovecs);
  
  	b = bio_alloc_bioset(gfp_mask, nr_iovecs,
  			     mddev->bio_set);
  	if (!b)
  		return NULL;
  	mddevp = (void*)b;
  	mddevp[-1] = mddev;
  	b->bi_destructor = mddev_bio_destructor;
  	return b;
  }
  EXPORT_SYMBOL_GPL(bio_alloc_mddev);
  
  struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask,
fd01b88c7   NeilBrown   md: remove typede...
181
  			    struct mddev *mddev)
a167f6632   NeilBrown   md: use separate ...
182
183
  {
  	struct bio *b;
fd01b88c7   NeilBrown   md: remove typede...
184
  	struct mddev **mddevp;
a167f6632   NeilBrown   md: use separate ...
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  
  	if (!mddev || !mddev->bio_set)
  		return bio_clone(bio, gfp_mask);
  
  	b = bio_alloc_bioset(gfp_mask, bio->bi_max_vecs,
  			     mddev->bio_set);
  	if (!b)
  		return NULL;
  	mddevp = (void*)b;
  	mddevp[-1] = mddev;
  	b->bi_destructor = mddev_bio_destructor;
  	__bio_clone(b, bio);
  	if (bio_integrity(bio)) {
  		int ret;
  
  		ret = bio_integrity_clone(b, bio, gfp_mask, mddev->bio_set);
  
  		if (ret < 0) {
  			bio_put(b);
  			return NULL;
  		}
  	}
  
  	return b;
  }
  EXPORT_SYMBOL_GPL(bio_clone_mddev);
d2eb35acf   NeilBrown   md/raid1: avoid r...
211
212
213
214
215
216
217
218
219
220
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
249
250
251
252
253
254
255
256
257
258
  void md_trim_bio(struct bio *bio, int offset, int size)
  {
  	/* 'bio' is a cloned bio which we need to trim to match
  	 * the given offset and size.
  	 * This requires adjusting bi_sector, bi_size, and bi_io_vec
  	 */
  	int i;
  	struct bio_vec *bvec;
  	int sofar = 0;
  
  	size <<= 9;
  	if (offset == 0 && size == bio->bi_size)
  		return;
  
  	bio->bi_sector += offset;
  	bio->bi_size = size;
  	offset <<= 9;
  	clear_bit(BIO_SEG_VALID, &bio->bi_flags);
  
  	while (bio->bi_idx < bio->bi_vcnt &&
  	       bio->bi_io_vec[bio->bi_idx].bv_len <= offset) {
  		/* remove this whole bio_vec */
  		offset -= bio->bi_io_vec[bio->bi_idx].bv_len;
  		bio->bi_idx++;
  	}
  	if (bio->bi_idx < bio->bi_vcnt) {
  		bio->bi_io_vec[bio->bi_idx].bv_offset += offset;
  		bio->bi_io_vec[bio->bi_idx].bv_len -= offset;
  	}
  	/* avoid any complications with bi_idx being non-zero*/
  	if (bio->bi_idx) {
  		memmove(bio->bi_io_vec, bio->bi_io_vec+bio->bi_idx,
  			(bio->bi_vcnt - bio->bi_idx) * sizeof(struct bio_vec));
  		bio->bi_vcnt -= bio->bi_idx;
  		bio->bi_idx = 0;
  	}
  	/* Make sure vcnt and last bv are not too big */
  	bio_for_each_segment(bvec, bio, i) {
  		if (sofar + bvec->bv_len > size)
  			bvec->bv_len = size - sofar;
  		if (bvec->bv_len == 0) {
  			bio->bi_vcnt = i;
  			break;
  		}
  		sofar += bvec->bv_len;
  	}
  }
  EXPORT_SYMBOL_GPL(md_trim_bio);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
  /*
d7603b7e3   NeilBrown   [PATCH] md: make ...
260
261
262
263
264
265
266
267
268
   * We have a system wide 'event count' that is incremented
   * on any 'interesting' event, and readers of /proc/mdstat
   * can use 'poll' or 'select' to find out when the event
   * count increases.
   *
   * Events are:
   *  start array, stop array, error, add device, remove device,
   *  start build, activate spare
   */
2989ddbd6   NeilBrown   [PATCH] md: make ...
269
  static DECLARE_WAIT_QUEUE_HEAD(md_event_waiters);
d7603b7e3   NeilBrown   [PATCH] md: make ...
270
  static atomic_t md_event_count;
fd01b88c7   NeilBrown   md: remove typede...
271
  void md_new_event(struct mddev *mddev)
d7603b7e3   NeilBrown   [PATCH] md: make ...
272
273
274
275
  {
  	atomic_inc(&md_event_count);
  	wake_up(&md_event_waiters);
  }
292695531   NeilBrown   [PATCH] md: Final...
276
  EXPORT_SYMBOL_GPL(md_new_event);
d7603b7e3   NeilBrown   [PATCH] md: make ...
277

c331eb04b   NeilBrown   [PATCH] md: Fix b...
278
279
280
  /* Alternate version that can be called from interrupts
   * when calling sysfs_notify isn't needed.
   */
fd01b88c7   NeilBrown   md: remove typede...
281
  static void md_new_event_inintr(struct mddev *mddev)
c331eb04b   NeilBrown   [PATCH] md: Fix b...
282
283
284
285
  {
  	atomic_inc(&md_event_count);
  	wake_up(&md_event_waiters);
  }
d7603b7e3   NeilBrown   [PATCH] md: make ...
286
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
290
291
292
293
294
295
296
297
298
299
300
   * Enables to iterate over all existing md arrays
   * all_mddevs_lock protects this list.
   */
  static LIST_HEAD(all_mddevs);
  static DEFINE_SPINLOCK(all_mddevs_lock);
  
  
  /*
   * iterates through all used mddevs in the system.
   * We take care to grab the all_mddevs_lock whenever navigating
   * the list, and to always hold a refcount when unlocked.
   * Any code which breaks out of this loop while own
   * a reference to the current mddev and must mddev_put it.
   */
fd01b88c7   NeilBrown   md: remove typede...
301
  #define for_each_mddev(_mddev,_tmp)					\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
  									\
  	for (({ spin_lock(&all_mddevs_lock); 				\
fd01b88c7   NeilBrown   md: remove typede...
304
305
306
307
  		_tmp = all_mddevs.next;					\
  		_mddev = NULL;});					\
  	     ({ if (_tmp != &all_mddevs)				\
  			mddev_get(list_entry(_tmp, struct mddev, all_mddevs));\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  		spin_unlock(&all_mddevs_lock);				\
fd01b88c7   NeilBrown   md: remove typede...
309
310
311
  		if (_mddev) mddev_put(_mddev);				\
  		_mddev = list_entry(_tmp, struct mddev, all_mddevs);	\
  		_tmp != &all_mddevs;});					\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  	     ({ spin_lock(&all_mddevs_lock);				\
fd01b88c7   NeilBrown   md: remove typede...
313
  		_tmp = _tmp->next;})					\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  		)
409c57f38   NeilBrown   md: enable suspen...
315
316
317
318
319
320
321
  /* Rather than calling directly into the personality make_request function,
   * IO requests come here first so that we can check if the device is
   * being suspended pending a reconfiguration.
   * We hold a refcount over the call to ->make_request.  By the time that
   * call has finished, the bio has been linked into some internal structure
   * and so is visible to ->quiesce(), so we don't need the refcount any more.
   */
5a7bbad27   Christoph Hellwig   block: remove sup...
322
  static void md_make_request(struct request_queue *q, struct bio *bio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
  {
490773268   NeilBrown   md: move io accou...
324
  	const int rw = bio_data_dir(bio);
fd01b88c7   NeilBrown   md: remove typede...
325
  	struct mddev *mddev = q->queuedata;
490773268   NeilBrown   md: move io accou...
326
  	int cpu;
e91ece559   Chris Mason   md_make_request: ...
327
  	unsigned int sectors;
490773268   NeilBrown   md: move io accou...
328

0ca69886a   NeilBrown   md: Ensure no IO ...
329
330
  	if (mddev == NULL || mddev->pers == NULL
  	    || !mddev->ready) {
409c57f38   NeilBrown   md: enable suspen...
331
  		bio_io_error(bio);
5a7bbad27   Christoph Hellwig   block: remove sup...
332
  		return;
409c57f38   NeilBrown   md: enable suspen...
333
  	}
0ca69886a   NeilBrown   md: Ensure no IO ...
334
  	smp_rmb(); /* Ensure implications of  'active' are visible */
409c57f38   NeilBrown   md: enable suspen...
335
  	rcu_read_lock();
e9c7469bb   Tejun Heo   md: implment REQ_...
336
  	if (mddev->suspended) {
409c57f38   NeilBrown   md: enable suspen...
337
338
339
340
  		DEFINE_WAIT(__wait);
  		for (;;) {
  			prepare_to_wait(&mddev->sb_wait, &__wait,
  					TASK_UNINTERRUPTIBLE);
e9c7469bb   Tejun Heo   md: implment REQ_...
341
  			if (!mddev->suspended)
409c57f38   NeilBrown   md: enable suspen...
342
343
344
345
346
347
348
349
350
  				break;
  			rcu_read_unlock();
  			schedule();
  			rcu_read_lock();
  		}
  		finish_wait(&mddev->sb_wait, &__wait);
  	}
  	atomic_inc(&mddev->active_io);
  	rcu_read_unlock();
490773268   NeilBrown   md: move io accou...
351

e91ece559   Chris Mason   md_make_request: ...
352
353
354
355
356
  	/*
  	 * save the sectors now since our bio can
  	 * go away inside make_request
  	 */
  	sectors = bio_sectors(bio);
5a7bbad27   Christoph Hellwig   block: remove sup...
357
  	mddev->pers->make_request(mddev, bio);
490773268   NeilBrown   md: move io accou...
358
359
360
  
  	cpu = part_stat_lock();
  	part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]);
e91ece559   Chris Mason   md_make_request: ...
361
  	part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw], sectors);
490773268   NeilBrown   md: move io accou...
362
  	part_stat_unlock();
409c57f38   NeilBrown   md: enable suspen...
363
364
  	if (atomic_dec_and_test(&mddev->active_io) && mddev->suspended)
  		wake_up(&mddev->sb_wait);
409c57f38   NeilBrown   md: enable suspen...
365
  }
9e35b99c7   NeilBrown   md: don't unregis...
366
367
368
369
370
371
  /* mddev_suspend makes sure no new requests are submitted
   * to the device, and that any requests that have been submitted
   * are completely handled.
   * Once ->stop is called and completes, the module will be completely
   * unused.
   */
fd01b88c7   NeilBrown   md: remove typede...
372
  void mddev_suspend(struct mddev *mddev)
409c57f38   NeilBrown   md: enable suspen...
373
374
375
376
377
378
  {
  	BUG_ON(mddev->suspended);
  	mddev->suspended = 1;
  	synchronize_rcu();
  	wait_event(mddev->sb_wait, atomic_read(&mddev->active_io) == 0);
  	mddev->pers->quiesce(mddev, 1);
409c57f38   NeilBrown   md: enable suspen...
379
  }
390ee602a   NeilBrown   md: export variou...
380
  EXPORT_SYMBOL_GPL(mddev_suspend);
409c57f38   NeilBrown   md: enable suspen...
381

fd01b88c7   NeilBrown   md: remove typede...
382
  void mddev_resume(struct mddev *mddev)
409c57f38   NeilBrown   md: enable suspen...
383
384
385
386
  {
  	mddev->suspended = 0;
  	wake_up(&mddev->sb_wait);
  	mddev->pers->quiesce(mddev, 0);
0fd018af3   Jonathan Brassow   MD: move thread w...
387
388
389
  
  	md_wakeup_thread(mddev->thread);
  	md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
  }
390ee602a   NeilBrown   md: export variou...
391
  EXPORT_SYMBOL_GPL(mddev_resume);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392

fd01b88c7   NeilBrown   md: remove typede...
393
  int mddev_congested(struct mddev *mddev, int bits)
3fa841d7e   NeilBrown   md: report device...
394
395
396
397
  {
  	return mddev->suspended;
  }
  EXPORT_SYMBOL(mddev_congested);
a2826aa92   NeilBrown   md: support barri...
398
  /*
e9c7469bb   Tejun Heo   md: implment REQ_...
399
   * Generic flush handling for md
a2826aa92   NeilBrown   md: support barri...
400
   */
e9c7469bb   Tejun Heo   md: implment REQ_...
401
  static void md_end_flush(struct bio *bio, int err)
a2826aa92   NeilBrown   md: support barri...
402
  {
3cb030020   NeilBrown   md: removing type...
403
  	struct md_rdev *rdev = bio->bi_private;
fd01b88c7   NeilBrown   md: remove typede...
404
  	struct mddev *mddev = rdev->mddev;
a2826aa92   NeilBrown   md: support barri...
405
406
407
408
  
  	rdev_dec_pending(rdev, mddev);
  
  	if (atomic_dec_and_test(&mddev->flush_pending)) {
e9c7469bb   Tejun Heo   md: implment REQ_...
409
  		/* The pre-request flush has finished */
e804ac780   Tejun Heo   md: fix and updat...
410
  		queue_work(md_wq, &mddev->flush_work);
a2826aa92   NeilBrown   md: support barri...
411
412
413
  	}
  	bio_put(bio);
  }
a7a07e696   NeilBrown   md: move code in ...
414
  static void md_submit_flush_data(struct work_struct *ws);
a035fc3e2   NeilBrown   md: fix possible ...
415
  static void submit_flushes(struct work_struct *ws)
a2826aa92   NeilBrown   md: support barri...
416
  {
fd01b88c7   NeilBrown   md: remove typede...
417
  	struct mddev *mddev = container_of(ws, struct mddev, flush_work);
3cb030020   NeilBrown   md: removing type...
418
  	struct md_rdev *rdev;
a2826aa92   NeilBrown   md: support barri...
419

a7a07e696   NeilBrown   md: move code in ...
420
421
  	INIT_WORK(&mddev->flush_work, md_submit_flush_data);
  	atomic_set(&mddev->flush_pending, 1);
a2826aa92   NeilBrown   md: support barri...
422
423
424
425
426
427
428
429
430
431
432
433
  	rcu_read_lock();
  	list_for_each_entry_rcu(rdev, &mddev->disks, same_set)
  		if (rdev->raid_disk >= 0 &&
  		    !test_bit(Faulty, &rdev->flags)) {
  			/* Take two references, one is dropped
  			 * when request finishes, one after
  			 * we reclaim rcu_read_lock
  			 */
  			struct bio *bi;
  			atomic_inc(&rdev->nr_pending);
  			atomic_inc(&rdev->nr_pending);
  			rcu_read_unlock();
a167f6632   NeilBrown   md: use separate ...
434
  			bi = bio_alloc_mddev(GFP_KERNEL, 0, mddev);
e9c7469bb   Tejun Heo   md: implment REQ_...
435
  			bi->bi_end_io = md_end_flush;
a2826aa92   NeilBrown   md: support barri...
436
437
438
  			bi->bi_private = rdev;
  			bi->bi_bdev = rdev->bdev;
  			atomic_inc(&mddev->flush_pending);
e9c7469bb   Tejun Heo   md: implment REQ_...
439
  			submit_bio(WRITE_FLUSH, bi);
a2826aa92   NeilBrown   md: support barri...
440
441
442
443
  			rcu_read_lock();
  			rdev_dec_pending(rdev, mddev);
  		}
  	rcu_read_unlock();
a7a07e696   NeilBrown   md: move code in ...
444
445
  	if (atomic_dec_and_test(&mddev->flush_pending))
  		queue_work(md_wq, &mddev->flush_work);
a2826aa92   NeilBrown   md: support barri...
446
  }
e9c7469bb   Tejun Heo   md: implment REQ_...
447
  static void md_submit_flush_data(struct work_struct *ws)
a2826aa92   NeilBrown   md: support barri...
448
  {
fd01b88c7   NeilBrown   md: remove typede...
449
  	struct mddev *mddev = container_of(ws, struct mddev, flush_work);
e9c7469bb   Tejun Heo   md: implment REQ_...
450
  	struct bio *bio = mddev->flush_bio;
a2826aa92   NeilBrown   md: support barri...
451

e9c7469bb   Tejun Heo   md: implment REQ_...
452
  	if (bio->bi_size == 0)
a2826aa92   NeilBrown   md: support barri...
453
454
455
  		/* an empty barrier - all done */
  		bio_endio(bio, 0);
  	else {
e9c7469bb   Tejun Heo   md: implment REQ_...
456
  		bio->bi_rw &= ~REQ_FLUSH;
5a7bbad27   Christoph Hellwig   block: remove sup...
457
  		mddev->pers->make_request(mddev, bio);
a2826aa92   NeilBrown   md: support barri...
458
  	}
2b74e12e5   NeilBrown   md: remove handli...
459
460
461
  
  	mddev->flush_bio = NULL;
  	wake_up(&mddev->sb_wait);
a2826aa92   NeilBrown   md: support barri...
462
  }
fd01b88c7   NeilBrown   md: remove typede...
463
  void md_flush_request(struct mddev *mddev, struct bio *bio)
a2826aa92   NeilBrown   md: support barri...
464
465
466
  {
  	spin_lock_irq(&mddev->write_lock);
  	wait_event_lock_irq(mddev->sb_wait,
e9c7469bb   Tejun Heo   md: implment REQ_...
467
  			    !mddev->flush_bio,
a2826aa92   NeilBrown   md: support barri...
468
  			    mddev->write_lock, /*nothing*/);
e9c7469bb   Tejun Heo   md: implment REQ_...
469
  	mddev->flush_bio = bio;
a2826aa92   NeilBrown   md: support barri...
470
  	spin_unlock_irq(&mddev->write_lock);
a035fc3e2   NeilBrown   md: fix possible ...
471
472
  	INIT_WORK(&mddev->flush_work, submit_flushes);
  	queue_work(md_wq, &mddev->flush_work);
a2826aa92   NeilBrown   md: support barri...
473
  }
e9c7469bb   Tejun Heo   md: implment REQ_...
474
  EXPORT_SYMBOL(md_flush_request);
409c57f38   NeilBrown   md: enable suspen...
475

97658cdd3   NeilBrown   md: provide gener...
476
477
478
479
480
481
482
483
484
485
  /* Support for plugging.
   * This mirrors the plugging support in request_queue, but does not
   * require having a whole queue or request structures.
   * We allocate an md_plug_cb for each md device and each thread it gets
   * plugged on.  This links tot the private plug_handle structure in the
   * personality data where we keep a count of the number of outstanding
   * plugs so other code can see if a plug is active.
   */
  struct md_plug_cb {
  	struct blk_plug_cb cb;
fd01b88c7   NeilBrown   md: remove typede...
486
  	struct mddev *mddev;
97658cdd3   NeilBrown   md: provide gener...
487
488
489
490
491
492
493
494
495
496
497
498
499
  };
  
  static void plugger_unplug(struct blk_plug_cb *cb)
  {
  	struct md_plug_cb *mdcb = container_of(cb, struct md_plug_cb, cb);
  	if (atomic_dec_and_test(&mdcb->mddev->plug_cnt))
  		md_wakeup_thread(mdcb->mddev->thread);
  	kfree(mdcb);
  }
  
  /* Check that an unplug wakeup will come shortly.
   * If not, wakeup the md thread immediately
   */
fd01b88c7   NeilBrown   md: remove typede...
500
  int mddev_check_plugged(struct mddev *mddev)
97658cdd3   NeilBrown   md: provide gener...
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
  {
  	struct blk_plug *plug = current->plug;
  	struct md_plug_cb *mdcb;
  
  	if (!plug)
  		return 0;
  
  	list_for_each_entry(mdcb, &plug->cb_list, cb.list) {
  		if (mdcb->cb.callback == plugger_unplug &&
  		    mdcb->mddev == mddev) {
  			/* Already on the list, move to top */
  			if (mdcb != list_first_entry(&plug->cb_list,
  						    struct md_plug_cb,
  						    cb.list))
  				list_move(&mdcb->cb.list, &plug->cb_list);
  			return 1;
  		}
  	}
  	/* Not currently on the callback list */
  	mdcb = kmalloc(sizeof(*mdcb), GFP_ATOMIC);
  	if (!mdcb)
  		return 0;
  
  	mdcb->mddev = mddev;
  	mdcb->cb.callback = plugger_unplug;
  	atomic_inc(&mddev->plug_cnt);
  	list_add(&mdcb->cb.list, &plug->cb_list);
  	return 1;
  }
  EXPORT_SYMBOL_GPL(mddev_check_plugged);
2ac874015   NeilBrown   md/raid5: add sim...
531

fd01b88c7   NeilBrown   md: remove typede...
532
  static inline struct mddev *mddev_get(struct mddev *mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
535
536
  {
  	atomic_inc(&mddev->active);
  	return mddev;
  }
5fd3a17ed   Dan Williams   md: fix deadlock ...
537
  static void mddev_delayed_delete(struct work_struct *ws);
d3374825c   NeilBrown   md: make devices ...
538

fd01b88c7   NeilBrown   md: remove typede...
539
  static void mddev_put(struct mddev *mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
  {
a167f6632   NeilBrown   md: use separate ...
541
  	struct bio_set *bs = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
  	if (!atomic_dec_and_lock(&mddev->active, &all_mddevs_lock))
  		return;
d3374825c   NeilBrown   md: make devices ...
544
  	if (!mddev->raid_disks && list_empty(&mddev->disks) &&
cbd199837   NeilBrown   md: Fix unfortuna...
545
546
547
  	    mddev->ctime == 0 && !mddev->hold_active) {
  		/* Array is not configured at all, and not held active,
  		 * so destroy it */
af8a24347   NeilBrown   md: take a refere...
548
  		list_del_init(&mddev->all_mddevs);
a167f6632   NeilBrown   md: use separate ...
549
550
  		bs = mddev->bio_set;
  		mddev->bio_set = NULL;
d3374825c   NeilBrown   md: make devices ...
551
  		if (mddev->gendisk) {
e804ac780   Tejun Heo   md: fix and updat...
552
553
554
555
  			/* We did a probe so need to clean up.  Call
  			 * queue_work inside the spinlock so that
  			 * flush_workqueue() after mddev_find will
  			 * succeed in waiting for the work to be done.
d3374825c   NeilBrown   md: make devices ...
556
557
  			 */
  			INIT_WORK(&mddev->del_work, mddev_delayed_delete);
e804ac780   Tejun Heo   md: fix and updat...
558
  			queue_work(md_misc_wq, &mddev->del_work);
d3374825c   NeilBrown   md: make devices ...
559
560
561
562
  		} else
  			kfree(mddev);
  	}
  	spin_unlock(&all_mddevs_lock);
a167f6632   NeilBrown   md: use separate ...
563
564
  	if (bs)
  		bioset_free(bs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
  }
fd01b88c7   NeilBrown   md: remove typede...
566
  void mddev_init(struct mddev *mddev)
fafd7fb05   NeilBrown   md: factor out in...
567
568
569
570
571
572
573
574
575
576
  {
  	mutex_init(&mddev->open_mutex);
  	mutex_init(&mddev->reconfig_mutex);
  	mutex_init(&mddev->bitmap_info.mutex);
  	INIT_LIST_HEAD(&mddev->disks);
  	INIT_LIST_HEAD(&mddev->all_mddevs);
  	init_timer(&mddev->safemode_timer);
  	atomic_set(&mddev->active, 1);
  	atomic_set(&mddev->openers, 0);
  	atomic_set(&mddev->active_io, 0);
97658cdd3   NeilBrown   md: provide gener...
577
  	atomic_set(&mddev->plug_cnt, 0);
fafd7fb05   NeilBrown   md: factor out in...
578
579
580
581
582
583
584
585
586
  	spin_lock_init(&mddev->write_lock);
  	atomic_set(&mddev->flush_pending, 0);
  	init_waitqueue_head(&mddev->sb_wait);
  	init_waitqueue_head(&mddev->recovery_wait);
  	mddev->reshape_position = MaxSector;
  	mddev->resync_min = 0;
  	mddev->resync_max = MaxSector;
  	mddev->level = LEVEL_NONE;
  }
390ee602a   NeilBrown   md: export variou...
587
  EXPORT_SYMBOL_GPL(mddev_init);
fafd7fb05   NeilBrown   md: factor out in...
588

fd01b88c7   NeilBrown   md: remove typede...
589
  static struct mddev * mddev_find(dev_t unit)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
  {
fd01b88c7   NeilBrown   md: remove typede...
591
  	struct mddev *mddev, *new = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592

8f5f02c46   NeilBrown   md: correctly han...
593
594
  	if (unit && MAJOR(unit) != MD_MAJOR)
  		unit &= ~((1<<MdpMinorShift)-1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
596
   retry:
  	spin_lock(&all_mddevs_lock);
efeb53c0e   NeilBrown   md: Allow md devi...
597
598
599
600
601
602
603
604
605
606
607
608
  
  	if (unit) {
  		list_for_each_entry(mddev, &all_mddevs, all_mddevs)
  			if (mddev->unit == unit) {
  				mddev_get(mddev);
  				spin_unlock(&all_mddevs_lock);
  				kfree(new);
  				return mddev;
  			}
  
  		if (new) {
  			list_add(&new->all_mddevs, &all_mddevs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
  			spin_unlock(&all_mddevs_lock);
efeb53c0e   NeilBrown   md: Allow md devi...
610
611
  			new->hold_active = UNTIL_IOCTL;
  			return new;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
  		}
efeb53c0e   NeilBrown   md: Allow md devi...
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
  	} else if (new) {
  		/* find an unused unit number */
  		static int next_minor = 512;
  		int start = next_minor;
  		int is_free = 0;
  		int dev = 0;
  		while (!is_free) {
  			dev = MKDEV(MD_MAJOR, next_minor);
  			next_minor++;
  			if (next_minor > MINORMASK)
  				next_minor = 0;
  			if (next_minor == start) {
  				/* Oh dear, all in use. */
  				spin_unlock(&all_mddevs_lock);
  				kfree(new);
  				return NULL;
  			}
  				
  			is_free = 1;
  			list_for_each_entry(mddev, &all_mddevs, all_mddevs)
  				if (mddev->unit == dev) {
  					is_free = 0;
  					break;
  				}
  		}
  		new->unit = dev;
  		new->md_minor = MINOR(dev);
  		new->hold_active = UNTIL_STOP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
643
644
645
  		list_add(&new->all_mddevs, &all_mddevs);
  		spin_unlock(&all_mddevs_lock);
  		return new;
  	}
  	spin_unlock(&all_mddevs_lock);
9ffae0cf3   NeilBrown   [PATCH] md: conve...
646
  	new = kzalloc(sizeof(*new), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
  	if (!new)
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
650
651
652
653
  	new->unit = unit;
  	if (MAJOR(unit) == MD_MAJOR)
  		new->md_minor = MINOR(unit);
  	else
  		new->md_minor = MINOR(unit) >> MdpMinorShift;
fafd7fb05   NeilBrown   md: factor out in...
654
  	mddev_init(new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
657
  	goto retry;
  }
fd01b88c7   NeilBrown   md: remove typede...
658
  static inline int mddev_lock(struct mddev * mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
  {
df5b89b32   NeilBrown   [PATCH] md: Conve...
660
  	return mutex_lock_interruptible(&mddev->reconfig_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
  }
fd01b88c7   NeilBrown   md: remove typede...
662
  static inline int mddev_is_locked(struct mddev *mddev)
b522adcde   Dan Williams   md: 'array_size' ...
663
664
665
  {
  	return mutex_is_locked(&mddev->reconfig_mutex);
  }
fd01b88c7   NeilBrown   md: remove typede...
666
  static inline int mddev_trylock(struct mddev * mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
  {
df5b89b32   NeilBrown   [PATCH] md: Conve...
668
  	return mutex_trylock(&mddev->reconfig_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
  }
b6eb127d2   NeilBrown   md: remove unneed...
670
  static struct attribute_group md_redundancy_group;
fd01b88c7   NeilBrown   md: remove typede...
671
  static void mddev_unlock(struct mddev * mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
  {
a64c876fd   NeilBrown   md: manage redund...
673
  	if (mddev->to_remove) {
b6eb127d2   NeilBrown   md: remove unneed...
674
675
676
677
  		/* These cannot be removed under reconfig_mutex as
  		 * an access to the files will try to take reconfig_mutex
  		 * while holding the file unremovable, which leads to
  		 * a deadlock.
bb4f1e9d0   NeilBrown   md: fix another d...
678
679
680
681
682
683
684
  		 * So hold set sysfs_active while the remove in happeing,
  		 * and anything else which might set ->to_remove or my
  		 * otherwise change the sysfs namespace will fail with
  		 * -EBUSY if sysfs_active is still set.
  		 * We set sysfs_active under reconfig_mutex and elsewhere
  		 * test it under the same mutex to ensure its correct value
  		 * is seen.
b6eb127d2   NeilBrown   md: remove unneed...
685
  		 */
a64c876fd   NeilBrown   md: manage redund...
686
687
  		struct attribute_group *to_remove = mddev->to_remove;
  		mddev->to_remove = NULL;
bb4f1e9d0   NeilBrown   md: fix another d...
688
  		mddev->sysfs_active = 1;
b6eb127d2   NeilBrown   md: remove unneed...
689
  		mutex_unlock(&mddev->reconfig_mutex);
00bcb4ac7   NeilBrown   md: reduce depend...
690
691
692
693
694
695
696
697
698
699
  		if (mddev->kobj.sd) {
  			if (to_remove != &md_redundancy_group)
  				sysfs_remove_group(&mddev->kobj, to_remove);
  			if (mddev->pers == NULL ||
  			    mddev->pers->sync_request == NULL) {
  				sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
  				if (mddev->sysfs_action)
  					sysfs_put(mddev->sysfs_action);
  				mddev->sysfs_action = NULL;
  			}
a64c876fd   NeilBrown   md: manage redund...
700
  		}
bb4f1e9d0   NeilBrown   md: fix another d...
701
  		mddev->sysfs_active = 0;
b6eb127d2   NeilBrown   md: remove unneed...
702
703
  	} else
  		mutex_unlock(&mddev->reconfig_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704

751e67ca2   Chris Dunlop   md.c: trivial com...
705
706
  	/* As we've dropped the mutex we need a spinlock to
  	 * make sure the thread doesn't disappear
01f96c0a9   NeilBrown   md: Avoid waking ...
707
708
  	 */
  	spin_lock(&pers_lock);
005eca5e7   NeilBrown   [PATCH] md: make ...
709
  	md_wakeup_thread(mddev->thread);
01f96c0a9   NeilBrown   md: Avoid waking ...
710
  	spin_unlock(&pers_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
  }
fd01b88c7   NeilBrown   md: remove typede...
712
  static struct md_rdev * find_rdev_nr(struct mddev *mddev, int nr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
  {
3cb030020   NeilBrown   md: removing type...
714
  	struct md_rdev *rdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715

159ec1fc0   Cheng Renquan   md: use list_for_...
716
  	list_for_each_entry(rdev, &mddev->disks, same_set)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
718
  		if (rdev->desc_nr == nr)
  			return rdev;
159ec1fc0   Cheng Renquan   md: use list_for_...
719

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
721
  	return NULL;
  }
fd01b88c7   NeilBrown   md: remove typede...
722
  static struct md_rdev * find_rdev(struct mddev * mddev, dev_t dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723
  {
3cb030020   NeilBrown   md: removing type...
724
  	struct md_rdev *rdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725

159ec1fc0   Cheng Renquan   md: use list_for_...
726
  	list_for_each_entry(rdev, &mddev->disks, same_set)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
728
  		if (rdev->bdev->bd_dev == dev)
  			return rdev;
159ec1fc0   Cheng Renquan   md: use list_for_...
729

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
731
  	return NULL;
  }
84fc4b56d   NeilBrown   md: rename "mdk_p...
732
  static struct md_personality *find_pers(int level, char *clevel)
2604b703b   NeilBrown   [PATCH] md: remov...
733
  {
84fc4b56d   NeilBrown   md: rename "mdk_p...
734
  	struct md_personality *pers;
d9d166c2a   NeilBrown   [PATCH] md: allow...
735
736
  	list_for_each_entry(pers, &pers_list, list) {
  		if (level != LEVEL_NONE && pers->level == level)
2604b703b   NeilBrown   [PATCH] md: remov...
737
  			return pers;
d9d166c2a   NeilBrown   [PATCH] md: allow...
738
739
740
  		if (strcmp(pers->name, clevel)==0)
  			return pers;
  	}
2604b703b   NeilBrown   [PATCH] md: remov...
741
742
  	return NULL;
  }
b73df2d3d   Andre Noll   md: Make calc_dev...
743
  /* return the offset of the super block in 512byte sectors */
3cb030020   NeilBrown   md: removing type...
744
  static inline sector_t calc_dev_sboffset(struct md_rdev *rdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
  {
57b2caa39   Jonathan Brassow   md-new-param-to-c...
746
  	sector_t num_sectors = i_size_read(rdev->bdev->bd_inode) / 512;
b73df2d3d   Andre Noll   md: Make calc_dev...
747
  	return MD_NEW_SIZE_SECTORS(num_sectors);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
  }
3cb030020   NeilBrown   md: removing type...
749
  static int alloc_disk_sb(struct md_rdev * rdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
751
752
753
754
755
756
757
  {
  	if (rdev->sb_page)
  		MD_BUG();
  
  	rdev->sb_page = alloc_page(GFP_KERNEL);
  	if (!rdev->sb_page) {
  		printk(KERN_ALERT "md: out of memory.
  ");
ebc243372   Andre Noll   md: alloc_disk_sb...
758
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759
760
761
762
  	}
  
  	return 0;
  }
3cb030020   NeilBrown   md: removing type...
763
  static void free_disk_sb(struct md_rdev * rdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
765
  {
  	if (rdev->sb_page) {
2d1f3b5d1   NeilBrown   [PATCH] md: clean...
766
  		put_page(rdev->sb_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
  		rdev->sb_loaded = 0;
  		rdev->sb_page = NULL;
0f420358e   Andre Noll   md: Turn rdev->sb...
769
  		rdev->sb_start = 0;
dd8ac336c   Andre Noll   md: Represent rai...
770
  		rdev->sectors = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
  	}
2699b6722   NeilBrown   md: load/store ba...
772
773
774
775
  	if (rdev->bb_page) {
  		put_page(rdev->bb_page);
  		rdev->bb_page = NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
  }
6712ecf8f   NeilBrown   Drop 'size' argum...
777
  static void super_written(struct bio *bio, int error)
7bfa19f27   NeilBrown   [PATCH] md: allow...
778
  {
3cb030020   NeilBrown   md: removing type...
779
  	struct md_rdev *rdev = bio->bi_private;
fd01b88c7   NeilBrown   md: remove typede...
780
  	struct mddev *mddev = rdev->mddev;
7bfa19f27   NeilBrown   [PATCH] md: allow...
781

3a0f5bbb1   NeilBrown   [PATCH] md: add e...
782
783
784
785
786
  	if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags)) {
  		printk("md: super_written gets error=%d, uptodate=%d
  ",
  		       error, test_bit(BIO_UPTODATE, &bio->bi_flags));
  		WARN_ON(test_bit(BIO_UPTODATE, &bio->bi_flags));
a9701a304   NeilBrown   [PATCH] md: suppo...
787
  		md_error(mddev, rdev);
3a0f5bbb1   NeilBrown   [PATCH] md: add e...
788
  	}
7bfa19f27   NeilBrown   [PATCH] md: allow...
789

a9701a304   NeilBrown   [PATCH] md: suppo...
790
791
  	if (atomic_dec_and_test(&mddev->pending_writes))
  		wake_up(&mddev->sb_wait);
f8b58edf3   Neil Brown   [PATCH] md: bio l...
792
  	bio_put(bio);
7bfa19f27   NeilBrown   [PATCH] md: allow...
793
  }
fd01b88c7   NeilBrown   md: remove typede...
794
  void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
7bfa19f27   NeilBrown   [PATCH] md: allow...
795
796
797
798
799
800
801
802
  		   sector_t sector, int size, struct page *page)
  {
  	/* write first size bytes of page to sector of rdev
  	 * Increment mddev->pending_writes before returning
  	 * and decrement it on completion, waking up sb_wait
  	 * if zero is reached.
  	 * If an error occurred, call md_error
  	 */
a167f6632   NeilBrown   md: use separate ...
803
  	struct bio *bio = bio_alloc_mddev(GFP_NOIO, 1, mddev);
7bfa19f27   NeilBrown   [PATCH] md: allow...
804

a6ff7e089   Jonathan Brassow   md: separate meta...
805
  	bio->bi_bdev = rdev->meta_bdev ? rdev->meta_bdev : rdev->bdev;
7bfa19f27   NeilBrown   [PATCH] md: allow...
806
807
808
809
  	bio->bi_sector = sector;
  	bio_add_page(bio, page, size, 0);
  	bio->bi_private = rdev;
  	bio->bi_end_io = super_written;
a9701a304   NeilBrown   [PATCH] md: suppo...
810

7bfa19f27   NeilBrown   [PATCH] md: allow...
811
  	atomic_inc(&mddev->pending_writes);
a5bf4df0c   Namhyung Kim   md: use REQ_NOIDL...
812
  	submit_bio(WRITE_FLUSH_FUA, bio);
a9701a304   NeilBrown   [PATCH] md: suppo...
813
  }
fd01b88c7   NeilBrown   md: remove typede...
814
  void md_super_wait(struct mddev *mddev)
a9701a304   NeilBrown   [PATCH] md: suppo...
815
  {
e9c7469bb   Tejun Heo   md: implment REQ_...
816
  	/* wait for all superblock writes that were scheduled to complete */
a9701a304   NeilBrown   [PATCH] md: suppo...
817
818
819
820
821
  	DEFINE_WAIT(wq);
  	for(;;) {
  		prepare_to_wait(&mddev->sb_wait, &wq, TASK_UNINTERRUPTIBLE);
  		if (atomic_read(&mddev->pending_writes)==0)
  			break;
a9701a304   NeilBrown   [PATCH] md: suppo...
822
823
824
  		schedule();
  	}
  	finish_wait(&mddev->sb_wait, &wq);
7bfa19f27   NeilBrown   [PATCH] md: allow...
825
  }
6712ecf8f   NeilBrown   Drop 'size' argum...
826
  static void bi_complete(struct bio *bio, int error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
  	complete((struct completion*)bio->bi_private);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
  }
3cb030020   NeilBrown   md: removing type...
830
  int sync_page_io(struct md_rdev *rdev, sector_t sector, int size,
ccebd4c41   Jonathan Brassow   md-new-param-to_s...
831
  		 struct page *page, int rw, bool metadata_op)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
832
  {
a167f6632   NeilBrown   md: use separate ...
833
  	struct bio *bio = bio_alloc_mddev(GFP_NOIO, 1, rdev->mddev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
834
835
  	struct completion event;
  	int ret;
721a9602e   Jens Axboe   block: kill off R...
836
  	rw |= REQ_SYNC;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837

a6ff7e089   Jonathan Brassow   md: separate meta...
838
839
  	bio->bi_bdev = (metadata_op && rdev->meta_bdev) ?
  		rdev->meta_bdev : rdev->bdev;
ccebd4c41   Jonathan Brassow   md-new-param-to_s...
840
841
842
843
  	if (metadata_op)
  		bio->bi_sector = sector + rdev->sb_start;
  	else
  		bio->bi_sector = sector + rdev->data_offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
845
846
847
848
849
850
851
852
853
854
  	bio_add_page(bio, page, size, 0);
  	init_completion(&event);
  	bio->bi_private = &event;
  	bio->bi_end_io = bi_complete;
  	submit_bio(rw, bio);
  	wait_for_completion(&event);
  
  	ret = test_bit(BIO_UPTODATE, &bio->bi_flags);
  	bio_put(bio);
  	return ret;
  }
a8745db23   NeilBrown   [PATCH] md: conve...
855
  EXPORT_SYMBOL_GPL(sync_page_io);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856

3cb030020   NeilBrown   md: removing type...
857
  static int read_disk_sb(struct md_rdev * rdev, int size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
859
860
861
862
863
864
865
  {
  	char b[BDEVNAME_SIZE];
  	if (!rdev->sb_page) {
  		MD_BUG();
  		return -EINVAL;
  	}
  	if (rdev->sb_loaded)
  		return 0;
ccebd4c41   Jonathan Brassow   md-new-param-to_s...
866
  	if (!sync_page_io(rdev, 0, size, rdev->sb_page, READ, true))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
868
869
870
871
872
873
874
875
876
877
878
879
  		goto fail;
  	rdev->sb_loaded = 1;
  	return 0;
  
  fail:
  	printk(KERN_WARNING "md: disabled device %s, could not read superblock.
  ",
  		bdevname(rdev->bdev,b));
  	return -EINVAL;
  }
  
  static int uuid_equal(mdp_super_t *sb1, mdp_super_t *sb2)
  {
05710466c   Andre Noll   md: Simplify uuid...
880
881
882
883
  	return 	sb1->set_uuid0 == sb2->set_uuid0 &&
  		sb1->set_uuid1 == sb2->set_uuid1 &&
  		sb1->set_uuid2 == sb2->set_uuid2 &&
  		sb1->set_uuid3 == sb2->set_uuid3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
884
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885
886
887
888
889
890
891
892
893
894
  static int sb_equal(mdp_super_t *sb1, mdp_super_t *sb2)
  {
  	int ret;
  	mdp_super_t *tmp1, *tmp2;
  
  	tmp1 = kmalloc(sizeof(*tmp1),GFP_KERNEL);
  	tmp2 = kmalloc(sizeof(*tmp2),GFP_KERNEL);
  
  	if (!tmp1 || !tmp2) {
  		ret = 0;
35020f1a0   Andre Noll   md: sb_equal(): F...
895
896
  		printk(KERN_INFO "md.c sb_equal(): failed to allocate memory!
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
898
899
900
901
902
903
904
905
906
907
  		goto abort;
  	}
  
  	*tmp1 = *sb1;
  	*tmp2 = *sb2;
  
  	/*
  	 * nr_disks is not constant
  	 */
  	tmp1->nr_disks = 0;
  	tmp2->nr_disks = 0;
ce0c8e05f   Andre Noll   md: Simplify sb_e...
908
  	ret = (memcmp(tmp1, tmp2, MD_SB_GENERIC_CONSTANT_WORDS * 4) == 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
  abort:
990a8baf5   Jesper Juhl   [PATCH] md: remov...
910
911
  	kfree(tmp1);
  	kfree(tmp2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
913
  	return ret;
  }
4d167f093   NeilBrown   md: stop using cs...
914
915
916
917
918
919
  
  static u32 md_csum_fold(u32 csum)
  {
  	csum = (csum & 0xffff) + (csum >> 16);
  	return (csum & 0xffff) + (csum >> 16);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920
921
  static unsigned int calc_sb_csum(mdp_super_t * sb)
  {
4d167f093   NeilBrown   md: stop using cs...
922
923
924
  	u64 newcsum = 0;
  	u32 *sb32 = (u32*)sb;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925
926
927
928
  	unsigned int disk_csum, csum;
  
  	disk_csum = sb->sb_csum;
  	sb->sb_csum = 0;
4d167f093   NeilBrown   md: stop using cs...
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
  
  	for (i = 0; i < MD_SB_BYTES/4 ; i++)
  		newcsum += sb32[i];
  	csum = (newcsum & 0xffffffff) + (newcsum>>32);
  
  
  #ifdef CONFIG_ALPHA
  	/* This used to use csum_partial, which was wrong for several
  	 * reasons including that different results are returned on
  	 * different architectures.  It isn't critical that we get exactly
  	 * the same return value as before (we always csum_fold before
  	 * testing, and that removes any differences).  However as we
  	 * know that csum_partial always returned a 16bit value on
  	 * alphas, do a fold to maximise conformity to previous behaviour.
  	 */
  	sb->sb_csum = md_csum_fold(disk_csum);
  #else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
  	sb->sb_csum = disk_csum;
4d167f093   NeilBrown   md: stop using cs...
947
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
948
949
950
951
952
953
954
955
956
957
958
959
  	return csum;
  }
  
  
  /*
   * Handle superblock details.
   * We want to be able to handle multiple superblock formats
   * so we have a common interface to them all, and an array of
   * different handlers.
   * We rely on user-space to write the initial superblock, and support
   * reading and updating of superblocks.
   * Interface methods are:
3cb030020   NeilBrown   md: removing type...
960
   *   int load_super(struct md_rdev *dev, struct md_rdev *refdev, int minor_version)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
961
962
963
964
965
966
967
968
969
   *      loads and validates a superblock on dev.
   *      if refdev != NULL, compare superblocks on both devices
   *    Return:
   *      0 - dev has a superblock that is compatible with refdev
   *      1 - dev has a superblock that is compatible and newer than refdev
   *          so dev should be used as the refdev in future
   *     -EINVAL superblock incompatible or invalid
   *     -othererror e.g. -EIO
   *
fd01b88c7   NeilBrown   md: remove typede...
970
   *   int validate_super(struct mddev *mddev, struct md_rdev *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
971
972
973
974
975
   *      Verify that dev is acceptable into mddev.
   *       The first time, mddev->raid_disks will be 0, and data from
   *       dev should be merged in.  Subsequent calls check that dev
   *       is new enough.  Return 0 or -EINVAL
   *
fd01b88c7   NeilBrown   md: remove typede...
976
   *   void sync_super(struct mddev *mddev, struct md_rdev *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977
978
979
980
981
982
   *     Update the superblock for rdev with data in mddev
   *     This does not write to disc.
   *
   */
  
  struct super_type  {
0cd17fec9   Chris Webb   Support changing ...
983
984
  	char		    *name;
  	struct module	    *owner;
3cb030020   NeilBrown   md: removing type...
985
  	int		    (*load_super)(struct md_rdev *rdev, struct md_rdev *refdev,
0cd17fec9   Chris Webb   Support changing ...
986
  					  int minor_version);
fd01b88c7   NeilBrown   md: remove typede...
987
988
  	int		    (*validate_super)(struct mddev *mddev, struct md_rdev *rdev);
  	void		    (*sync_super)(struct mddev *mddev, struct md_rdev *rdev);
3cb030020   NeilBrown   md: removing type...
989
  	unsigned long long  (*rdev_size_change)(struct md_rdev *rdev,
15f4a5fdf   Andre Noll   md: Make super_ty...
990
  						sector_t num_sectors);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991
992
993
  };
  
  /*
0894cc306   Andre Noll   md: Move check fo...
994
995
996
997
998
999
1000
   * Check that the given mddev has no bitmap.
   *
   * This function is called from the run method of all personalities that do not
   * support bitmaps. It prints an error message and returns non-zero if mddev
   * has a bitmap. Otherwise, it returns 0.
   *
   */
fd01b88c7   NeilBrown   md: remove typede...
1001
  int md_check_no_bitmap(struct mddev *mddev)
0894cc306   Andre Noll   md: Move check fo...
1002
  {
c3d9714e8   NeilBrown   md: collect bitma...
1003
  	if (!mddev->bitmap_info.file && !mddev->bitmap_info.offset)
0894cc306   Andre Noll   md: Move check fo...
1004
1005
1006
1007
1008
1009
1010
1011
1012
  		return 0;
  	printk(KERN_ERR "%s: bitmaps are not supported for %s
  ",
  		mdname(mddev), mddev->pers->name);
  	return 1;
  }
  EXPORT_SYMBOL(md_check_no_bitmap);
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013
1014
   * load_super for 0.90.0 
   */
3cb030020   NeilBrown   md: removing type...
1015
  static int super_90_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_version)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1016
1017
1018
1019
  {
  	char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
  	mdp_super_t *sb;
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
1021
  
  	/*
0f420358e   Andre Noll   md: Turn rdev->sb...
1022
  	 * Calculate the position of the superblock (512byte sectors),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1023
1024
1025
1026
  	 * it's at the end of the disk.
  	 *
  	 * It also happens to be a multiple of 4Kb.
  	 */
57b2caa39   Jonathan Brassow   md-new-param-to-c...
1027
  	rdev->sb_start = calc_dev_sboffset(rdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1028

0002b2718   NeilBrown   [PATCH] md: limit...
1029
  	ret = read_disk_sb(rdev, MD_SB_BYTES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1030
1031
1032
1033
1034
  	if (ret) return ret;
  
  	ret = -EINVAL;
  
  	bdevname(rdev->bdev, b);
65a06f067   Namhyung Kim   md: get rid of un...
1035
  	sb = page_address(rdev->sb_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1036
1037
1038
1039
1040
1041
1042
1043
1044
  
  	if (sb->md_magic != MD_SB_MAGIC) {
  		printk(KERN_ERR "md: invalid raid superblock magic on %s
  ",
  		       b);
  		goto abort;
  	}
  
  	if (sb->major_version != 0 ||
f67055780   NeilBrown   [PATCH] md: Check...
1045
1046
  	    sb->minor_version < 90 ||
  	    sb->minor_version > 91) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1047
1048
1049
1050
1051
1052
1053
1054
1055
  		printk(KERN_WARNING "Bad version number %d.%d on %s
  ",
  			sb->major_version, sb->minor_version,
  			b);
  		goto abort;
  	}
  
  	if (sb->raid_disks <= 0)
  		goto abort;
4d167f093   NeilBrown   md: stop using cs...
1056
  	if (md_csum_fold(calc_sb_csum(sb)) != md_csum_fold(sb->sb_csum)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1057
1058
1059
1060
1061
1062
1063
1064
  		printk(KERN_WARNING "md: invalid superblock checksum on %s
  ",
  			b);
  		goto abort;
  	}
  
  	rdev->preferred_minor = sb->md_minor;
  	rdev->data_offset = 0;
0002b2718   NeilBrown   [PATCH] md: limit...
1065
  	rdev->sb_size = MD_SB_BYTES;
9f2f38307   NeilBrown   md: Disable bad b...
1066
  	rdev->badblocks.shift = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
1068
1069
1070
1071
  
  	if (sb->level == LEVEL_MULTIPATH)
  		rdev->desc_nr = -1;
  	else
  		rdev->desc_nr = sb->this_disk.number;
9a7b2b0f3   Harvey Harrison   md: fix integer a...
1072
  	if (!refdev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1073
  		ret = 1;
9a7b2b0f3   Harvey Harrison   md: fix integer a...
1074
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1075
  		__u64 ev1, ev2;
65a06f067   Namhyung Kim   md: get rid of un...
1076
  		mdp_super_t *refsb = page_address(refdev->sb_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
  		if (!uuid_equal(refsb, sb)) {
  			printk(KERN_WARNING "md: %s has different UUID to %s
  ",
  				b, bdevname(refdev->bdev,b2));
  			goto abort;
  		}
  		if (!sb_equal(refsb, sb)) {
  			printk(KERN_WARNING "md: %s has same UUID"
  			       " but different superblock to %s
  ",
  			       b, bdevname(refdev->bdev, b2));
  			goto abort;
  		}
  		ev1 = md_event(sb);
  		ev2 = md_event(refsb);
  		if (ev1 > ev2)
  			ret = 1;
  		else 
  			ret = 0;
  	}
8190e754e   NeilBrown   md: remove chunks...
1097
  	rdev->sectors = rdev->sb_start;
27a7b260f   NeilBrown   md: Fix handling ...
1098
1099
1100
  	/* Limit to 4TB as metadata cannot record more than that */
  	if (rdev->sectors >= (2ULL << 32))
  		rdev->sectors = (2ULL << 32) - 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101

27a7b260f   NeilBrown   md: Fix handling ...
1102
  	if (rdev->sectors < ((sector_t)sb->size) * 2 && sb->level >= 1)
2bf071bf5   NeilBrown   [PATCH] md: keep ...
1103
1104
  		/* "this cannot possibly happen" ... */
  		ret = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1105
1106
1107
1108
1109
1110
1111
   abort:
  	return ret;
  }
  
  /*
   * validate_super for 0.90.0
   */
fd01b88c7   NeilBrown   md: remove typede...
1112
  static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1113
1114
  {
  	mdp_disk_t *desc;
65a06f067   Namhyung Kim   md: get rid of un...
1115
  	mdp_super_t *sb = page_address(rdev->sb_page);
07d84d109   NeilBrown   [PATCH] md: Allow...
1116
  	__u64 ev1 = md_event(sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1117

41158c7eb   NeilBrown   [PATCH] md: optim...
1118
  	rdev->raid_disk = -1;
c5d79adba   NeilBrown   md: allow devices...
1119
1120
1121
  	clear_bit(Faulty, &rdev->flags);
  	clear_bit(In_sync, &rdev->flags);
  	clear_bit(WriteMostly, &rdev->flags);
c5d79adba   NeilBrown   md: allow devices...
1122

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1123
1124
1125
1126
  	if (mddev->raid_disks == 0) {
  		mddev->major_version = 0;
  		mddev->minor_version = sb->minor_version;
  		mddev->patch_version = sb->patch_version;
e691063a6   NeilBrown   md: support 'exte...
1127
  		mddev->external = 0;
9d8f03636   Andre Noll   md: Make mddev->c...
1128
  		mddev->chunk_sectors = sb->chunk_size >> 9;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
1130
1131
  		mddev->ctime = sb->ctime;
  		mddev->utime = sb->utime;
  		mddev->level = sb->level;
d9d166c2a   NeilBrown   [PATCH] md: allow...
1132
  		mddev->clevel[0] = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1133
1134
  		mddev->layout = sb->layout;
  		mddev->raid_disks = sb->raid_disks;
27a7b260f   NeilBrown   md: Fix handling ...
1135
  		mddev->dev_sectors = ((sector_t)sb->size) * 2;
07d84d109   NeilBrown   [PATCH] md: Allow...
1136
  		mddev->events = ev1;
c3d9714e8   NeilBrown   md: collect bitma...
1137
1138
  		mddev->bitmap_info.offset = 0;
  		mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1139

f67055780   NeilBrown   [PATCH] md: Check...
1140
1141
1142
1143
1144
  		if (mddev->minor_version >= 91) {
  			mddev->reshape_position = sb->reshape_position;
  			mddev->delta_disks = sb->delta_disks;
  			mddev->new_level = sb->new_level;
  			mddev->new_layout = sb->new_layout;
664e7c413   Andre Noll   md: Convert mddev...
1145
  			mddev->new_chunk_sectors = sb->new_chunk >> 9;
f67055780   NeilBrown   [PATCH] md: Check...
1146
1147
1148
1149
1150
  		} else {
  			mddev->reshape_position = MaxSector;
  			mddev->delta_disks = 0;
  			mddev->new_level = mddev->level;
  			mddev->new_layout = mddev->layout;
664e7c413   Andre Noll   md: Convert mddev...
1151
  			mddev->new_chunk_sectors = mddev->chunk_sectors;
f67055780   NeilBrown   [PATCH] md: Check...
1152
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
  		if (sb->state & (1<<MD_SB_CLEAN))
  			mddev->recovery_cp = MaxSector;
  		else {
  			if (sb->events_hi == sb->cp_events_hi && 
  				sb->events_lo == sb->cp_events_lo) {
  				mddev->recovery_cp = sb->recovery_cp;
  			} else
  				mddev->recovery_cp = 0;
  		}
  
  		memcpy(mddev->uuid+0, &sb->set_uuid0, 4);
  		memcpy(mddev->uuid+4, &sb->set_uuid1, 4);
  		memcpy(mddev->uuid+8, &sb->set_uuid2, 4);
  		memcpy(mddev->uuid+12,&sb->set_uuid3, 4);
  
  		mddev->max_disks = MD_SB_DISKS;
a654b9d8f   NeilBrown   [PATCH] md: allow...
1169
1170
  
  		if (sb->state & (1<<MD_SB_BITMAP_PRESENT) &&
c3d9714e8   NeilBrown   md: collect bitma...
1171
1172
1173
  		    mddev->bitmap_info.file == NULL)
  			mddev->bitmap_info.offset =
  				mddev->bitmap_info.default_offset;
a654b9d8f   NeilBrown   [PATCH] md: allow...
1174

41158c7eb   NeilBrown   [PATCH] md: optim...
1175
  	} else if (mddev->pers == NULL) {
be6800a73   NeilBrown   md: don't insist ...
1176
1177
  		/* Insist on good event counter while assembling, except
  		 * for spares (which don't need an event count) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1178
  		++ev1;
be6800a73   NeilBrown   md: don't insist ...
1179
1180
1181
1182
  		if (sb->disks[rdev->desc_nr].state & (
  			    (1<<MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE)))
  			if (ev1 < mddev->events) 
  				return -EINVAL;
41158c7eb   NeilBrown   [PATCH] md: optim...
1183
1184
1185
1186
  	} else if (mddev->bitmap) {
  		/* if adding to array with a bitmap, then we can accept an
  		 * older device ... but not too old.
  		 */
41158c7eb   NeilBrown   [PATCH] md: optim...
1187
1188
  		if (ev1 < mddev->bitmap->events_cleared)
  			return 0;
07d84d109   NeilBrown   [PATCH] md: Allow...
1189
1190
1191
1192
1193
  	} else {
  		if (ev1 < mddev->events)
  			/* just a hot-add of a new device, leave raid_disk at -1 */
  			return 0;
  	}
41158c7eb   NeilBrown   [PATCH] md: optim...
1194

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1195
  	if (mddev->level != LEVEL_MULTIPATH) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1196
1197
1198
  		desc = sb->disks + rdev->desc_nr;
  
  		if (desc->state & (1<<MD_DISK_FAULTY))
b2d444d7a   NeilBrown   [PATCH] md: conve...
1199
  			set_bit(Faulty, &rdev->flags);
7c7546ccf   NeilBrown   [PATCH] md: allow...
1200
1201
  		else if (desc->state & (1<<MD_DISK_SYNC) /* &&
  			    desc->raid_disk < mddev->raid_disks */) {
b2d444d7a   NeilBrown   [PATCH] md: conve...
1202
  			set_bit(In_sync, &rdev->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1203
  			rdev->raid_disk = desc->raid_disk;
0261cd9f1   NeilBrown   md: allow v0.91 m...
1204
1205
1206
1207
1208
1209
1210
1211
  		} else if (desc->state & (1<<MD_DISK_ACTIVE)) {
  			/* active but not in sync implies recovery up to
  			 * reshape position.  We don't know exactly where
  			 * that is, so set to zero for now */
  			if (mddev->minor_version >= 91) {
  				rdev->recovery_offset = 0;
  				rdev->raid_disk = desc->raid_disk;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1212
  		}
8ddf9efe6   NeilBrown   [PATCH] md: suppo...
1213
1214
  		if (desc->state & (1<<MD_DISK_WRITEMOSTLY))
  			set_bit(WriteMostly, &rdev->flags);
41158c7eb   NeilBrown   [PATCH] md: optim...
1215
  	} else /* MULTIPATH are always insync */
b2d444d7a   NeilBrown   [PATCH] md: conve...
1216
  		set_bit(In_sync, &rdev->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1217
1218
1219
1220
1221
1222
  	return 0;
  }
  
  /*
   * sync_super for 0.90.0
   */
fd01b88c7   NeilBrown   md: remove typede...
1223
  static void super_90_sync(struct mddev *mddev, struct md_rdev *rdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1224
1225
  {
  	mdp_super_t *sb;
3cb030020   NeilBrown   md: removing type...
1226
  	struct md_rdev *rdev2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1227
  	int next_spare = mddev->raid_disks;
19133a429   NeilBrown   [PATCH] md: Remov...
1228

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
  
  	/* make rdev->sb match mddev data..
  	 *
  	 * 1/ zero out disks
  	 * 2/ Add info for each disk, keeping track of highest desc_nr (next_spare);
  	 * 3/ any empty disks < next_spare become removed
  	 *
  	 * disks[0] gets initialised to REMOVED because
  	 * we cannot be sure from other fields if it has
  	 * been initialised or not.
  	 */
  	int i;
  	int active=0, working=0,failed=0,spare=0,nr_disks=0;
611815651   NeilBrown   [PATCH] md: reall...
1242
  	rdev->sb_size = MD_SB_BYTES;
65a06f067   Namhyung Kim   md: get rid of un...
1243
  	sb = page_address(rdev->sb_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1244
1245
1246
1247
1248
  
  	memset(sb, 0, sizeof(*sb));
  
  	sb->md_magic = MD_SB_MAGIC;
  	sb->major_version = mddev->major_version;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1249
1250
1251
1252
1253
1254
1255
1256
1257
  	sb->patch_version = mddev->patch_version;
  	sb->gvalid_words  = 0; /* ignored */
  	memcpy(&sb->set_uuid0, mddev->uuid+0, 4);
  	memcpy(&sb->set_uuid1, mddev->uuid+4, 4);
  	memcpy(&sb->set_uuid2, mddev->uuid+8, 4);
  	memcpy(&sb->set_uuid3, mddev->uuid+12,4);
  
  	sb->ctime = mddev->ctime;
  	sb->level = mddev->level;
58c0fed40   Andre Noll   md: Make mddev->s...
1258
  	sb->size = mddev->dev_sectors / 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1259
1260
  	sb->raid_disks = mddev->raid_disks;
  	sb->md_minor = mddev->md_minor;
e691063a6   NeilBrown   md: support 'exte...
1261
  	sb->not_persistent = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1262
1263
1264
1265
  	sb->utime = mddev->utime;
  	sb->state = 0;
  	sb->events_hi = (mddev->events>>32);
  	sb->events_lo = (u32)mddev->events;
f67055780   NeilBrown   [PATCH] md: Check...
1266
1267
1268
1269
1270
1271
1272
1273
  	if (mddev->reshape_position == MaxSector)
  		sb->minor_version = 90;
  	else {
  		sb->minor_version = 91;
  		sb->reshape_position = mddev->reshape_position;
  		sb->new_level = mddev->new_level;
  		sb->delta_disks = mddev->delta_disks;
  		sb->new_layout = mddev->new_layout;
664e7c413   Andre Noll   md: Convert mddev...
1274
  		sb->new_chunk = mddev->new_chunk_sectors << 9;
f67055780   NeilBrown   [PATCH] md: Check...
1275
1276
  	}
  	mddev->minor_version = sb->minor_version;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
  	if (mddev->in_sync)
  	{
  		sb->recovery_cp = mddev->recovery_cp;
  		sb->cp_events_hi = (mddev->events>>32);
  		sb->cp_events_lo = (u32)mddev->events;
  		if (mddev->recovery_cp == MaxSector)
  			sb->state = (1<< MD_SB_CLEAN);
  	} else
  		sb->recovery_cp = 0;
  
  	sb->layout = mddev->layout;
9d8f03636   Andre Noll   md: Make mddev->c...
1288
  	sb->chunk_size = mddev->chunk_sectors << 9;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1289

c3d9714e8   NeilBrown   md: collect bitma...
1290
  	if (mddev->bitmap && mddev->bitmap_info.file == NULL)
a654b9d8f   NeilBrown   [PATCH] md: allow...
1291
  		sb->state |= (1<<MD_SB_BITMAP_PRESENT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1292
  	sb->disks[0].state = (1<<MD_DISK_REMOVED);
159ec1fc0   Cheng Renquan   md: use list_for_...
1293
  	list_for_each_entry(rdev2, &mddev->disks, same_set) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294
  		mdp_disk_t *d;
86e6ffdd2   NeilBrown   [PATCH] md: exten...
1295
  		int desc_nr;
0261cd9f1   NeilBrown   md: allow v0.91 m...
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
  		int is_active = test_bit(In_sync, &rdev2->flags);
  
  		if (rdev2->raid_disk >= 0 &&
  		    sb->minor_version >= 91)
  			/* we have nowhere to store the recovery_offset,
  			 * but if it is not below the reshape_position,
  			 * we can piggy-back on that.
  			 */
  			is_active = 1;
  		if (rdev2->raid_disk < 0 ||
  		    test_bit(Faulty, &rdev2->flags))
  			is_active = 0;
  		if (is_active)
86e6ffdd2   NeilBrown   [PATCH] md: exten...
1309
  			desc_nr = rdev2->raid_disk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1310
  		else
86e6ffdd2   NeilBrown   [PATCH] md: exten...
1311
  			desc_nr = next_spare++;
19133a429   NeilBrown   [PATCH] md: Remov...
1312
  		rdev2->desc_nr = desc_nr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1313
1314
1315
1316
1317
  		d = &sb->disks[rdev2->desc_nr];
  		nr_disks++;
  		d->number = rdev2->desc_nr;
  		d->major = MAJOR(rdev2->bdev->bd_dev);
  		d->minor = MINOR(rdev2->bdev->bd_dev);
0261cd9f1   NeilBrown   md: allow v0.91 m...
1318
  		if (is_active)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1319
1320
1321
  			d->raid_disk = rdev2->raid_disk;
  		else
  			d->raid_disk = rdev2->desc_nr; /* compatibility */
1be7892ff   NeilBrown   [PATCH] md: Fix t...
1322
  		if (test_bit(Faulty, &rdev2->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
  			d->state = (1<<MD_DISK_FAULTY);
0261cd9f1   NeilBrown   md: allow v0.91 m...
1324
  		else if (is_active) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1325
  			d->state = (1<<MD_DISK_ACTIVE);
0261cd9f1   NeilBrown   md: allow v0.91 m...
1326
1327
  			if (test_bit(In_sync, &rdev2->flags))
  				d->state |= (1<<MD_DISK_SYNC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1328
1329
1330
1331
1332
1333
1334
  			active++;
  			working++;
  		} else {
  			d->state = 0;
  			spare++;
  			working++;
  		}
8ddf9efe6   NeilBrown   [PATCH] md: suppo...
1335
1336
  		if (test_bit(WriteMostly, &rdev2->flags))
  			d->state |= (1<<MD_DISK_WRITEMOSTLY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1337
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
  	/* now set the "removed" and "faulty" bits on any missing devices */
  	for (i=0 ; i < mddev->raid_disks ; i++) {
  		mdp_disk_t *d = &sb->disks[i];
  		if (d->state == 0 && d->number == 0) {
  			d->number = i;
  			d->raid_disk = i;
  			d->state = (1<<MD_DISK_REMOVED);
  			d->state |= (1<<MD_DISK_FAULTY);
  			failed++;
  		}
  	}
  	sb->nr_disks = nr_disks;
  	sb->active_disks = active;
  	sb->working_disks = working;
  	sb->failed_disks = failed;
  	sb->spare_disks = spare;
  
  	sb->this_disk = sb->disks[rdev->desc_nr];
  	sb->sb_csum = calc_sb_csum(sb);
  }
  
  /*
0cd17fec9   Chris Webb   Support changing ...
1360
1361
1362
   * rdev_size_change for 0.90.0
   */
  static unsigned long long
3cb030020   NeilBrown   md: removing type...
1363
  super_90_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
0cd17fec9   Chris Webb   Support changing ...
1364
  {
58c0fed40   Andre Noll   md: Make mddev->s...
1365
  	if (num_sectors && num_sectors < rdev->mddev->dev_sectors)
0cd17fec9   Chris Webb   Support changing ...
1366
  		return 0; /* component must fit device */
c3d9714e8   NeilBrown   md: collect bitma...
1367
  	if (rdev->mddev->bitmap_info.offset)
0cd17fec9   Chris Webb   Support changing ...
1368
  		return 0; /* can't move bitmap */
57b2caa39   Jonathan Brassow   md-new-param-to-c...
1369
  	rdev->sb_start = calc_dev_sboffset(rdev);
15f4a5fdf   Andre Noll   md: Make super_ty...
1370
1371
  	if (!num_sectors || num_sectors > rdev->sb_start)
  		num_sectors = rdev->sb_start;
27a7b260f   NeilBrown   md: Fix handling ...
1372
1373
1374
1375
1376
  	/* Limit to 4TB as metadata cannot record more than that.
  	 * 4TB == 2^32 KB, or 2*2^32 sectors.
  	 */
  	if (num_sectors >= (2ULL << 32))
  		num_sectors = (2ULL << 32) - 2;
0f420358e   Andre Noll   md: Turn rdev->sb...
1377
  	md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
0cd17fec9   Chris Webb   Support changing ...
1378
1379
  		       rdev->sb_page);
  	md_super_wait(rdev->mddev);
c26a44ed1   Justin Maggard   md: fix return va...
1380
  	return num_sectors;
0cd17fec9   Chris Webb   Support changing ...
1381
1382
1383
1384
  }
  
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1385
1386
   * version 1 superblock
   */
1c05b4bc2   NeilBrown   [PATCH] md: endia...
1387
  static __le32 calc_sb_1_csum(struct mdp_superblock_1 * sb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1388
  {
1c05b4bc2   NeilBrown   [PATCH] md: endia...
1389
1390
  	__le32 disk_csum;
  	u32 csum;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1391
1392
  	unsigned long long newcsum;
  	int size = 256 + le32_to_cpu(sb->max_dev)*2;
1c05b4bc2   NeilBrown   [PATCH] md: endia...
1393
  	__le32 *isuper = (__le32*)sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1394
1395
1396
1397
1398
1399
1400
1401
1402
  	int i;
  
  	disk_csum = sb->sb_csum;
  	sb->sb_csum = 0;
  	newcsum = 0;
  	for (i=0; size>=4; size -= 4 )
  		newcsum += le32_to_cpu(*isuper++);
  
  	if (size == 2)
1c05b4bc2   NeilBrown   [PATCH] md: endia...
1403
  		newcsum += le16_to_cpu(*(__le16*) isuper);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1404
1405
1406
1407
1408
  
  	csum = (newcsum & 0xffffffff) + (newcsum >> 32);
  	sb->sb_csum = disk_csum;
  	return cpu_to_le32(csum);
  }
2699b6722   NeilBrown   md: load/store ba...
1409
1410
  static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors,
  			    int acknowledged);
3cb030020   NeilBrown   md: removing type...
1411
  static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_version)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412
1413
1414
  {
  	struct mdp_superblock_1 *sb;
  	int ret;
0f420358e   Andre Noll   md: Turn rdev->sb...
1415
  	sector_t sb_start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1416
  	char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
0002b2718   NeilBrown   [PATCH] md: limit...
1417
  	int bmask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1418
1419
  
  	/*
0f420358e   Andre Noll   md: Turn rdev->sb...
1420
  	 * Calculate the position of the superblock in 512byte sectors.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1421
1422
1423
1424
1425
1426
1427
1428
  	 * It is always aligned to a 4K boundary and
  	 * depeding on minor_version, it can be:
  	 * 0: At least 8K, but less than 12K, from end of device
  	 * 1: At start of device
  	 * 2: 4K from start of device.
  	 */
  	switch(minor_version) {
  	case 0:
77304d2ab   Mike Snitzer   block: read i_siz...
1429
  		sb_start = i_size_read(rdev->bdev->bd_inode) >> 9;
0f420358e   Andre Noll   md: Turn rdev->sb...
1430
1431
  		sb_start -= 8*2;
  		sb_start &= ~(sector_t)(4*2-1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1432
1433
  		break;
  	case 1:
0f420358e   Andre Noll   md: Turn rdev->sb...
1434
  		sb_start = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1435
1436
  		break;
  	case 2:
0f420358e   Andre Noll   md: Turn rdev->sb...
1437
  		sb_start = 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1438
1439
1440
1441
  		break;
  	default:
  		return -EINVAL;
  	}
0f420358e   Andre Noll   md: Turn rdev->sb...
1442
  	rdev->sb_start = sb_start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1443

0002b2718   NeilBrown   [PATCH] md: limit...
1444
1445
1446
1447
  	/* superblock is rarely larger than 1K, but it can be larger,
  	 * and it is safe to read 4k, so we do that
  	 */
  	ret = read_disk_sb(rdev, 4096);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1448
  	if (ret) return ret;
65a06f067   Namhyung Kim   md: get rid of un...
1449
  	sb = page_address(rdev->sb_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1450
1451
1452
1453
  
  	if (sb->magic != cpu_to_le32(MD_SB_MAGIC) ||
  	    sb->major_version != cpu_to_le32(1) ||
  	    le32_to_cpu(sb->max_dev) > (4096-256)/2 ||
0f420358e   Andre Noll   md: Turn rdev->sb...
1454
  	    le64_to_cpu(sb->super_offset) != rdev->sb_start ||
71c0805cb   NeilBrown   [PATCH] md: allow...
1455
  	    (le32_to_cpu(sb->feature_map) & ~MD_FEATURE_ALL) != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
  		return -EINVAL;
  
  	if (calc_sb_1_csum(sb) != sb->sb_csum) {
  		printk("md: invalid superblock checksum on %s
  ",
  			bdevname(rdev->bdev,b));
  		return -EINVAL;
  	}
  	if (le64_to_cpu(sb->data_size) < 10) {
  		printk("md: data_size too small on %s
  ",
  		       bdevname(rdev->bdev,b));
  		return -EINVAL;
  	}
e11e93fac   NeilBrown   md: move test for...
1470

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1471
1472
  	rdev->preferred_minor = 0xffff;
  	rdev->data_offset = le64_to_cpu(sb->data_offset);
4dbcdc751   NeilBrown   [PATCH] md: count...
1473
  	atomic_set(&rdev->corrected_errors, le32_to_cpu(sb->cnt_corrected_read));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1474

0002b2718   NeilBrown   [PATCH] md: limit...
1475
  	rdev->sb_size = le32_to_cpu(sb->max_dev) * 2 + 256;
e1defc4ff   Martin K. Petersen   block: Do away wi...
1476
  	bmask = queue_logical_block_size(rdev->bdev->bd_disk->queue)-1;
0002b2718   NeilBrown   [PATCH] md: limit...
1477
  	if (rdev->sb_size & bmask)
a1801f858   NeilBrown   md: guard against...
1478
1479
1480
  		rdev->sb_size = (rdev->sb_size | bmask) + 1;
  
  	if (minor_version
0f420358e   Andre Noll   md: Turn rdev->sb...
1481
  	    && rdev->data_offset < sb_start + (rdev->sb_size/512))
a1801f858   NeilBrown   md: guard against...
1482
  		return -EINVAL;
0002b2718   NeilBrown   [PATCH] md: limit...
1483

31b65a0d3   NeilBrown   [PATCH] md: set d...
1484
1485
1486
1487
  	if (sb->level == cpu_to_le32(LEVEL_MULTIPATH))
  		rdev->desc_nr = -1;
  	else
  		rdev->desc_nr = le32_to_cpu(sb->dev_number);
2699b6722   NeilBrown   md: load/store ba...
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
  	if (!rdev->bb_page) {
  		rdev->bb_page = alloc_page(GFP_KERNEL);
  		if (!rdev->bb_page)
  			return -ENOMEM;
  	}
  	if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BAD_BLOCKS) &&
  	    rdev->badblocks.count == 0) {
  		/* need to load the bad block list.
  		 * Currently we limit it to one page.
  		 */
  		s32 offset;
  		sector_t bb_sector;
  		u64 *bbp;
  		int i;
  		int sectors = le16_to_cpu(sb->bblog_size);
  		if (sectors > (PAGE_SIZE / 512))
  			return -EINVAL;
  		offset = le32_to_cpu(sb->bblog_offset);
  		if (offset == 0)
  			return -EINVAL;
  		bb_sector = (long long)offset;
  		if (!sync_page_io(rdev, bb_sector, sectors << 9,
  				  rdev->bb_page, READ, true))
  			return -EIO;
  		bbp = (u64 *)page_address(rdev->bb_page);
  		rdev->badblocks.shift = sb->bblog_shift;
  		for (i = 0 ; i < (sectors << (9-3)) ; i++, bbp++) {
  			u64 bb = le64_to_cpu(*bbp);
  			int count = bb & (0x3ff);
  			u64 sector = bb >> 10;
  			sector <<= sb->bblog_shift;
  			count <<= sb->bblog_shift;
  			if (bb + 1 == 0)
  				break;
  			if (md_set_badblocks(&rdev->badblocks,
  					     sector, count, 1) == 0)
  				return -EINVAL;
  		}
  	} else if (sb->bblog_offset == 0)
  		rdev->badblocks.shift = -1;
9a7b2b0f3   Harvey Harrison   md: fix integer a...
1528
  	if (!refdev) {
8ed75463b   NeilBrown   [PATCH] md: Make ...
1529
  		ret = 1;
9a7b2b0f3   Harvey Harrison   md: fix integer a...
1530
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1531
  		__u64 ev1, ev2;
65a06f067   Namhyung Kim   md: get rid of un...
1532
  		struct mdp_superblock_1 *refsb = page_address(refdev->sb_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
  
  		if (memcmp(sb->set_uuid, refsb->set_uuid, 16) != 0 ||
  		    sb->level != refsb->level ||
  		    sb->layout != refsb->layout ||
  		    sb->chunksize != refsb->chunksize) {
  			printk(KERN_WARNING "md: %s has strangely different"
  				" superblock to %s
  ",
  				bdevname(rdev->bdev,b),
  				bdevname(refdev->bdev,b2));
  			return -EINVAL;
  		}
  		ev1 = le64_to_cpu(sb->events);
  		ev2 = le64_to_cpu(refsb->events);
  
  		if (ev1 > ev2)
8ed75463b   NeilBrown   [PATCH] md: Make ...
1549
1550
1551
  			ret = 1;
  		else
  			ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1552
  	}
a1801f858   NeilBrown   md: guard against...
1553
  	if (minor_version)
77304d2ab   Mike Snitzer   block: read i_siz...
1554
  		rdev->sectors = (i_size_read(rdev->bdev->bd_inode) >> 9) -
dd8ac336c   Andre Noll   md: Represent rai...
1555
  			le64_to_cpu(sb->data_offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1556
  	else
dd8ac336c   Andre Noll   md: Represent rai...
1557
1558
  		rdev->sectors = rdev->sb_start;
  	if (rdev->sectors < le64_to_cpu(sb->data_size))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1559
  		return -EINVAL;
dd8ac336c   Andre Noll   md: Represent rai...
1560
  	rdev->sectors = le64_to_cpu(sb->data_size);
dd8ac336c   Andre Noll   md: Represent rai...
1561
  	if (le64_to_cpu(sb->size) > rdev->sectors)
2bf071bf5   NeilBrown   [PATCH] md: keep ...
1562
  		return -EINVAL;
8ed75463b   NeilBrown   [PATCH] md: Make ...
1563
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1564
  }
fd01b88c7   NeilBrown   md: remove typede...
1565
  static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1566
  {
65a06f067   Namhyung Kim   md: get rid of un...
1567
  	struct mdp_superblock_1 *sb = page_address(rdev->sb_page);
07d84d109   NeilBrown   [PATCH] md: Allow...
1568
  	__u64 ev1 = le64_to_cpu(sb->events);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1569

41158c7eb   NeilBrown   [PATCH] md: optim...
1570
  	rdev->raid_disk = -1;
c5d79adba   NeilBrown   md: allow devices...
1571
1572
1573
  	clear_bit(Faulty, &rdev->flags);
  	clear_bit(In_sync, &rdev->flags);
  	clear_bit(WriteMostly, &rdev->flags);
c5d79adba   NeilBrown   md: allow devices...
1574

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1575
1576
1577
  	if (mddev->raid_disks == 0) {
  		mddev->major_version = 1;
  		mddev->patch_version = 0;
e691063a6   NeilBrown   md: support 'exte...
1578
  		mddev->external = 0;
9d8f03636   Andre Noll   md: Make mddev->c...
1579
  		mddev->chunk_sectors = le32_to_cpu(sb->chunksize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1580
1581
1582
  		mddev->ctime = le64_to_cpu(sb->ctime) & ((1ULL << 32)-1);
  		mddev->utime = le64_to_cpu(sb->utime) & ((1ULL << 32)-1);
  		mddev->level = le32_to_cpu(sb->level);
d9d166c2a   NeilBrown   [PATCH] md: allow...
1583
  		mddev->clevel[0] = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1584
1585
  		mddev->layout = le32_to_cpu(sb->layout);
  		mddev->raid_disks = le32_to_cpu(sb->raid_disks);
58c0fed40   Andre Noll   md: Make mddev->s...
1586
  		mddev->dev_sectors = le64_to_cpu(sb->size);
07d84d109   NeilBrown   [PATCH] md: Allow...
1587
  		mddev->events = ev1;
c3d9714e8   NeilBrown   md: collect bitma...
1588
1589
  		mddev->bitmap_info.offset = 0;
  		mddev->bitmap_info.default_offset = 1024 >> 9;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1590
1591
1592
1593
1594
  		
  		mddev->recovery_cp = le64_to_cpu(sb->resync_offset);
  		memcpy(mddev->uuid, sb->set_uuid, 16);
  
  		mddev->max_disks =  (4096-256)/2;
a654b9d8f   NeilBrown   [PATCH] md: allow...
1595

71c0805cb   NeilBrown   [PATCH] md: allow...
1596
  		if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET) &&
c3d9714e8   NeilBrown   md: collect bitma...
1597
1598
1599
  		    mddev->bitmap_info.file == NULL )
  			mddev->bitmap_info.offset =
  				(__s32)le32_to_cpu(sb->bitmap_offset);
e11e93fac   NeilBrown   md: move test for...
1600

f67055780   NeilBrown   [PATCH] md: Check...
1601
1602
1603
1604
1605
  		if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) {
  			mddev->reshape_position = le64_to_cpu(sb->reshape_position);
  			mddev->delta_disks = le32_to_cpu(sb->delta_disks);
  			mddev->new_level = le32_to_cpu(sb->new_level);
  			mddev->new_layout = le32_to_cpu(sb->new_layout);
664e7c413   Andre Noll   md: Convert mddev...
1606
  			mddev->new_chunk_sectors = le32_to_cpu(sb->new_chunk);
f67055780   NeilBrown   [PATCH] md: Check...
1607
1608
1609
1610
1611
  		} else {
  			mddev->reshape_position = MaxSector;
  			mddev->delta_disks = 0;
  			mddev->new_level = mddev->level;
  			mddev->new_layout = mddev->layout;
664e7c413   Andre Noll   md: Convert mddev...
1612
  			mddev->new_chunk_sectors = mddev->chunk_sectors;
f67055780   NeilBrown   [PATCH] md: Check...
1613
  		}
41158c7eb   NeilBrown   [PATCH] md: optim...
1614
  	} else if (mddev->pers == NULL) {
be6800a73   NeilBrown   md: don't insist ...
1615
1616
  		/* Insist of good event counter while assembling, except for
  		 * spares (which don't need an event count) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1617
  		++ev1;
be6800a73   NeilBrown   md: don't insist ...
1618
1619
1620
1621
1622
  		if (rdev->desc_nr >= 0 &&
  		    rdev->desc_nr < le32_to_cpu(sb->max_dev) &&
  		    le16_to_cpu(sb->dev_roles[rdev->desc_nr]) < 0xfffe)
  			if (ev1 < mddev->events)
  				return -EINVAL;
41158c7eb   NeilBrown   [PATCH] md: optim...
1623
1624
1625
1626
  	} else if (mddev->bitmap) {
  		/* If adding to array with a bitmap, then we can accept an
  		 * older device, but not too old.
  		 */
41158c7eb   NeilBrown   [PATCH] md: optim...
1627
1628
  		if (ev1 < mddev->bitmap->events_cleared)
  			return 0;
07d84d109   NeilBrown   [PATCH] md: Allow...
1629
1630
1631
1632
1633
  	} else {
  		if (ev1 < mddev->events)
  			/* just a hot-add of a new device, leave raid_disk at -1 */
  			return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1634
1635
  	if (mddev->level != LEVEL_MULTIPATH) {
  		int role;
3673f305f   NeilBrown   md: avoid array o...
1636
1637
1638
1639
1640
1641
  		if (rdev->desc_nr < 0 ||
  		    rdev->desc_nr >= le32_to_cpu(sb->max_dev)) {
  			role = 0xffff;
  			rdev->desc_nr = -1;
  		} else
  			role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1642
1643
  		switch(role) {
  		case 0xffff: /* spare */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1644
1645
  			break;
  		case 0xfffe: /* faulty */
b2d444d7a   NeilBrown   [PATCH] md: conve...
1646
  			set_bit(Faulty, &rdev->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1647
1648
  			break;
  		default:
5fd6c1dce   NeilBrown   [PATCH] md: allow...
1649
1650
1651
1652
1653
  			if ((le32_to_cpu(sb->feature_map) &
  			     MD_FEATURE_RECOVERY_OFFSET))
  				rdev->recovery_offset = le64_to_cpu(sb->recovery_offset);
  			else
  				set_bit(In_sync, &rdev->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1654
1655
1656
  			rdev->raid_disk = role;
  			break;
  		}
8ddf9efe6   NeilBrown   [PATCH] md: suppo...
1657
1658
  		if (sb->devflags & WriteMostly1)
  			set_bit(WriteMostly, &rdev->flags);
41158c7eb   NeilBrown   [PATCH] md: optim...
1659
  	} else /* MULTIPATH are always insync */
b2d444d7a   NeilBrown   [PATCH] md: conve...
1660
  		set_bit(In_sync, &rdev->flags);
41158c7eb   NeilBrown   [PATCH] md: optim...
1661

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1662
1663
  	return 0;
  }
fd01b88c7   NeilBrown   md: remove typede...
1664
  static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1665
1666
  {
  	struct mdp_superblock_1 *sb;
3cb030020   NeilBrown   md: removing type...
1667
  	struct md_rdev *rdev2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1668
1669
  	int max_dev, i;
  	/* make rdev->sb match mddev and rdev data. */
65a06f067   Namhyung Kim   md: get rid of un...
1670
  	sb = page_address(rdev->sb_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1671
1672
1673
  
  	sb->feature_map = 0;
  	sb->pad0 = 0;
5fd6c1dce   NeilBrown   [PATCH] md: allow...
1674
  	sb->recovery_offset = cpu_to_le64(0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1675
  	memset(sb->pad1, 0, sizeof(sb->pad1));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1676
1677
1678
1679
1680
1681
1682
1683
  	memset(sb->pad3, 0, sizeof(sb->pad3));
  
  	sb->utime = cpu_to_le64((__u64)mddev->utime);
  	sb->events = cpu_to_le64(mddev->events);
  	if (mddev->in_sync)
  		sb->resync_offset = cpu_to_le64(mddev->recovery_cp);
  	else
  		sb->resync_offset = cpu_to_le64(0);
1c05b4bc2   NeilBrown   [PATCH] md: endia...
1684
  	sb->cnt_corrected_read = cpu_to_le32(atomic_read(&rdev->corrected_errors));
4dbcdc751   NeilBrown   [PATCH] md: count...
1685

f0ca340cd   NeilBrown   [PATCH] md: Make ...
1686
  	sb->raid_disks = cpu_to_le32(mddev->raid_disks);
58c0fed40   Andre Noll   md: Make mddev->s...
1687
  	sb->size = cpu_to_le64(mddev->dev_sectors);
9d8f03636   Andre Noll   md: Make mddev->c...
1688
  	sb->chunksize = cpu_to_le32(mddev->chunk_sectors);
62e1e389f   NeilBrown   md: always update...
1689
1690
  	sb->level = cpu_to_le32(mddev->level);
  	sb->layout = cpu_to_le32(mddev->layout);
f0ca340cd   NeilBrown   [PATCH] md: Make ...
1691

aeb9b2118   NeilBrown   md: ensure change...
1692
1693
1694
1695
  	if (test_bit(WriteMostly, &rdev->flags))
  		sb->devflags |= WriteMostly1;
  	else
  		sb->devflags &= ~WriteMostly1;
c3d9714e8   NeilBrown   md: collect bitma...
1696
1697
  	if (mddev->bitmap && mddev->bitmap_info.file == NULL) {
  		sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_info.offset);
71c0805cb   NeilBrown   [PATCH] md: allow...
1698
  		sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET);
a654b9d8f   NeilBrown   [PATCH] md: allow...
1699
  	}
5fd6c1dce   NeilBrown   [PATCH] md: allow...
1700
1701
  
  	if (rdev->raid_disk >= 0 &&
97e4f42d6   NeilBrown   md: occasionally ...
1702
  	    !test_bit(In_sync, &rdev->flags)) {
93be75ffd   NeilBrown   md: integrate spa...
1703
1704
1705
1706
  		sb->feature_map |=
  			cpu_to_le32(MD_FEATURE_RECOVERY_OFFSET);
  		sb->recovery_offset =
  			cpu_to_le64(rdev->recovery_offset);
5fd6c1dce   NeilBrown   [PATCH] md: allow...
1707
  	}
f67055780   NeilBrown   [PATCH] md: Check...
1708
1709
1710
1711
1712
1713
  	if (mddev->reshape_position != MaxSector) {
  		sb->feature_map |= cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE);
  		sb->reshape_position = cpu_to_le64(mddev->reshape_position);
  		sb->new_layout = cpu_to_le32(mddev->new_layout);
  		sb->delta_disks = cpu_to_le32(mddev->delta_disks);
  		sb->new_level = cpu_to_le32(mddev->new_level);
664e7c413   Andre Noll   md: Convert mddev...
1714
  		sb->new_chunk = cpu_to_le32(mddev->new_chunk_sectors);
f67055780   NeilBrown   [PATCH] md: Check...
1715
  	}
a654b9d8f   NeilBrown   [PATCH] md: allow...
1716

2699b6722   NeilBrown   md: load/store ba...
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
  	if (rdev->badblocks.count == 0)
  		/* Nothing to do for bad blocks*/ ;
  	else if (sb->bblog_offset == 0)
  		/* Cannot record bad blocks on this device */
  		md_error(mddev, rdev);
  	else {
  		struct badblocks *bb = &rdev->badblocks;
  		u64 *bbp = (u64 *)page_address(rdev->bb_page);
  		u64 *p = bb->page;
  		sb->feature_map |= cpu_to_le32(MD_FEATURE_BAD_BLOCKS);
  		if (bb->changed) {
  			unsigned seq;
  
  retry:
  			seq = read_seqbegin(&bb->lock);
  
  			memset(bbp, 0xff, PAGE_SIZE);
  
  			for (i = 0 ; i < bb->count ; i++) {
  				u64 internal_bb = *p++;
  				u64 store_bb = ((BB_OFFSET(internal_bb) << 10)
  						| BB_LEN(internal_bb));
  				*bbp++ = cpu_to_le64(store_bb);
  			}
  			if (read_seqretry(&bb->lock, seq))
  				goto retry;
  
  			bb->sector = (rdev->sb_start +
  				      (int)le32_to_cpu(sb->bblog_offset));
  			bb->size = le16_to_cpu(sb->bblog_size);
  			bb->changed = 0;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1750
  	max_dev = 0;
159ec1fc0   Cheng Renquan   md: use list_for_...
1751
  	list_for_each_entry(rdev2, &mddev->disks, same_set)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1752
1753
  		if (rdev2->desc_nr+1 > max_dev)
  			max_dev = rdev2->desc_nr+1;
a778b73ff   NeilBrown   md: fix bug with ...
1754

70471dafe   NeilBrown   md: Handle growth...
1755
1756
  	if (max_dev > le32_to_cpu(sb->max_dev)) {
  		int bmask;
a778b73ff   NeilBrown   md: fix bug with ...
1757
  		sb->max_dev = cpu_to_le32(max_dev);
70471dafe   NeilBrown   md: Handle growth...
1758
1759
1760
1761
  		rdev->sb_size = max_dev * 2 + 256;
  		bmask = queue_logical_block_size(rdev->bdev->bd_disk->queue)-1;
  		if (rdev->sb_size & bmask)
  			rdev->sb_size = (rdev->sb_size | bmask) + 1;
ddcf3522c   NeilBrown   md: fix v1.x meta...
1762
1763
  	} else
  		max_dev = le32_to_cpu(sb->max_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1764
1765
1766
  	for (i=0; i<max_dev;i++)
  		sb->dev_roles[i] = cpu_to_le16(0xfffe);
  	
159ec1fc0   Cheng Renquan   md: use list_for_...
1767
  	list_for_each_entry(rdev2, &mddev->disks, same_set) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1768
  		i = rdev2->desc_nr;
b2d444d7a   NeilBrown   [PATCH] md: conve...
1769
  		if (test_bit(Faulty, &rdev2->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1770
  			sb->dev_roles[i] = cpu_to_le16(0xfffe);
b2d444d7a   NeilBrown   [PATCH] md: conve...
1771
  		else if (test_bit(In_sync, &rdev2->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1772
  			sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk);
93be75ffd   NeilBrown   md: integrate spa...
1773
  		else if (rdev2->raid_disk >= 0)
5fd6c1dce   NeilBrown   [PATCH] md: allow...
1774
  			sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1775
1776
1777
  		else
  			sb->dev_roles[i] = cpu_to_le16(0xffff);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1778
1779
  	sb->sb_csum = calc_sb_1_csum(sb);
  }
0cd17fec9   Chris Webb   Support changing ...
1780
  static unsigned long long
3cb030020   NeilBrown   md: removing type...
1781
  super_1_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
0cd17fec9   Chris Webb   Support changing ...
1782
1783
  {
  	struct mdp_superblock_1 *sb;
15f4a5fdf   Andre Noll   md: Make super_ty...
1784
  	sector_t max_sectors;
58c0fed40   Andre Noll   md: Make mddev->s...
1785
  	if (num_sectors && num_sectors < rdev->mddev->dev_sectors)
0cd17fec9   Chris Webb   Support changing ...
1786
  		return 0; /* component must fit device */
0f420358e   Andre Noll   md: Turn rdev->sb...
1787
  	if (rdev->sb_start < rdev->data_offset) {
0cd17fec9   Chris Webb   Support changing ...
1788
  		/* minor versions 1 and 2; superblock before data */
77304d2ab   Mike Snitzer   block: read i_siz...
1789
  		max_sectors = i_size_read(rdev->bdev->bd_inode) >> 9;
15f4a5fdf   Andre Noll   md: Make super_ty...
1790
1791
1792
  		max_sectors -= rdev->data_offset;
  		if (!num_sectors || num_sectors > max_sectors)
  			num_sectors = max_sectors;
c3d9714e8   NeilBrown   md: collect bitma...
1793
  	} else if (rdev->mddev->bitmap_info.offset) {
0cd17fec9   Chris Webb   Support changing ...
1794
1795
1796
1797
  		/* minor version 0 with bitmap we can't move */
  		return 0;
  	} else {
  		/* minor version 0; superblock after data */
0f420358e   Andre Noll   md: Turn rdev->sb...
1798
  		sector_t sb_start;
77304d2ab   Mike Snitzer   block: read i_siz...
1799
  		sb_start = (i_size_read(rdev->bdev->bd_inode) >> 9) - 8*2;
0f420358e   Andre Noll   md: Turn rdev->sb...
1800
  		sb_start &= ~(sector_t)(4*2 - 1);
dd8ac336c   Andre Noll   md: Represent rai...
1801
  		max_sectors = rdev->sectors + sb_start - rdev->sb_start;
15f4a5fdf   Andre Noll   md: Make super_ty...
1802
1803
  		if (!num_sectors || num_sectors > max_sectors)
  			num_sectors = max_sectors;
0f420358e   Andre Noll   md: Turn rdev->sb...
1804
  		rdev->sb_start = sb_start;
0cd17fec9   Chris Webb   Support changing ...
1805
  	}
65a06f067   Namhyung Kim   md: get rid of un...
1806
  	sb = page_address(rdev->sb_page);
15f4a5fdf   Andre Noll   md: Make super_ty...
1807
  	sb->data_size = cpu_to_le64(num_sectors);
0f420358e   Andre Noll   md: Turn rdev->sb...
1808
  	sb->super_offset = rdev->sb_start;
0cd17fec9   Chris Webb   Support changing ...
1809
  	sb->sb_csum = calc_sb_1_csum(sb);
0f420358e   Andre Noll   md: Turn rdev->sb...
1810
  	md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
0cd17fec9   Chris Webb   Support changing ...
1811
1812
  		       rdev->sb_page);
  	md_super_wait(rdev->mddev);
c26a44ed1   Justin Maggard   md: fix return va...
1813
  	return num_sectors;
0cd17fec9   Chris Webb   Support changing ...
1814
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1815

75c96f858   Adrian Bunk   [PATCH] make some...
1816
  static struct super_type super_types[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1817
1818
1819
  	[0] = {
  		.name	= "0.90.0",
  		.owner	= THIS_MODULE,
0cd17fec9   Chris Webb   Support changing ...
1820
1821
1822
1823
  		.load_super	    = super_90_load,
  		.validate_super	    = super_90_validate,
  		.sync_super	    = super_90_sync,
  		.rdev_size_change   = super_90_rdev_size_change,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1824
1825
1826
1827
  	},
  	[1] = {
  		.name	= "md-1",
  		.owner	= THIS_MODULE,
0cd17fec9   Chris Webb   Support changing ...
1828
1829
1830
1831
  		.load_super	    = super_1_load,
  		.validate_super	    = super_1_validate,
  		.sync_super	    = super_1_sync,
  		.rdev_size_change   = super_1_rdev_size_change,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1832
1833
  	},
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1834

fd01b88c7   NeilBrown   md: remove typede...
1835
  static void sync_super(struct mddev *mddev, struct md_rdev *rdev)
076f968b3   Jonathan Brassow   MD: add sync_supe...
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
  {
  	if (mddev->sync_super) {
  		mddev->sync_super(mddev, rdev);
  		return;
  	}
  
  	BUG_ON(mddev->major_version >= ARRAY_SIZE(super_types));
  
  	super_types[mddev->major_version].sync_super(mddev, rdev);
  }
fd01b88c7   NeilBrown   md: remove typede...
1846
  static int match_mddev_units(struct mddev *mddev1, struct mddev *mddev2)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1847
  {
3cb030020   NeilBrown   md: removing type...
1848
  	struct md_rdev *rdev, *rdev2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1849

4b80991c6   NeilBrown   md: Protect acces...
1850
1851
1852
  	rcu_read_lock();
  	rdev_for_each_rcu(rdev, mddev1)
  		rdev_for_each_rcu(rdev2, mddev2)
7dd5e7c3d   NeilBrown   [PATCH] md: move ...
1853
  			if (rdev->bdev->bd_contains ==
4b80991c6   NeilBrown   md: Protect acces...
1854
1855
  			    rdev2->bdev->bd_contains) {
  				rcu_read_unlock();
7dd5e7c3d   NeilBrown   [PATCH] md: move ...
1856
  				return 1;
4b80991c6   NeilBrown   md: Protect acces...
1857
1858
  			}
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1859
1860
1861
1862
  	return 0;
  }
  
  static LIST_HEAD(pending_raid_disks);
ac5e7113e   Andre Noll   md: Push down dat...
1863
1864
1865
1866
1867
1868
1869
  /*
   * Try to register data integrity profile for an mddev
   *
   * This is called when an array is started and after a disk has been kicked
   * from the array. It only succeeds if all working and active component devices
   * are integrity capable with matching profiles.
   */
fd01b88c7   NeilBrown   md: remove typede...
1870
  int md_integrity_register(struct mddev *mddev)
ac5e7113e   Andre Noll   md: Push down dat...
1871
  {
3cb030020   NeilBrown   md: removing type...
1872
  	struct md_rdev *rdev, *reference = NULL;
ac5e7113e   Andre Noll   md: Push down dat...
1873
1874
1875
  
  	if (list_empty(&mddev->disks))
  		return 0; /* nothing to do */
629acb6ab   Jonathan Brassow   MD: no integrity ...
1876
1877
  	if (!mddev->gendisk || blk_get_integrity(mddev->gendisk))
  		return 0; /* shouldn't register, or already is */
ac5e7113e   Andre Noll   md: Push down dat...
1878
1879
1880
1881
1882
1883
  	list_for_each_entry(rdev, &mddev->disks, same_set) {
  		/* skip spares and non-functional disks */
  		if (test_bit(Faulty, &rdev->flags))
  			continue;
  		if (rdev->raid_disk < 0)
  			continue;
ac5e7113e   Andre Noll   md: Push down dat...
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
  		if (!reference) {
  			/* Use the first rdev as the reference */
  			reference = rdev;
  			continue;
  		}
  		/* does this rdev's profile match the reference profile? */
  		if (blk_integrity_compare(reference->bdev->bd_disk,
  				rdev->bdev->bd_disk) < 0)
  			return -EINVAL;
  	}
89078d572   Martin K. Petersen   md: Fix integrity...
1894
1895
  	if (!reference || !bdev_get_integrity(reference->bdev))
  		return 0;
ac5e7113e   Andre Noll   md: Push down dat...
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
  	/*
  	 * All component devices are integrity capable and have matching
  	 * profiles, register the common profile for the md device.
  	 */
  	if (blk_integrity_register(mddev->gendisk,
  			bdev_get_integrity(reference->bdev)) != 0) {
  		printk(KERN_ERR "md: failed to register integrity for %s
  ",
  			mdname(mddev));
  		return -EINVAL;
  	}
a91a2785b   Martin K. Petersen   block: Require su...
1907
1908
1909
1910
1911
1912
1913
1914
  	printk(KERN_NOTICE "md: data integrity enabled on %s
  ", mdname(mddev));
  	if (bioset_integrity_create(mddev->bio_set, BIO_POOL_SIZE)) {
  		printk(KERN_ERR "md: failed to create integrity pool for %s
  ",
  		       mdname(mddev));
  		return -EINVAL;
  	}
ac5e7113e   Andre Noll   md: Push down dat...
1915
1916
1917
1918
1919
  	return 0;
  }
  EXPORT_SYMBOL(md_integrity_register);
  
  /* Disable data integrity if non-capable/non-matching disk is being added */
fd01b88c7   NeilBrown   md: remove typede...
1920
  void md_integrity_add_rdev(struct md_rdev *rdev, struct mddev *mddev)
3f9d99c12   Martin K. Petersen   MD data integrity...
1921
  {
3f9d99c12   Martin K. Petersen   MD data integrity...
1922
  	struct blk_integrity *bi_rdev = bdev_get_integrity(rdev->bdev);
ac5e7113e   Andre Noll   md: Push down dat...
1923
  	struct blk_integrity *bi_mddev = blk_get_integrity(mddev->gendisk);
3f9d99c12   Martin K. Petersen   MD data integrity...
1924

ac5e7113e   Andre Noll   md: Push down dat...
1925
  	if (!bi_mddev) /* nothing to do */
3f9d99c12   Martin K. Petersen   MD data integrity...
1926
  		return;
ac5e7113e   Andre Noll   md: Push down dat...
1927
  	if (rdev->raid_disk < 0) /* skip spares */
3f9d99c12   Martin K. Petersen   MD data integrity...
1928
  		return;
ac5e7113e   Andre Noll   md: Push down dat...
1929
1930
1931
1932
1933
1934
  	if (bi_rdev && blk_integrity_compare(mddev->gendisk,
  					     rdev->bdev->bd_disk) >= 0)
  		return;
  	printk(KERN_NOTICE "disabling data integrity on %s
  ", mdname(mddev));
  	blk_integrity_unregister(mddev->gendisk);
3f9d99c12   Martin K. Petersen   MD data integrity...
1935
  }
ac5e7113e   Andre Noll   md: Push down dat...
1936
  EXPORT_SYMBOL(md_integrity_add_rdev);
3f9d99c12   Martin K. Petersen   MD data integrity...
1937

fd01b88c7   NeilBrown   md: remove typede...
1938
  static int bind_rdev_to_array(struct md_rdev * rdev, struct mddev * mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1939
  {
7dd5e7c3d   NeilBrown   [PATCH] md: move ...
1940
  	char b[BDEVNAME_SIZE];
f637b9f9f   NeilBrown   [PATCH] md: make ...
1941
  	struct kobject *ko;
1edf80d34   Neil Brown   [PATCH] md: remov...
1942
  	char *s;
5e55e2f5f   NeilBrown   [PATCH] md: conve...
1943
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1944
1945
1946
1947
1948
  
  	if (rdev->mddev) {
  		MD_BUG();
  		return -EINVAL;
  	}
11e2ede02   Dan Williams   md: prevent dupli...
1949
1950
1951
1952
  
  	/* prevent duplicates */
  	if (find_rdev(mddev, rdev->bdev->bd_dev))
  		return -EEXIST;
dd8ac336c   Andre Noll   md: Represent rai...
1953
1954
1955
  	/* make sure rdev->sectors exceeds mddev->dev_sectors */
  	if (rdev->sectors && (mddev->dev_sectors == 0 ||
  			rdev->sectors < mddev->dev_sectors)) {
a778b73ff   NeilBrown   md: fix bug with ...
1956
1957
1958
1959
1960
1961
1962
1963
  		if (mddev->pers) {
  			/* Cannot change size, so fail
  			 * If mddev->level <= 0, then we don't care
  			 * about aligning sizes (e.g. linear)
  			 */
  			if (mddev->level > 0)
  				return -ENOSPC;
  		} else
dd8ac336c   Andre Noll   md: Represent rai...
1964
  			mddev->dev_sectors = rdev->sectors;
2bf071bf5   NeilBrown   [PATCH] md: keep ...
1965
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
  
  	/* Verify rdev->desc_nr is unique.
  	 * If it is -1, assign a free number, else
  	 * check number is not in use
  	 */
  	if (rdev->desc_nr < 0) {
  		int choice = 0;
  		if (mddev->pers) choice = mddev->raid_disks;
  		while (find_rdev_nr(mddev, choice))
  			choice++;
  		rdev->desc_nr = choice;
  	} else {
  		if (find_rdev_nr(mddev, rdev->desc_nr))
  			return -EBUSY;
  	}
de01dfadf   NeilBrown   md: Ensure an md ...
1981
1982
1983
1984
1985
1986
  	if (mddev->max_disks && rdev->desc_nr >= mddev->max_disks) {
  		printk(KERN_WARNING "md: %s: array is limited to %d devices
  ",
  		       mdname(mddev), mddev->max_disks);
  		return -EBUSY;
  	}
19133a429   NeilBrown   [PATCH] md: Remov...
1987
  	bdevname(rdev->bdev,b);
649316b25   Greg Kroah-Hartman   Kobject: convert ...
1988
  	while ( (s=strchr(b, '/')) != NULL)
1edf80d34   Neil Brown   [PATCH] md: remov...
1989
  		*s = '!';
649316b25   Greg Kroah-Hartman   Kobject: convert ...
1990

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1991
  	rdev->mddev = mddev;
19133a429   NeilBrown   [PATCH] md: Remov...
1992
1993
  	printk(KERN_INFO "md: bind<%s>
  ", b);
86e6ffdd2   NeilBrown   [PATCH] md: exten...
1994

b2d6db587   Greg Kroah-Hartman   Kobject: rename k...
1995
  	if ((err = kobject_add(&rdev->kobj, &mddev->kobj, "dev-%s", b)))
5e55e2f5f   NeilBrown   [PATCH] md: conve...
1996
  		goto fail;
86e6ffdd2   NeilBrown   [PATCH] md: exten...
1997

0762b8bde   Tejun Heo   block: always set...
1998
  	ko = &part_to_dev(rdev->bdev->bd_part)->kobj;
00bcb4ac7   NeilBrown   md: reduce depend...
1999
2000
2001
  	if (sysfs_create_link(&rdev->kobj, ko, "block"))
  		/* failure here is OK */;
  	rdev->sysfs_state = sysfs_get_dirent_safe(rdev->kobj.sd, "state");
3c0ee63a6   NeilBrown   md: use sysfs_not...
2002

4b80991c6   NeilBrown   md: Protect acces...
2003
  	list_add_rcu(&rdev->same_set, &mddev->disks);
e09b457bd   Tejun Heo   block: simplify h...
2004
  	bd_link_disk_holder(rdev->bdev, mddev->gendisk);
4044ba58d   NeilBrown   md: don't retry r...
2005
2006
  
  	/* May as well allow recovery to be retried once */
5389042ff   NeilBrown   md: change manage...
2007
  	mddev->recovery_disabled++;
3f9d99c12   Martin K. Petersen   MD data integrity...
2008

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2009
  	return 0;
5e55e2f5f   NeilBrown   [PATCH] md: conve...
2010
2011
2012
2013
2014
2015
  
   fail:
  	printk(KERN_WARNING "md: failed to register dev-%s for %s
  ",
  	       b, mdname(mddev));
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2016
  }
177a99b23   NeilBrown   md: fix use-after...
2017
  static void md_delayed_delete(struct work_struct *ws)
5792a2856   NeilBrown   [PATCH] md: avoid...
2018
  {
3cb030020   NeilBrown   md: removing type...
2019
  	struct md_rdev *rdev = container_of(ws, struct md_rdev, del_work);
5792a2856   NeilBrown   [PATCH] md: avoid...
2020
  	kobject_del(&rdev->kobj);
177a99b23   NeilBrown   md: fix use-after...
2021
  	kobject_put(&rdev->kobj);
5792a2856   NeilBrown   [PATCH] md: avoid...
2022
  }
3cb030020   NeilBrown   md: removing type...
2023
  static void unbind_rdev_from_array(struct md_rdev * rdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2024
2025
2026
2027
2028
2029
  {
  	char b[BDEVNAME_SIZE];
  	if (!rdev->mddev) {
  		MD_BUG();
  		return;
  	}
49731baa4   Tejun Heo   block: restore mu...
2030
  	bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk);
4b80991c6   NeilBrown   md: Protect acces...
2031
  	list_del_rcu(&rdev->same_set);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2032
2033
2034
  	printk(KERN_INFO "md: unbind<%s>
  ", bdevname(rdev->bdev,b));
  	rdev->mddev = NULL;
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2035
  	sysfs_remove_link(&rdev->kobj, "block");
3c0ee63a6   NeilBrown   md: use sysfs_not...
2036
2037
  	sysfs_put(rdev->sysfs_state);
  	rdev->sysfs_state = NULL;
2230dfe4c   NeilBrown   md: beginnings of...
2038
2039
2040
  	kfree(rdev->badblocks.page);
  	rdev->badblocks.count = 0;
  	rdev->badblocks.page = NULL;
5792a2856   NeilBrown   [PATCH] md: avoid...
2041
  	/* We need to delay this, otherwise we can deadlock when
4b80991c6   NeilBrown   md: Protect acces...
2042
2043
  	 * writing to 'remove' to "dev/state".  We also need
  	 * to delay it due to rcu usage.
5792a2856   NeilBrown   [PATCH] md: avoid...
2044
  	 */
4b80991c6   NeilBrown   md: Protect acces...
2045
  	synchronize_rcu();
177a99b23   NeilBrown   md: fix use-after...
2046
2047
  	INIT_WORK(&rdev->del_work, md_delayed_delete);
  	kobject_get(&rdev->kobj);
e804ac780   Tejun Heo   md: fix and updat...
2048
  	queue_work(md_misc_wq, &rdev->del_work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2049
2050
2051
2052
2053
2054
2055
  }
  
  /*
   * prevent the device from being mounted, repartitioned or
   * otherwise reused by a RAID array (or any other kernel
   * subsystem), by bd_claiming the device.
   */
3cb030020   NeilBrown   md: removing type...
2056
  static int lock_rdev(struct md_rdev *rdev, dev_t dev, int shared)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2057
2058
2059
2060
  {
  	int err = 0;
  	struct block_device *bdev;
  	char b[BDEVNAME_SIZE];
d4d776299   Tejun Heo   block: clean up b...
2061
  	bdev = blkdev_get_by_dev(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL,
3cb030020   NeilBrown   md: removing type...
2062
  				 shared ? (struct md_rdev *)lock_rdev : rdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2063
2064
2065
2066
2067
2068
  	if (IS_ERR(bdev)) {
  		printk(KERN_ERR "md: could not open %s.
  ",
  			__bdevname(dev, b));
  		return PTR_ERR(bdev);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2069
2070
2071
  	rdev->bdev = bdev;
  	return err;
  }
3cb030020   NeilBrown   md: removing type...
2072
  static void unlock_rdev(struct md_rdev *rdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2073
2074
2075
2076
2077
  {
  	struct block_device *bdev = rdev->bdev;
  	rdev->bdev = NULL;
  	if (!bdev)
  		MD_BUG();
e525fd89d   Tejun Heo   block: make blkde...
2078
  	blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2079
2080
2081
  }
  
  void md_autodetect_dev(dev_t dev);
3cb030020   NeilBrown   md: removing type...
2082
  static void export_rdev(struct md_rdev * rdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2083
2084
2085
2086
2087
2088
2089
2090
  {
  	char b[BDEVNAME_SIZE];
  	printk(KERN_INFO "md: export_rdev(%s)
  ",
  		bdevname(rdev->bdev,b));
  	if (rdev->mddev)
  		MD_BUG();
  	free_disk_sb(rdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2091
  #ifndef MODULE
d0fae18f1   NeilBrown   md: clean up irre...
2092
2093
  	if (test_bit(AutoDetected, &rdev->flags))
  		md_autodetect_dev(rdev->bdev->bd_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2094
2095
  #endif
  	unlock_rdev(rdev);
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2096
  	kobject_put(&rdev->kobj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2097
  }
3cb030020   NeilBrown   md: removing type...
2098
  static void kick_rdev_from_array(struct md_rdev * rdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2099
2100
2101
2102
  {
  	unbind_rdev_from_array(rdev);
  	export_rdev(rdev);
  }
fd01b88c7   NeilBrown   md: remove typede...
2103
  static void export_array(struct mddev *mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2104
  {
3cb030020   NeilBrown   md: removing type...
2105
  	struct md_rdev *rdev, *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2106

d089c6af1   NeilBrown   md: change ITERAT...
2107
  	rdev_for_each(rdev, tmp, mddev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
  		if (!rdev->mddev) {
  			MD_BUG();
  			continue;
  		}
  		kick_rdev_from_array(rdev);
  	}
  	if (!list_empty(&mddev->disks))
  		MD_BUG();
  	mddev->raid_disks = 0;
  	mddev->major_version = 0;
  }
  
  static void print_desc(mdp_disk_t *desc)
  {
  	printk(" DISK<N:%d,(%d,%d),R:%d,S:%d>
  ", desc->number,
  		desc->major,desc->minor,desc->raid_disk,desc->state);
  }
cd2ac9321   Cheng Renquan   md: need another ...
2126
  static void print_sb_90(mdp_super_t *sb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
  {
  	int i;
  
  	printk(KERN_INFO 
  		"md:  SB: (V:%d.%d.%d) ID:<%08x.%08x.%08x.%08x> CT:%08x
  ",
  		sb->major_version, sb->minor_version, sb->patch_version,
  		sb->set_uuid0, sb->set_uuid1, sb->set_uuid2, sb->set_uuid3,
  		sb->ctime);
  	printk(KERN_INFO "md:     L%d S%08d ND:%d RD:%d md%d LO:%d CS:%d
  ",
  		sb->level, sb->size, sb->nr_disks, sb->raid_disks,
  		sb->md_minor, sb->layout, sb->chunk_size);
  	printk(KERN_INFO "md:     UT:%08x ST:%d AD:%d WD:%d"
  		" FD:%d SD:%d CSUM:%08x E:%08lx
  ",
  		sb->utime, sb->state, sb->active_disks, sb->working_disks,
  		sb->failed_disks, sb->spare_disks,
  		sb->sb_csum, (unsigned long)sb->events_lo);
  
  	printk(KERN_INFO);
  	for (i = 0; i < MD_SB_DISKS; i++) {
  		mdp_disk_t *desc;
  
  		desc = sb->disks + i;
  		if (desc->number || desc->major || desc->minor ||
  		    desc->raid_disk || (desc->state && (desc->state != 4))) {
  			printk("     D %2d: ", i);
  			print_desc(desc);
  		}
  	}
  	printk(KERN_INFO "md:     THIS: ");
  	print_desc(&sb->this_disk);
cd2ac9321   Cheng Renquan   md: need another ...
2160
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2161

cd2ac9321   Cheng Renquan   md: need another ...
2162
2163
2164
2165
2166
  static void print_sb_1(struct mdp_superblock_1 *sb)
  {
  	__u8 *uuid;
  
  	uuid = sb->set_uuid;
ad361c988   Joe Perches   Remove multiple K...
2167
  	printk(KERN_INFO
7b75c2f8c   Joe Perches   drivers/md/md.c: ...
2168
2169
  	       "md:  SB: (V:%u) (F:0x%08x) Array-ID:<%pU>
  "
ad361c988   Joe Perches   Remove multiple K...
2170
2171
  	       "md:    Name: \"%s\" CT:%llu
  ",
cd2ac9321   Cheng Renquan   md: need another ...
2172
2173
  		le32_to_cpu(sb->major_version),
  		le32_to_cpu(sb->feature_map),
7b75c2f8c   Joe Perches   drivers/md/md.c: ...
2174
  		uuid,
cd2ac9321   Cheng Renquan   md: need another ...
2175
2176
2177
2178
2179
  		sb->set_name,
  		(unsigned long long)le64_to_cpu(sb->ctime)
  		       & MD_SUPERBLOCK_1_TIME_SEC_MASK);
  
  	uuid = sb->device_uuid;
ad361c988   Joe Perches   Remove multiple K...
2180
2181
  	printk(KERN_INFO
  	       "md:       L%u SZ%llu RD:%u LO:%u CS:%u DO:%llu DS:%llu SO:%llu"
cd2ac9321   Cheng Renquan   md: need another ...
2182
2183
  			" RO:%llu
  "
7b75c2f8c   Joe Perches   drivers/md/md.c: ...
2184
2185
  	       "md:     Dev:%08x UUID: %pU
  "
ad361c988   Joe Perches   Remove multiple K...
2186
2187
2188
2189
  	       "md:       (F:0x%08x) UT:%llu Events:%llu ResyncOffset:%llu CSUM:0x%08x
  "
  	       "md:         (MaxDev:%u) 
  ",
cd2ac9321   Cheng Renquan   md: need another ...
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
  		le32_to_cpu(sb->level),
  		(unsigned long long)le64_to_cpu(sb->size),
  		le32_to_cpu(sb->raid_disks),
  		le32_to_cpu(sb->layout),
  		le32_to_cpu(sb->chunksize),
  		(unsigned long long)le64_to_cpu(sb->data_offset),
  		(unsigned long long)le64_to_cpu(sb->data_size),
  		(unsigned long long)le64_to_cpu(sb->super_offset),
  		(unsigned long long)le64_to_cpu(sb->recovery_offset),
  		le32_to_cpu(sb->dev_number),
7b75c2f8c   Joe Perches   drivers/md/md.c: ...
2200
  		uuid,
cd2ac9321   Cheng Renquan   md: need another ...
2201
2202
2203
2204
2205
2206
2207
  		sb->devflags,
  		(unsigned long long)le64_to_cpu(sb->utime) & MD_SUPERBLOCK_1_TIME_SEC_MASK,
  		(unsigned long long)le64_to_cpu(sb->events),
  		(unsigned long long)le64_to_cpu(sb->resync_offset),
  		le32_to_cpu(sb->sb_csum),
  		le32_to_cpu(sb->max_dev)
  		);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2208
  }
3cb030020   NeilBrown   md: removing type...
2209
  static void print_rdev(struct md_rdev *rdev, int major_version)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2210
2211
  {
  	char b[BDEVNAME_SIZE];
dd8ac336c   Andre Noll   md: Represent rai...
2212
2213
2214
  	printk(KERN_INFO "md: rdev %s, Sect:%08llu F:%d S:%d DN:%u
  ",
  		bdevname(rdev->bdev, b), (unsigned long long)rdev->sectors,
b2d444d7a   NeilBrown   [PATCH] md: conve...
2215
2216
  	        test_bit(Faulty, &rdev->flags), test_bit(In_sync, &rdev->flags),
  	        rdev->desc_nr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2217
  	if (rdev->sb_loaded) {
cd2ac9321   Cheng Renquan   md: need another ...
2218
2219
2220
2221
  		printk(KERN_INFO "md: rdev superblock (MJ:%d):
  ", major_version);
  		switch (major_version) {
  		case 0:
65a06f067   Namhyung Kim   md: get rid of un...
2222
  			print_sb_90(page_address(rdev->sb_page));
cd2ac9321   Cheng Renquan   md: need another ...
2223
2224
  			break;
  		case 1:
65a06f067   Namhyung Kim   md: get rid of un...
2225
  			print_sb_1(page_address(rdev->sb_page));
cd2ac9321   Cheng Renquan   md: need another ...
2226
2227
  			break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2228
2229
2230
2231
  	} else
  		printk(KERN_INFO "md: no rdev superblock!
  ");
  }
5e56341d0   Adrian Bunk   [PATCH] md: make ...
2232
  static void md_print_devices(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2233
  {
159ec1fc0   Cheng Renquan   md: use list_for_...
2234
  	struct list_head *tmp;
3cb030020   NeilBrown   md: removing type...
2235
  	struct md_rdev *rdev;
fd01b88c7   NeilBrown   md: remove typede...
2236
  	struct mddev *mddev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
  	char b[BDEVNAME_SIZE];
  
  	printk("
  ");
  	printk("md:	**********************************
  ");
  	printk("md:	* <COMPLETE RAID STATE PRINTOUT> *
  ");
  	printk("md:	**********************************
  ");
29ac4aa3f   NeilBrown   md: change INTERA...
2247
  	for_each_mddev(mddev, tmp) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2248

32a7627cf   NeilBrown   [PATCH] md: optim...
2249
2250
2251
2252
  		if (mddev->bitmap)
  			bitmap_print_sb(mddev->bitmap);
  		else
  			printk("%s: ", mdname(mddev));
159ec1fc0   Cheng Renquan   md: use list_for_...
2253
  		list_for_each_entry(rdev, &mddev->disks, same_set)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2254
2255
2256
  			printk("<%s>", bdevname(rdev->bdev,b));
  		printk("
  ");
159ec1fc0   Cheng Renquan   md: use list_for_...
2257
  		list_for_each_entry(rdev, &mddev->disks, same_set)
cd2ac9321   Cheng Renquan   md: need another ...
2258
  			print_rdev(rdev, mddev->major_version);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2259
2260
2261
2262
2263
2264
  	}
  	printk("md:	**********************************
  ");
  	printk("
  ");
  }
fd01b88c7   NeilBrown   md: remove typede...
2265
  static void sync_sbs(struct mddev * mddev, int nospares)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2266
  {
425437691   NeilBrown   [PATCH] md: Don't...
2267
2268
2269
2270
2271
2272
  	/* Update each superblock (in-memory image), but
  	 * if we are allowed to, skip spares which already
  	 * have the right event counter, or have one earlier
  	 * (which would mean they aren't being marked as dirty
  	 * with the rest of the array)
  	 */
3cb030020   NeilBrown   md: removing type...
2273
  	struct md_rdev *rdev;
159ec1fc0   Cheng Renquan   md: use list_for_...
2274
  	list_for_each_entry(rdev, &mddev->disks, same_set) {
425437691   NeilBrown   [PATCH] md: Don't...
2275
2276
2277
  		if (rdev->sb_events == mddev->events ||
  		    (nospares &&
  		     rdev->raid_disk < 0 &&
425437691   NeilBrown   [PATCH] md: Don't...
2278
2279
2280
2281
  		     rdev->sb_events+1 == mddev->events)) {
  			/* Don't update this superblock */
  			rdev->sb_loaded = 2;
  		} else {
076f968b3   Jonathan Brassow   MD: add sync_supe...
2282
  			sync_super(mddev, rdev);
425437691   NeilBrown   [PATCH] md: Don't...
2283
2284
  			rdev->sb_loaded = 1;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2285
2286
  	}
  }
fd01b88c7   NeilBrown   md: remove typede...
2287
  static void md_update_sb(struct mddev * mddev, int force_change)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2288
  {
3cb030020   NeilBrown   md: removing type...
2289
  	struct md_rdev *rdev;
06d91a5fe   NeilBrown   [PATCH] md: impro...
2290
  	int sync_req;
425437691   NeilBrown   [PATCH] md: Don't...
2291
  	int nospares = 0;
2699b6722   NeilBrown   md: load/store ba...
2292
  	int any_badblocks_changed = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2293

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2294
  repeat:
3a3a5ddb7   NeilBrown   Update recovery_o...
2295
2296
2297
2298
2299
2300
2301
2302
2303
  	/* First make sure individual recovery_offsets are correct */
  	list_for_each_entry(rdev, &mddev->disks, same_set) {
  		if (rdev->raid_disk >= 0 &&
  		    mddev->delta_disks >= 0 &&
  		    !test_bit(In_sync, &rdev->flags) &&
  		    mddev->curr_resync_completed > rdev->recovery_offset)
  				rdev->recovery_offset = mddev->curr_resync_completed;
  
  	}	
bd52b7462   Dan Williams   md: don't clear M...
2304
  	if (!mddev->persistent) {
070dc6dd7   NeilBrown   md: resolve confu...
2305
  		clear_bit(MD_CHANGE_CLEAN, &mddev->flags);
3a3a5ddb7   NeilBrown   Update recovery_o...
2306
  		clear_bit(MD_CHANGE_DEVS, &mddev->flags);
de393cdea   NeilBrown   md: make it easie...
2307
  		if (!mddev->external) {
d97a41dc9   NeilBrown   md: Fix regressio...
2308
  			clear_bit(MD_CHANGE_PENDING, &mddev->flags);
de393cdea   NeilBrown   md: make it easie...
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
  			list_for_each_entry(rdev, &mddev->disks, same_set) {
  				if (rdev->badblocks.changed) {
  					md_ack_all_badblocks(&rdev->badblocks);
  					md_error(mddev, rdev);
  				}
  				clear_bit(Blocked, &rdev->flags);
  				clear_bit(BlockedBadBlocks, &rdev->flags);
  				wake_up(&rdev->blocked_wait);
  			}
  		}
3a3a5ddb7   NeilBrown   Update recovery_o...
2319
2320
2321
  		wake_up(&mddev->sb_wait);
  		return;
  	}
a9701a304   NeilBrown   [PATCH] md: suppo...
2322
  	spin_lock_irq(&mddev->write_lock);
846921959   NeilBrown   [PATCH] md: avoid...
2323

3a3a5ddb7   NeilBrown   Update recovery_o...
2324
  	mddev->utime = get_seconds();
850b2b420   NeilBrown   [PATCH] md: repla...
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
  	if (test_and_clear_bit(MD_CHANGE_DEVS, &mddev->flags))
  		force_change = 1;
  	if (test_and_clear_bit(MD_CHANGE_CLEAN, &mddev->flags))
  		/* just a clean<-> dirty transition, possibly leave spares alone,
  		 * though if events isn't the right even/odd, we will have to do
  		 * spares after all
  		 */
  		nospares = 1;
  	if (force_change)
  		nospares = 0;
  	if (mddev->degraded)
846921959   NeilBrown   [PATCH] md: avoid...
2336
2337
2338
2339
2340
2341
2342
2343
2344
  		/* If the array is degraded, then skipping spares is both
  		 * dangerous and fairly pointless.
  		 * Dangerous because a device that was removed from the array
  		 * might have a event_count that still looks up-to-date,
  		 * so it can be re-added without a resync.
  		 * Pointless because if there are any spares to skip,
  		 * then a recovery will happen and soon that array won't
  		 * be degraded any more and the spare can go back to sleep then.
  		 */
850b2b420   NeilBrown   [PATCH] md: repla...
2345
  		nospares = 0;
846921959   NeilBrown   [PATCH] md: avoid...
2346

06d91a5fe   NeilBrown   [PATCH] md: impro...
2347
  	sync_req = mddev->in_sync;
425437691   NeilBrown   [PATCH] md: Don't...
2348
2349
2350
  
  	/* If this is just a dirty<->clean transition, and the array is clean
  	 * and 'events' is odd, we can roll back to the previous clean state */
850b2b420   NeilBrown   [PATCH] md: repla...
2351
  	if (nospares
425437691   NeilBrown   [PATCH] md: Don't...
2352
  	    && (mddev->in_sync && mddev->recovery_cp == MaxSector)
a8707c08f   NeilBrown   md: simplify upda...
2353
2354
  	    && mddev->can_decrease_events
  	    && mddev->events != 1) {
425437691   NeilBrown   [PATCH] md: Don't...
2355
  		mddev->events--;
a8707c08f   NeilBrown   md: simplify upda...
2356
2357
  		mddev->can_decrease_events = 0;
  	} else {
425437691   NeilBrown   [PATCH] md: Don't...
2358
2359
  		/* otherwise we have to go forward and ... */
  		mddev->events ++;
a8707c08f   NeilBrown   md: simplify upda...
2360
  		mddev->can_decrease_events = nospares;
425437691   NeilBrown   [PATCH] md: Don't...
2361
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
  
  	if (!mddev->events) {
  		/*
  		 * oops, this 64-bit counter should never wrap.
  		 * Either we are in around ~1 trillion A.C., assuming
  		 * 1 reboot per second, or we have a bug:
  		 */
  		MD_BUG();
  		mddev->events --;
  	}
2699b6722   NeilBrown   md: load/store ba...
2372

de393cdea   NeilBrown   md: make it easie...
2373
  	list_for_each_entry(rdev, &mddev->disks, same_set) {
2699b6722   NeilBrown   md: load/store ba...
2374
2375
  		if (rdev->badblocks.changed)
  			any_badblocks_changed++;
de393cdea   NeilBrown   md: make it easie...
2376
2377
2378
  		if (test_bit(Faulty, &rdev->flags))
  			set_bit(FaultRecorded, &rdev->flags);
  	}
2699b6722   NeilBrown   md: load/store ba...
2379

e691063a6   NeilBrown   md: support 'exte...
2380
  	sync_sbs(mddev, nospares);
a9701a304   NeilBrown   [PATCH] md: suppo...
2381
  	spin_unlock_irq(&mddev->write_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2382

36a4e1fe0   NeilBrown   md: remove PRINTK...
2383
2384
2385
  	pr_debug("md: updating %s RAID superblock on device (in sync %d)
  ",
  		 mdname(mddev), mddev->in_sync);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2386

4ad136637   NeilBrown   md: change bitmap...
2387
  	bitmap_update_sb(mddev->bitmap);
159ec1fc0   Cheng Renquan   md: use list_for_...
2388
  	list_for_each_entry(rdev, &mddev->disks, same_set) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2389
  		char b[BDEVNAME_SIZE];
36a4e1fe0   NeilBrown   md: remove PRINTK...
2390

425437691   NeilBrown   [PATCH] md: Don't...
2391
2392
  		if (rdev->sb_loaded != 1)
  			continue; /* no noise on spare devices */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2393

d70ed2e4f   Andrei Warkentin   MD: Allow restart...
2394
2395
  		if (!test_bit(Faulty, &rdev->flags) &&
  		    rdev->saved_raid_disk == -1) {
7bfa19f27   NeilBrown   [PATCH] md: allow...
2396
  			md_super_write(mddev,rdev,
0f420358e   Andre Noll   md: Turn rdev->sb...
2397
  				       rdev->sb_start, rdev->sb_size,
7bfa19f27   NeilBrown   [PATCH] md: allow...
2398
  				       rdev->sb_page);
36a4e1fe0   NeilBrown   md: remove PRINTK...
2399
2400
2401
2402
  			pr_debug("md: (write) %s's sb offset: %llu
  ",
  				 bdevname(rdev->bdev, b),
  				 (unsigned long long)rdev->sb_start);
425437691   NeilBrown   [PATCH] md: Don't...
2403
  			rdev->sb_events = mddev->events;
2699b6722   NeilBrown   md: load/store ba...
2404
2405
2406
2407
2408
2409
2410
  			if (rdev->badblocks.size) {
  				md_super_write(mddev, rdev,
  					       rdev->badblocks.sector,
  					       rdev->badblocks.size << 9,
  					       rdev->bb_page);
  				rdev->badblocks.size = 0;
  			}
7bfa19f27   NeilBrown   [PATCH] md: allow...
2411

d70ed2e4f   Andrei Warkentin   MD: Allow restart...
2412
  		} else if (test_bit(Faulty, &rdev->flags))
36a4e1fe0   NeilBrown   md: remove PRINTK...
2413
2414
2415
  			pr_debug("md: %s (skipping faulty)
  ",
  				 bdevname(rdev->bdev, b));
d70ed2e4f   Andrei Warkentin   MD: Allow restart...
2416
2417
  		else
  			pr_debug("(skipping incremental s/r ");
7bfa19f27   NeilBrown   [PATCH] md: allow...
2418
  		if (mddev->level == LEVEL_MULTIPATH)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2419
2420
2421
  			/* only need to write one superblock... */
  			break;
  	}
a9701a304   NeilBrown   [PATCH] md: suppo...
2422
  	md_super_wait(mddev);
850b2b420   NeilBrown   [PATCH] md: repla...
2423
  	/* if there was a failure, MD_CHANGE_DEVS was set, and we re-write super */
7bfa19f27   NeilBrown   [PATCH] md: allow...
2424

a9701a304   NeilBrown   [PATCH] md: suppo...
2425
  	spin_lock_irq(&mddev->write_lock);
850b2b420   NeilBrown   [PATCH] md: repla...
2426
2427
  	if (mddev->in_sync != sync_req ||
  	    test_bit(MD_CHANGE_DEVS, &mddev->flags)) {
06d91a5fe   NeilBrown   [PATCH] md: impro...
2428
  		/* have to write it out again */
a9701a304   NeilBrown   [PATCH] md: suppo...
2429
  		spin_unlock_irq(&mddev->write_lock);
06d91a5fe   NeilBrown   [PATCH] md: impro...
2430
2431
  		goto repeat;
  	}
850b2b420   NeilBrown   [PATCH] md: repla...
2432
  	clear_bit(MD_CHANGE_PENDING, &mddev->flags);
a9701a304   NeilBrown   [PATCH] md: suppo...
2433
  	spin_unlock_irq(&mddev->write_lock);
3d310eb7b   NeilBrown   [PATCH] md: fix d...
2434
  	wake_up(&mddev->sb_wait);
acb180b0e   NeilBrown   md: improve usefu...
2435
2436
  	if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
  		sysfs_notify(&mddev->kobj, NULL, "sync_completed");
06d91a5fe   NeilBrown   [PATCH] md: impro...
2437

de393cdea   NeilBrown   md: make it easie...
2438
2439
2440
2441
2442
  	list_for_each_entry(rdev, &mddev->disks, same_set) {
  		if (test_and_clear_bit(FaultRecorded, &rdev->flags))
  			clear_bit(Blocked, &rdev->flags);
  
  		if (any_badblocks_changed)
2699b6722   NeilBrown   md: load/store ba...
2443
  			md_ack_all_badblocks(&rdev->badblocks);
de393cdea   NeilBrown   md: make it easie...
2444
2445
2446
  		clear_bit(BlockedBadBlocks, &rdev->flags);
  		wake_up(&rdev->blocked_wait);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2447
  }
7f6ce7692   Andre Noll   md: Fix a typo in...
2448
2449
  /* words written to sysfs files may, or may not, be 
   terminated.
bce74dac0   NeilBrown   [PATCH] md: helpe...
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
   * We want to accept with case. For this we use cmd_match.
   */
  static int cmd_match(const char *cmd, const char *str)
  {
  	/* See if cmd, written into a sysfs file, matches
  	 * str.  They must either be the same, or cmd can
  	 * have a trailing newline
  	 */
  	while (*cmd && *str && *cmd == *str) {
  		cmd++;
  		str++;
  	}
  	if (*cmd == '
  ')
  		cmd++;
  	if (*str || *cmd)
  		return 0;
  	return 1;
  }
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2469
2470
  struct rdev_sysfs_entry {
  	struct attribute attr;
3cb030020   NeilBrown   md: removing type...
2471
2472
  	ssize_t (*show)(struct md_rdev *, char *);
  	ssize_t (*store)(struct md_rdev *, const char *, size_t);
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2473
2474
2475
  };
  
  static ssize_t
3cb030020   NeilBrown   md: removing type...
2476
  state_show(struct md_rdev *rdev, char *page)
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2477
2478
  {
  	char *sep = "";
20a49ff67   NeilBrown   md: change a few ...
2479
  	size_t len = 0;
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2480

de393cdea   NeilBrown   md: make it easie...
2481
2482
  	if (test_bit(Faulty, &rdev->flags) ||
  	    rdev->badblocks.unacked_exist) {
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2483
2484
2485
  		len+= sprintf(page+len, "%sfaulty",sep);
  		sep = ",";
  	}
b2d444d7a   NeilBrown   [PATCH] md: conve...
2486
  	if (test_bit(In_sync, &rdev->flags)) {
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2487
2488
2489
  		len += sprintf(page+len, "%sin_sync",sep);
  		sep = ",";
  	}
f655675b3   NeilBrown   [PATCH] md: Allow...
2490
2491
2492
2493
  	if (test_bit(WriteMostly, &rdev->flags)) {
  		len += sprintf(page+len, "%swrite_mostly",sep);
  		sep = ",";
  	}
de393cdea   NeilBrown   md: make it easie...
2494
  	if (test_bit(Blocked, &rdev->flags) ||
52c64152a   NeilBrown   md: bad blocks sh...
2495
2496
  	    (rdev->badblocks.unacked_exist
  	     && !test_bit(Faulty, &rdev->flags))) {
6bfe0b499   Dan Williams   md: support block...
2497
2498
2499
  		len += sprintf(page+len, "%sblocked", sep);
  		sep = ",";
  	}
b2d444d7a   NeilBrown   [PATCH] md: conve...
2500
2501
  	if (!test_bit(Faulty, &rdev->flags) &&
  	    !test_bit(In_sync, &rdev->flags)) {
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2502
2503
2504
  		len += sprintf(page+len, "%sspare", sep);
  		sep = ",";
  	}
d7a9d443b   NeilBrown   md: add 'write_er...
2505
2506
2507
2508
  	if (test_bit(WriteErrorSeen, &rdev->flags)) {
  		len += sprintf(page+len, "%swrite_error", sep);
  		sep = ",";
  	}
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2509
2510
2511
  	return len+sprintf(page+len, "
  ");
  }
45dc2de1e   NeilBrown   [PATCH] md: Allow...
2512
  static ssize_t
3cb030020   NeilBrown   md: removing type...
2513
  state_store(struct md_rdev *rdev, const char *buf, size_t len)
45dc2de1e   NeilBrown   [PATCH] md: Allow...
2514
2515
  {
  	/* can write
de393cdea   NeilBrown   md: make it easie...
2516
  	 *  faulty  - simulates an error
45dc2de1e   NeilBrown   [PATCH] md: Allow...
2517
  	 *  remove  - disconnects the device
f655675b3   NeilBrown   [PATCH] md: Allow...
2518
2519
  	 *  writemostly - sets write_mostly
  	 *  -writemostly - clears write_mostly
de393cdea   NeilBrown   md: make it easie...
2520
2521
  	 *  blocked - sets the Blocked flags
  	 *  -blocked - clears the Blocked and possibly simulates an error
6d56e2784   NeilBrown   md: allow setting...
2522
  	 *  insync - sets Insync providing device isn't active
d7a9d443b   NeilBrown   md: add 'write_er...
2523
2524
  	 *  write_error - sets WriteErrorSeen
  	 *  -write_error - clears WriteErrorSeen
45dc2de1e   NeilBrown   [PATCH] md: Allow...
2525
2526
2527
2528
  	 */
  	int err = -EINVAL;
  	if (cmd_match(buf, "faulty") && rdev->mddev->pers) {
  		md_error(rdev->mddev, rdev);
5ef56c8fe   NeilBrown   md: report failur...
2529
2530
2531
2532
  		if (test_bit(Faulty, &rdev->flags))
  			err = 0;
  		else
  			err = -EBUSY;
45dc2de1e   NeilBrown   [PATCH] md: Allow...
2533
2534
2535
2536
  	} else if (cmd_match(buf, "remove")) {
  		if (rdev->raid_disk >= 0)
  			err = -EBUSY;
  		else {
fd01b88c7   NeilBrown   md: remove typede...
2537
  			struct mddev *mddev = rdev->mddev;
45dc2de1e   NeilBrown   [PATCH] md: Allow...
2538
  			kick_rdev_from_array(rdev);
3f9d7b0d8   NeilBrown   [PATCH] md: fix a...
2539
2540
  			if (mddev->pers)
  				md_update_sb(mddev, 1);
45dc2de1e   NeilBrown   [PATCH] md: Allow...
2541
2542
2543
  			md_new_event(mddev);
  			err = 0;
  		}
f655675b3   NeilBrown   [PATCH] md: Allow...
2544
2545
2546
2547
2548
2549
  	} else if (cmd_match(buf, "writemostly")) {
  		set_bit(WriteMostly, &rdev->flags);
  		err = 0;
  	} else if (cmd_match(buf, "-writemostly")) {
  		clear_bit(WriteMostly, &rdev->flags);
  		err = 0;
6bfe0b499   Dan Williams   md: support block...
2550
2551
2552
2553
  	} else if (cmd_match(buf, "blocked")) {
  		set_bit(Blocked, &rdev->flags);
  		err = 0;
  	} else if (cmd_match(buf, "-blocked")) {
de393cdea   NeilBrown   md: make it easie...
2554
  		if (!test_bit(Faulty, &rdev->flags) &&
7da64a0ab   NeilBrown   md: fix clearing ...
2555
  		    rdev->badblocks.unacked_exist) {
de393cdea   NeilBrown   md: make it easie...
2556
2557
2558
2559
2560
  			/* metadata handler doesn't understand badblocks,
  			 * so we need to fail the device
  			 */
  			md_error(rdev->mddev, rdev);
  		}
6bfe0b499   Dan Williams   md: support block...
2561
  		clear_bit(Blocked, &rdev->flags);
de393cdea   NeilBrown   md: make it easie...
2562
  		clear_bit(BlockedBadBlocks, &rdev->flags);
6bfe0b499   Dan Williams   md: support block...
2563
2564
2565
2566
2567
  		wake_up(&rdev->blocked_wait);
  		set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
  		md_wakeup_thread(rdev->mddev->thread);
  
  		err = 0;
6d56e2784   NeilBrown   md: allow setting...
2568
2569
2570
  	} else if (cmd_match(buf, "insync") && rdev->raid_disk == -1) {
  		set_bit(In_sync, &rdev->flags);
  		err = 0;
d7a9d443b   NeilBrown   md: add 'write_er...
2571
2572
2573
2574
2575
2576
  	} else if (cmd_match(buf, "write_error")) {
  		set_bit(WriteErrorSeen, &rdev->flags);
  		err = 0;
  	} else if (cmd_match(buf, "-write_error")) {
  		clear_bit(WriteErrorSeen, &rdev->flags);
  		err = 0;
45dc2de1e   NeilBrown   [PATCH] md: Allow...
2577
  	}
00bcb4ac7   NeilBrown   md: reduce depend...
2578
2579
  	if (!err)
  		sysfs_notify_dirent_safe(rdev->sysfs_state);
45dc2de1e   NeilBrown   [PATCH] md: Allow...
2580
2581
  	return err ? err : len;
  }
80ca3a44f   NeilBrown   [PATCH] md: unify...
2582
2583
  static struct rdev_sysfs_entry rdev_state =
  __ATTR(state, S_IRUGO|S_IWUSR, state_show, state_store);
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2584
2585
  
  static ssize_t
3cb030020   NeilBrown   md: removing type...
2586
  errors_show(struct md_rdev *rdev, char *page)
4dbcdc751   NeilBrown   [PATCH] md: count...
2587
2588
2589
2590
2591
2592
  {
  	return sprintf(page, "%d
  ", atomic_read(&rdev->corrected_errors));
  }
  
  static ssize_t
3cb030020   NeilBrown   md: removing type...
2593
  errors_store(struct md_rdev *rdev, const char *buf, size_t len)
4dbcdc751   NeilBrown   [PATCH] md: count...
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
  {
  	char *e;
  	unsigned long n = simple_strtoul(buf, &e, 10);
  	if (*buf && (*e == 0 || *e == '
  ')) {
  		atomic_set(&rdev->corrected_errors, n);
  		return len;
  	}
  	return -EINVAL;
  }
  static struct rdev_sysfs_entry rdev_errors =
80ca3a44f   NeilBrown   [PATCH] md: unify...
2605
  __ATTR(errors, S_IRUGO|S_IWUSR, errors_show, errors_store);
4dbcdc751   NeilBrown   [PATCH] md: count...
2606

014236d2b   NeilBrown   [PATCH] md: expos...
2607
  static ssize_t
3cb030020   NeilBrown   md: removing type...
2608
  slot_show(struct md_rdev *rdev, char *page)
014236d2b   NeilBrown   [PATCH] md: expos...
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
  {
  	if (rdev->raid_disk < 0)
  		return sprintf(page, "none
  ");
  	else
  		return sprintf(page, "%d
  ", rdev->raid_disk);
  }
  
  static ssize_t
3cb030020   NeilBrown   md: removing type...
2619
  slot_store(struct md_rdev *rdev, const char *buf, size_t len)
014236d2b   NeilBrown   [PATCH] md: expos...
2620
2621
  {
  	char *e;
c303da6d7   NeilBrown   md: give userspac...
2622
  	int err;
014236d2b   NeilBrown   [PATCH] md: expos...
2623
2624
2625
2626
2627
2628
  	int slot = simple_strtoul(buf, &e, 10);
  	if (strncmp(buf, "none", 4)==0)
  		slot = -1;
  	else if (e==buf || (*e && *e!= '
  '))
  		return -EINVAL;
6c2fce2ef   Neil Brown   Support adding a ...
2629
  	if (rdev->mddev->pers && slot == -1) {
c303da6d7   NeilBrown   md: give userspac...
2630
2631
2632
2633
2634
2635
2636
  		/* Setting 'slot' on an active array requires also
  		 * updating the 'rd%d' link, and communicating
  		 * with the personality with ->hot_*_disk.
  		 * For now we only support removing
  		 * failed/spare devices.  This normally happens automatically,
  		 * but not when the metadata is externally managed.
  		 */
c303da6d7   NeilBrown   md: give userspac...
2637
2638
2639
  		if (rdev->raid_disk == -1)
  			return -EEXIST;
  		/* personality does all needed checks */
01393f3d5   Namhyung Kim   md: check ->hot_r...
2640
  		if (rdev->mddev->pers->hot_remove_disk == NULL)
c303da6d7   NeilBrown   md: give userspac...
2641
2642
2643
2644
2645
  			return -EINVAL;
  		err = rdev->mddev->pers->
  			hot_remove_disk(rdev->mddev, rdev->raid_disk);
  		if (err)
  			return err;
36fad858a   Namhyung Kim   md: introduce lin...
2646
  		sysfs_unlink_rdev(rdev->mddev, rdev);
b71031076   Maciej Trela   md: Correctly han...
2647
  		rdev->raid_disk = -1;
c303da6d7   NeilBrown   md: give userspac...
2648
2649
  		set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
  		md_wakeup_thread(rdev->mddev->thread);
6c2fce2ef   Neil Brown   Support adding a ...
2650
  	} else if (rdev->mddev->pers) {
3cb030020   NeilBrown   md: removing type...
2651
  		struct md_rdev *rdev2;
6c2fce2ef   Neil Brown   Support adding a ...
2652
  		/* Activating a spare .. or possibly reactivating
6d56e2784   NeilBrown   md: allow setting...
2653
  		 * if we ever get bitmaps working here.
6c2fce2ef   Neil Brown   Support adding a ...
2654
2655
2656
2657
  		 */
  
  		if (rdev->raid_disk != -1)
  			return -EBUSY;
c6751b2bd   NeilBrown   md: Don't allow s...
2658
2659
  		if (test_bit(MD_RECOVERY_RUNNING, &rdev->mddev->recovery))
  			return -EBUSY;
6c2fce2ef   Neil Brown   Support adding a ...
2660
2661
  		if (rdev->mddev->pers->hot_add_disk == NULL)
  			return -EINVAL;
159ec1fc0   Cheng Renquan   md: use list_for_...
2662
  		list_for_each_entry(rdev2, &rdev->mddev->disks, same_set)
6c2fce2ef   Neil Brown   Support adding a ...
2663
2664
  			if (rdev2->raid_disk == slot)
  				return -EEXIST;
ba1b41b6b   NeilBrown   md: range check s...
2665
2666
2667
  		if (slot >= rdev->mddev->raid_disks &&
  		    slot >= rdev->mddev->raid_disks + rdev->mddev->delta_disks)
  			return -ENOSPC;
6c2fce2ef   Neil Brown   Support adding a ...
2668
2669
2670
2671
2672
  		rdev->raid_disk = slot;
  		if (test_bit(In_sync, &rdev->flags))
  			rdev->saved_raid_disk = slot;
  		else
  			rdev->saved_raid_disk = -1;
d30519fc5   NeilBrown   md: clear In_sync...
2673
  		clear_bit(In_sync, &rdev->flags);
6c2fce2ef   Neil Brown   Support adding a ...
2674
2675
  		err = rdev->mddev->pers->
  			hot_add_disk(rdev->mddev, rdev);
199050ea1   Neil Brown   rationalise retur...
2676
  		if (err) {
6c2fce2ef   Neil Brown   Support adding a ...
2677
  			rdev->raid_disk = -1;
6c2fce2ef   Neil Brown   Support adding a ...
2678
  			return err;
526647320   Neil Brown   Make sure all cha...
2679
  		} else
00bcb4ac7   NeilBrown   md: reduce depend...
2680
  			sysfs_notify_dirent_safe(rdev->sysfs_state);
36fad858a   Namhyung Kim   md: introduce lin...
2681
  		if (sysfs_link_rdev(rdev->mddev, rdev))
00bcb4ac7   NeilBrown   md: reduce depend...
2682
  			/* failure here is OK */;
6c2fce2ef   Neil Brown   Support adding a ...
2683
  		/* don't wakeup anyone, leave that to userspace. */
c303da6d7   NeilBrown   md: give userspac...
2684
  	} else {
ba1b41b6b   NeilBrown   md: range check s...
2685
2686
  		if (slot >= rdev->mddev->raid_disks &&
  		    slot >= rdev->mddev->raid_disks + rdev->mddev->delta_disks)
c303da6d7   NeilBrown   md: give userspac...
2687
2688
2689
  			return -ENOSPC;
  		rdev->raid_disk = slot;
  		/* assume it is working */
c5d79adba   NeilBrown   md: allow devices...
2690
2691
  		clear_bit(Faulty, &rdev->flags);
  		clear_bit(WriteMostly, &rdev->flags);
c303da6d7   NeilBrown   md: give userspac...
2692
  		set_bit(In_sync, &rdev->flags);
00bcb4ac7   NeilBrown   md: reduce depend...
2693
  		sysfs_notify_dirent_safe(rdev->sysfs_state);
c303da6d7   NeilBrown   md: give userspac...
2694
  	}
014236d2b   NeilBrown   [PATCH] md: expos...
2695
2696
2697
2698
2699
  	return len;
  }
  
  
  static struct rdev_sysfs_entry rdev_slot =
80ca3a44f   NeilBrown   [PATCH] md: unify...
2700
  __ATTR(slot, S_IRUGO|S_IWUSR, slot_show, slot_store);
014236d2b   NeilBrown   [PATCH] md: expos...
2701

93c8cad03   NeilBrown   [PATCH] md: expor...
2702
  static ssize_t
3cb030020   NeilBrown   md: removing type...
2703
  offset_show(struct md_rdev *rdev, char *page)
93c8cad03   NeilBrown   [PATCH] md: expor...
2704
  {
6961ece46   Andrew Morton   [PATCH] md-export...
2705
2706
  	return sprintf(page, "%llu
  ", (unsigned long long)rdev->data_offset);
93c8cad03   NeilBrown   [PATCH] md: expor...
2707
2708
2709
  }
  
  static ssize_t
3cb030020   NeilBrown   md: removing type...
2710
  offset_store(struct md_rdev *rdev, const char *buf, size_t len)
93c8cad03   NeilBrown   [PATCH] md: expor...
2711
2712
2713
2714
2715
2716
  {
  	char *e;
  	unsigned long long offset = simple_strtoull(buf, &e, 10);
  	if (e==buf || (*e && *e != '
  '))
  		return -EINVAL;
8ed0a5216   Neil Brown   Enable setting of...
2717
  	if (rdev->mddev->pers && rdev->raid_disk >= 0)
93c8cad03   NeilBrown   [PATCH] md: expor...
2718
  		return -EBUSY;
dd8ac336c   Andre Noll   md: Represent rai...
2719
  	if (rdev->sectors && rdev->mddev->external)
c5d79adba   NeilBrown   md: allow devices...
2720
2721
2722
  		/* Must set offset before size, so overlap checks
  		 * can be sane */
  		return -EBUSY;
93c8cad03   NeilBrown   [PATCH] md: expor...
2723
2724
2725
2726
2727
  	rdev->data_offset = offset;
  	return len;
  }
  
  static struct rdev_sysfs_entry rdev_offset =
80ca3a44f   NeilBrown   [PATCH] md: unify...
2728
  __ATTR(offset, S_IRUGO|S_IWUSR, offset_show, offset_store);
93c8cad03   NeilBrown   [PATCH] md: expor...
2729

83303b613   NeilBrown   [PATCH] md: allow...
2730
  static ssize_t
3cb030020   NeilBrown   md: removing type...
2731
  rdev_size_show(struct md_rdev *rdev, char *page)
83303b613   NeilBrown   [PATCH] md: allow...
2732
  {
dd8ac336c   Andre Noll   md: Represent rai...
2733
2734
  	return sprintf(page, "%llu
  ", (unsigned long long)rdev->sectors / 2);
83303b613   NeilBrown   [PATCH] md: allow...
2735
  }
c5d79adba   NeilBrown   md: allow devices...
2736
2737
2738
2739
2740
2741
2742
2743
2744
  static int overlaps(sector_t s1, sector_t l1, sector_t s2, sector_t l2)
  {
  	/* check if two start/length pairs overlap */
  	if (s1+l1 <= s2)
  		return 0;
  	if (s2+l2 <= s1)
  		return 0;
  	return 1;
  }
b522adcde   Dan Williams   md: 'array_size' ...
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
  static int strict_blocks_to_sectors(const char *buf, sector_t *sectors)
  {
  	unsigned long long blocks;
  	sector_t new;
  
  	if (strict_strtoull(buf, 10, &blocks) < 0)
  		return -EINVAL;
  
  	if (blocks & 1ULL << (8 * sizeof(blocks) - 1))
  		return -EINVAL; /* sector conversion overflow */
  
  	new = blocks * 2;
  	if (new != blocks * 2)
  		return -EINVAL; /* unsigned long long to sector_t overflow */
  
  	*sectors = new;
  	return 0;
  }
83303b613   NeilBrown   [PATCH] md: allow...
2763
  static ssize_t
3cb030020   NeilBrown   md: removing type...
2764
  rdev_size_store(struct md_rdev *rdev, const char *buf, size_t len)
83303b613   NeilBrown   [PATCH] md: allow...
2765
  {
fd01b88c7   NeilBrown   md: remove typede...
2766
  	struct mddev *my_mddev = rdev->mddev;
dd8ac336c   Andre Noll   md: Represent rai...
2767
  	sector_t oldsectors = rdev->sectors;
b522adcde   Dan Williams   md: 'array_size' ...
2768
  	sector_t sectors;
27c529bb8   NeilBrown   md: lock access t...
2769

b522adcde   Dan Williams   md: 'array_size' ...
2770
  	if (strict_blocks_to_sectors(buf, &sectors) < 0)
d7027458d   Neil Brown   md: Tidy up rdev_...
2771
  		return -EINVAL;
0cd17fec9   Chris Webb   Support changing ...
2772
  	if (my_mddev->pers && rdev->raid_disk >= 0) {
d7027458d   Neil Brown   md: Tidy up rdev_...
2773
  		if (my_mddev->persistent) {
dd8ac336c   Andre Noll   md: Represent rai...
2774
2775
2776
  			sectors = super_types[my_mddev->major_version].
  				rdev_size_change(rdev, sectors);
  			if (!sectors)
0cd17fec9   Chris Webb   Support changing ...
2777
  				return -EBUSY;
dd8ac336c   Andre Noll   md: Represent rai...
2778
  		} else if (!sectors)
77304d2ab   Mike Snitzer   block: read i_siz...
2779
  			sectors = (i_size_read(rdev->bdev->bd_inode) >> 9) -
dd8ac336c   Andre Noll   md: Represent rai...
2780
  				rdev->data_offset;
0cd17fec9   Chris Webb   Support changing ...
2781
  	}
dd8ac336c   Andre Noll   md: Represent rai...
2782
  	if (sectors < my_mddev->dev_sectors)
7d3c6f871   Chris Webb   md: Fix rdev_size...
2783
  		return -EINVAL; /* component must fit device */
0cd17fec9   Chris Webb   Support changing ...
2784

dd8ac336c   Andre Noll   md: Represent rai...
2785
2786
  	rdev->sectors = sectors;
  	if (sectors > oldsectors && my_mddev->external) {
c5d79adba   NeilBrown   md: allow devices...
2787
2788
  		/* need to check that all other rdevs with the same ->bdev
  		 * do not overlap.  We need to unlock the mddev to avoid
dd8ac336c   Andre Noll   md: Represent rai...
2789
  		 * a deadlock.  We have already changed rdev->sectors, and if
c5d79adba   NeilBrown   md: allow devices...
2790
2791
  		 * we have to change it back, we will have the lock again.
  		 */
fd01b88c7   NeilBrown   md: remove typede...
2792
  		struct mddev *mddev;
c5d79adba   NeilBrown   md: allow devices...
2793
  		int overlap = 0;
159ec1fc0   Cheng Renquan   md: use list_for_...
2794
  		struct list_head *tmp;
c5d79adba   NeilBrown   md: allow devices...
2795

27c529bb8   NeilBrown   md: lock access t...
2796
  		mddev_unlock(my_mddev);
29ac4aa3f   NeilBrown   md: change INTERA...
2797
  		for_each_mddev(mddev, tmp) {
3cb030020   NeilBrown   md: removing type...
2798
  			struct md_rdev *rdev2;
c5d79adba   NeilBrown   md: allow devices...
2799
2800
  
  			mddev_lock(mddev);
159ec1fc0   Cheng Renquan   md: use list_for_...
2801
  			list_for_each_entry(rdev2, &mddev->disks, same_set)
f21e9ff7f   NeilBrown   md: Remove the Al...
2802
2803
2804
2805
2806
  				if (rdev->bdev == rdev2->bdev &&
  				    rdev != rdev2 &&
  				    overlaps(rdev->data_offset, rdev->sectors,
  					     rdev2->data_offset,
  					     rdev2->sectors)) {
c5d79adba   NeilBrown   md: allow devices...
2807
2808
2809
2810
2811
2812
2813
2814
2815
  					overlap = 1;
  					break;
  				}
  			mddev_unlock(mddev);
  			if (overlap) {
  				mddev_put(mddev);
  				break;
  			}
  		}
27c529bb8   NeilBrown   md: lock access t...
2816
  		mddev_lock(my_mddev);
c5d79adba   NeilBrown   md: allow devices...
2817
2818
2819
  		if (overlap) {
  			/* Someone else could have slipped in a size
  			 * change here, but doing so is just silly.
dd8ac336c   Andre Noll   md: Represent rai...
2820
  			 * We put oldsectors back because we *know* it is
c5d79adba   NeilBrown   md: allow devices...
2821
2822
2823
  			 * safe, and trust userspace not to race with
  			 * itself
  			 */
dd8ac336c   Andre Noll   md: Represent rai...
2824
  			rdev->sectors = oldsectors;
c5d79adba   NeilBrown   md: allow devices...
2825
2826
2827
  			return -EBUSY;
  		}
  	}
83303b613   NeilBrown   [PATCH] md: allow...
2828
2829
2830
2831
  	return len;
  }
  
  static struct rdev_sysfs_entry rdev_size =
80ca3a44f   NeilBrown   [PATCH] md: unify...
2832
  __ATTR(size, S_IRUGO|S_IWUSR, rdev_size_show, rdev_size_store);
83303b613   NeilBrown   [PATCH] md: allow...
2833

06e3c817b   Dan Williams   md: add 'recovery...
2834

3cb030020   NeilBrown   md: removing type...
2835
  static ssize_t recovery_start_show(struct md_rdev *rdev, char *page)
06e3c817b   Dan Williams   md: add 'recovery...
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
  {
  	unsigned long long recovery_start = rdev->recovery_offset;
  
  	if (test_bit(In_sync, &rdev->flags) ||
  	    recovery_start == MaxSector)
  		return sprintf(page, "none
  ");
  
  	return sprintf(page, "%llu
  ", recovery_start);
  }
3cb030020   NeilBrown   md: removing type...
2847
  static ssize_t recovery_start_store(struct md_rdev *rdev, const char *buf, size_t len)
06e3c817b   Dan Williams   md: add 'recovery...
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
  {
  	unsigned long long recovery_start;
  
  	if (cmd_match(buf, "none"))
  		recovery_start = MaxSector;
  	else if (strict_strtoull(buf, 10, &recovery_start))
  		return -EINVAL;
  
  	if (rdev->mddev->pers &&
  	    rdev->raid_disk >= 0)
  		return -EBUSY;
  
  	rdev->recovery_offset = recovery_start;
  	if (recovery_start == MaxSector)
  		set_bit(In_sync, &rdev->flags);
  	else
  		clear_bit(In_sync, &rdev->flags);
  	return len;
  }
  
  static struct rdev_sysfs_entry rdev_recovery_start =
  __ATTR(recovery_start, S_IRUGO|S_IWUSR, recovery_start_show, recovery_start_store);
16c791a5a   NeilBrown   md/bad-block-log:...
2870
2871
2872
2873
2874
  
  static ssize_t
  badblocks_show(struct badblocks *bb, char *page, int unack);
  static ssize_t
  badblocks_store(struct badblocks *bb, const char *page, size_t len, int unack);
3cb030020   NeilBrown   md: removing type...
2875
  static ssize_t bb_show(struct md_rdev *rdev, char *page)
16c791a5a   NeilBrown   md/bad-block-log:...
2876
2877
2878
  {
  	return badblocks_show(&rdev->badblocks, page, 0);
  }
3cb030020   NeilBrown   md: removing type...
2879
  static ssize_t bb_store(struct md_rdev *rdev, const char *page, size_t len)
16c791a5a   NeilBrown   md/bad-block-log:...
2880
  {
de393cdea   NeilBrown   md: make it easie...
2881
2882
2883
2884
2885
  	int rv = badblocks_store(&rdev->badblocks, page, len, 0);
  	/* Maybe that ack was all we needed */
  	if (test_and_clear_bit(BlockedBadBlocks, &rdev->flags))
  		wake_up(&rdev->blocked_wait);
  	return rv;
16c791a5a   NeilBrown   md/bad-block-log:...
2886
2887
2888
  }
  static struct rdev_sysfs_entry rdev_bad_blocks =
  __ATTR(bad_blocks, S_IRUGO|S_IWUSR, bb_show, bb_store);
3cb030020   NeilBrown   md: removing type...
2889
  static ssize_t ubb_show(struct md_rdev *rdev, char *page)
16c791a5a   NeilBrown   md/bad-block-log:...
2890
2891
2892
  {
  	return badblocks_show(&rdev->badblocks, page, 1);
  }
3cb030020   NeilBrown   md: removing type...
2893
  static ssize_t ubb_store(struct md_rdev *rdev, const char *page, size_t len)
16c791a5a   NeilBrown   md/bad-block-log:...
2894
2895
2896
2897
2898
  {
  	return badblocks_store(&rdev->badblocks, page, len, 1);
  }
  static struct rdev_sysfs_entry rdev_unack_bad_blocks =
  __ATTR(unacknowledged_bad_blocks, S_IRUGO|S_IWUSR, ubb_show, ubb_store);
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2899
2900
  static struct attribute *rdev_default_attrs[] = {
  	&rdev_state.attr,
4dbcdc751   NeilBrown   [PATCH] md: count...
2901
  	&rdev_errors.attr,
014236d2b   NeilBrown   [PATCH] md: expos...
2902
  	&rdev_slot.attr,
93c8cad03   NeilBrown   [PATCH] md: expor...
2903
  	&rdev_offset.attr,
83303b613   NeilBrown   [PATCH] md: allow...
2904
  	&rdev_size.attr,
06e3c817b   Dan Williams   md: add 'recovery...
2905
  	&rdev_recovery_start.attr,
16c791a5a   NeilBrown   md/bad-block-log:...
2906
2907
  	&rdev_bad_blocks.attr,
  	&rdev_unack_bad_blocks.attr,
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2908
2909
2910
2911
2912
2913
  	NULL,
  };
  static ssize_t
  rdev_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
  {
  	struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
3cb030020   NeilBrown   md: removing type...
2914
  	struct md_rdev *rdev = container_of(kobj, struct md_rdev, kobj);
fd01b88c7   NeilBrown   md: remove typede...
2915
  	struct mddev *mddev = rdev->mddev;
27c529bb8   NeilBrown   md: lock access t...
2916
  	ssize_t rv;
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2917
2918
2919
  
  	if (!entry->show)
  		return -EIO;
27c529bb8   NeilBrown   md: lock access t...
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
  
  	rv = mddev ? mddev_lock(mddev) : -EBUSY;
  	if (!rv) {
  		if (rdev->mddev == NULL)
  			rv = -EBUSY;
  		else
  			rv = entry->show(rdev, page);
  		mddev_unlock(mddev);
  	}
  	return rv;
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2930
2931
2932
2933
2934
2935
2936
  }
  
  static ssize_t
  rdev_attr_store(struct kobject *kobj, struct attribute *attr,
  	      const char *page, size_t length)
  {
  	struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
3cb030020   NeilBrown   md: removing type...
2937
  	struct md_rdev *rdev = container_of(kobj, struct md_rdev, kobj);
27c529bb8   NeilBrown   md: lock access t...
2938
  	ssize_t rv;
fd01b88c7   NeilBrown   md: remove typede...
2939
  	struct mddev *mddev = rdev->mddev;
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2940
2941
2942
  
  	if (!entry->store)
  		return -EIO;
67463acb6   NeilBrown   [PATCH] md: requi...
2943
2944
  	if (!capable(CAP_SYS_ADMIN))
  		return -EACCES;
27c529bb8   NeilBrown   md: lock access t...
2945
  	rv = mddev ? mddev_lock(mddev): -EBUSY;
ca3880594   NeilBrown   md: lock address ...
2946
  	if (!rv) {
27c529bb8   NeilBrown   md: lock access t...
2947
2948
2949
2950
  		if (rdev->mddev == NULL)
  			rv = -EBUSY;
  		else
  			rv = entry->store(rdev, page, length);
6a51830e1   Dan Williams   md: fix use after...
2951
  		mddev_unlock(mddev);
ca3880594   NeilBrown   md: lock address ...
2952
2953
  	}
  	return rv;
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2954
2955
2956
2957
  }
  
  static void rdev_free(struct kobject *ko)
  {
3cb030020   NeilBrown   md: removing type...
2958
  	struct md_rdev *rdev = container_of(ko, struct md_rdev, kobj);
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2959
2960
  	kfree(rdev);
  }
52cf25d0a   Emese Revfy   Driver core: Cons...
2961
  static const struct sysfs_ops rdev_sysfs_ops = {
86e6ffdd2   NeilBrown   [PATCH] md: exten...
2962
2963
2964
2965
2966
2967
2968
2969
  	.show		= rdev_attr_show,
  	.store		= rdev_attr_store,
  };
  static struct kobj_type rdev_ktype = {
  	.release	= rdev_free,
  	.sysfs_ops	= &rdev_sysfs_ops,
  	.default_attrs	= rdev_default_attrs,
  };
3cb030020   NeilBrown   md: removing type...
2970
  int md_rdev_init(struct md_rdev *rdev)
e8bb9a839   NeilBrown   md: split out md_...
2971
2972
2973
2974
2975
2976
2977
2978
2979
  {
  	rdev->desc_nr = -1;
  	rdev->saved_raid_disk = -1;
  	rdev->raid_disk = -1;
  	rdev->flags = 0;
  	rdev->data_offset = 0;
  	rdev->sb_events = 0;
  	rdev->last_read_error.tv_sec  = 0;
  	rdev->last_read_error.tv_nsec = 0;
2699b6722   NeilBrown   md: load/store ba...
2980
2981
  	rdev->sb_loaded = 0;
  	rdev->bb_page = NULL;
e8bb9a839   NeilBrown   md: split out md_...
2982
2983
2984
2985
2986
2987
  	atomic_set(&rdev->nr_pending, 0);
  	atomic_set(&rdev->read_errors, 0);
  	atomic_set(&rdev->corrected_errors, 0);
  
  	INIT_LIST_HEAD(&rdev->same_set);
  	init_waitqueue_head(&rdev->blocked_wait);
2230dfe4c   NeilBrown   md: beginnings of...
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
  
  	/* Add space to store bad block list.
  	 * This reserves the space even on arrays where it cannot
  	 * be used - I wonder if that matters
  	 */
  	rdev->badblocks.count = 0;
  	rdev->badblocks.shift = 0;
  	rdev->badblocks.page = kmalloc(PAGE_SIZE, GFP_KERNEL);
  	seqlock_init(&rdev->badblocks.lock);
  	if (rdev->badblocks.page == NULL)
  		return -ENOMEM;
  
  	return 0;
e8bb9a839   NeilBrown   md: split out md_...
3001
3002
  }
  EXPORT_SYMBOL_GPL(md_rdev_init);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
  /*
   * Import a device. If 'super_format' >= 0, then sanity check the superblock
   *
   * mark the device faulty if:
   *
   *   - the device is nonexistent (zero size)
   *   - the device has no valid superblock
   *
   * a faulty rdev _never_ has rdev->sb set.
   */
3cb030020   NeilBrown   md: removing type...
3013
  static struct md_rdev *md_import_device(dev_t newdev, int super_format, int super_minor)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3014
3015
3016
  {
  	char b[BDEVNAME_SIZE];
  	int err;
3cb030020   NeilBrown   md: removing type...
3017
  	struct md_rdev *rdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3018
  	sector_t size;
9ffae0cf3   NeilBrown   [PATCH] md: conve...
3019
  	rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3020
3021
3022
3023
3024
  	if (!rdev) {
  		printk(KERN_ERR "md: could not alloc mem for new device!
  ");
  		return ERR_PTR(-ENOMEM);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3025

2230dfe4c   NeilBrown   md: beginnings of...
3026
3027
3028
3029
3030
  	err = md_rdev_init(rdev);
  	if (err)
  		goto abort_free;
  	err = alloc_disk_sb(rdev);
  	if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3031
  		goto abort_free;
c5d79adba   NeilBrown   md: allow devices...
3032
  	err = lock_rdev(rdev, newdev, super_format == -2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3033
3034
  	if (err)
  		goto abort_free;
f9cb074bf   Greg Kroah-Hartman   Kobject: rename k...
3035
  	kobject_init(&rdev->kobj, &rdev_ktype);
86e6ffdd2   NeilBrown   [PATCH] md: exten...
3036

77304d2ab   Mike Snitzer   block: read i_siz...
3037
  	size = i_size_read(rdev->bdev->bd_inode) >> BLOCK_SIZE_BITS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
  	if (!size) {
  		printk(KERN_WARNING 
  			"md: %s has zero or unknown size, marking faulty!
  ",
  			bdevname(rdev->bdev,b));
  		err = -EINVAL;
  		goto abort_free;
  	}
  
  	if (super_format >= 0) {
  		err = super_types[super_format].
  			load_super(rdev, NULL, super_minor);
  		if (err == -EINVAL) {
df968c4e8   NeilBrown   md: improve messa...
3051
3052
3053
3054
3055
3056
  			printk(KERN_WARNING
  				"md: %s does not have a valid v%d.%d "
  			       "superblock, not importing!
  ",
  				bdevname(rdev->bdev,b),
  			       super_format, super_minor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
  			goto abort_free;
  		}
  		if (err < 0) {
  			printk(KERN_WARNING 
  				"md: could not read %s's sb, not importing!
  ",
  				bdevname(rdev->bdev,b));
  			goto abort_free;
  		}
  	}
9f2f38307   NeilBrown   md: Disable bad b...
3067
3068
3069
  	if (super_format == -1)
  		/* hot-add for 0.90, or non-persistent: so no badblocks */
  		rdev->badblocks.shift = -1;
6bfe0b499   Dan Williams   md: support block...
3070

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3071
3072
3073
  	return rdev;
  
  abort_free:
2699b6722   NeilBrown   md: load/store ba...
3074
3075
3076
  	if (rdev->bdev)
  		unlock_rdev(rdev);
  	free_disk_sb(rdev);
2230dfe4c   NeilBrown   md: beginnings of...
3077
  	kfree(rdev->badblocks.page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3078
3079
3080
3081
3082
3083
3084
  	kfree(rdev);
  	return ERR_PTR(err);
  }
  
  /*
   * Check a full RAID array for plausibility
   */
fd01b88c7   NeilBrown   md: remove typede...
3085
  static void analyze_sbs(struct mddev * mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3086
3087
  {
  	int i;
3cb030020   NeilBrown   md: removing type...
3088
  	struct md_rdev *rdev, *freshest, *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3089
3090
3091
  	char b[BDEVNAME_SIZE];
  
  	freshest = NULL;
d089c6af1   NeilBrown   md: change ITERAT...
3092
  	rdev_for_each(rdev, tmp, mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
  		switch (super_types[mddev->major_version].
  			load_super(rdev, freshest, mddev->minor_version)) {
  		case 1:
  			freshest = rdev;
  			break;
  		case 0:
  			break;
  		default:
  			printk( KERN_ERR \
  				"md: fatal superblock inconsistency in %s"
  				" -- removing from array
  ", 
  				bdevname(rdev->bdev,b));
  			kick_rdev_from_array(rdev);
  		}
  
  
  	super_types[mddev->major_version].
  		validate_super(mddev, freshest);
  
  	i = 0;
d089c6af1   NeilBrown   md: change ITERAT...
3114
  	rdev_for_each(rdev, tmp, mddev) {
233fca36b   NeilBrown   md: Relax checks ...
3115
3116
3117
  		if (mddev->max_disks &&
  		    (rdev->desc_nr >= mddev->max_disks ||
  		     i > mddev->max_disks)) {
de01dfadf   NeilBrown   md: Ensure an md ...
3118
3119
3120
3121
3122
3123
3124
3125
  			printk(KERN_WARNING
  			       "md: %s: %s: only %d devices permitted
  ",
  			       mdname(mddev), bdevname(rdev->bdev, b),
  			       mddev->max_disks);
  			kick_rdev_from_array(rdev);
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
  		if (rdev != freshest)
  			if (super_types[mddev->major_version].
  			    validate_super(mddev, rdev)) {
  				printk(KERN_WARNING "md: kicking non-fresh %s"
  					" from array!
  ",
  					bdevname(rdev->bdev,b));
  				kick_rdev_from_array(rdev);
  				continue;
  			}
  		if (mddev->level == LEVEL_MULTIPATH) {
  			rdev->desc_nr = i++;
  			rdev->raid_disk = rdev->desc_nr;
b2d444d7a   NeilBrown   [PATCH] md: conve...
3139
  			set_bit(In_sync, &rdev->flags);
5e5e3e78e   NeilBrown   md: Fix handling ...
3140
  		} else if (rdev->raid_disk >= (mddev->raid_disks - min(0, mddev->delta_disks))) {
a778b73ff   NeilBrown   md: fix bug with ...
3141
3142
  			rdev->raid_disk = -1;
  			clear_bit(In_sync, &rdev->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3143
3144
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3145
  }
72e02075a   NeilBrown   md: factor out pa...
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
  /* Read a fixed-point number.
   * Numbers in sysfs attributes should be in "standard" units where
   * possible, so time should be in seconds.
   * However we internally use a a much smaller unit such as 
   * milliseconds or jiffies.
   * This function takes a decimal number with a possible fractional
   * component, and produces an integer which is the result of
   * multiplying that number by 10^'scale'.
   * all without any floating-point arithmetic.
   */
  int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale)
  {
  	unsigned long result = 0;
  	long decimals = -1;
  	while (isdigit(*cp) || (*cp == '.' && decimals < 0)) {
  		if (*cp == '.')
  			decimals = 0;
  		else if (decimals < scale) {
  			unsigned int value;
  			value = *cp - '0';
  			result = result * 10 + value;
  			if (decimals >= 0)
  				decimals++;
  		}
  		cp++;
  	}
  	if (*cp == '
  ')
  		cp++;
  	if (*cp)
  		return -EINVAL;
  	if (decimals < 0)
  		decimals = 0;
  	while (decimals < scale) {
  		result *= 10;
  		decimals ++;
  	}
  	*res = result;
  	return 0;
  }
19052c0e8   NeilBrown   Make writes to md...
3186
  static void md_safemode_timeout(unsigned long data);
eae1701fb   NeilBrown   [PATCH] md: initi...
3187
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3188
  safe_delay_show(struct mddev *mddev, char *page)
16f17b39f   NeilBrown   [PATCH] md: incre...
3189
3190
3191
3192
3193
3194
  {
  	int msec = (mddev->safemode_delay*1000)/HZ;
  	return sprintf(page, "%d.%03d
  ", msec/1000, msec%1000);
  }
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3195
  safe_delay_store(struct mddev *mddev, const char *cbuf, size_t len)
16f17b39f   NeilBrown   [PATCH] md: incre...
3196
  {
16f17b39f   NeilBrown   [PATCH] md: incre...
3197
  	unsigned long msec;
97ce0a7f9   Dan Williams   md: fix input tru...
3198

72e02075a   NeilBrown   md: factor out pa...
3199
  	if (strict_strtoul_scaled(cbuf, &msec, 3) < 0)
16f17b39f   NeilBrown   [PATCH] md: incre...
3200
  		return -EINVAL;
16f17b39f   NeilBrown   [PATCH] md: incre...
3201
3202
3203
  	if (msec == 0)
  		mddev->safemode_delay = 0;
  	else {
19052c0e8   NeilBrown   Make writes to md...
3204
  		unsigned long old_delay = mddev->safemode_delay;
16f17b39f   NeilBrown   [PATCH] md: incre...
3205
3206
3207
  		mddev->safemode_delay = (msec*HZ)/1000;
  		if (mddev->safemode_delay == 0)
  			mddev->safemode_delay = 1;
19052c0e8   NeilBrown   Make writes to md...
3208
3209
  		if (mddev->safemode_delay < old_delay)
  			md_safemode_timeout((unsigned long)mddev);
16f17b39f   NeilBrown   [PATCH] md: incre...
3210
3211
3212
3213
  	}
  	return len;
  }
  static struct md_sysfs_entry md_safe_delay =
80ca3a44f   NeilBrown   [PATCH] md: unify...
3214
  __ATTR(safe_mode_delay, S_IRUGO|S_IWUSR,safe_delay_show, safe_delay_store);
16f17b39f   NeilBrown   [PATCH] md: incre...
3215
3216
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3217
  level_show(struct mddev *mddev, char *page)
eae1701fb   NeilBrown   [PATCH] md: initi...
3218
  {
84fc4b56d   NeilBrown   md: rename "mdk_p...
3219
  	struct md_personality *p = mddev->pers;
d9d166c2a   NeilBrown   [PATCH] md: allow...
3220
  	if (p)
eae1701fb   NeilBrown   [PATCH] md: initi...
3221
3222
  		return sprintf(page, "%s
  ", p->name);
d9d166c2a   NeilBrown   [PATCH] md: allow...
3223
3224
3225
3226
3227
3228
3229
3230
  	else if (mddev->clevel[0])
  		return sprintf(page, "%s
  ", mddev->clevel);
  	else if (mddev->level != LEVEL_NONE)
  		return sprintf(page, "%d
  ", mddev->level);
  	else
  		return 0;
eae1701fb   NeilBrown   [PATCH] md: initi...
3231
  }
d9d166c2a   NeilBrown   [PATCH] md: allow...
3232
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3233
  level_store(struct mddev *mddev, const char *buf, size_t len)
d9d166c2a   NeilBrown   [PATCH] md: allow...
3234
  {
f2859af67   Dan Williams   md: allow integer...
3235
  	char clevel[16];
20a49ff67   NeilBrown   md: change a few ...
3236
  	ssize_t rv = len;
84fc4b56d   NeilBrown   md: rename "mdk_p...
3237
  	struct md_personality *pers;
f2859af67   Dan Williams   md: allow integer...
3238
  	long level;
245f46c2c   NeilBrown   md: add ->takeove...
3239
  	void *priv;
3cb030020   NeilBrown   md: removing type...
3240
  	struct md_rdev *rdev;
245f46c2c   NeilBrown   md: add ->takeove...
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
  
  	if (mddev->pers == NULL) {
  		if (len == 0)
  			return 0;
  		if (len >= sizeof(mddev->clevel))
  			return -ENOSPC;
  		strncpy(mddev->clevel, buf, len);
  		if (mddev->clevel[len-1] == '
  ')
  			len--;
  		mddev->clevel[len] = 0;
  		mddev->level = LEVEL_NONE;
  		return rv;
  	}
  
  	/* request to change the personality.  Need to ensure:
  	 *  - array is not engaged in resync/recovery/reshape
  	 *  - old personality can be suspended
  	 *  - new personality will access other array.
  	 */
bb4f1e9d0   NeilBrown   md: fix another d...
3261
3262
3263
  	if (mddev->sync_thread ||
  	    mddev->reshape_position != MaxSector ||
  	    mddev->sysfs_active)
d9d166c2a   NeilBrown   [PATCH] md: allow...
3264
  		return -EBUSY;
245f46c2c   NeilBrown   md: add ->takeove...
3265
3266
3267
3268
3269
3270
3271
3272
3273
  
  	if (!mddev->pers->quiesce) {
  		printk(KERN_WARNING "md: %s: %s does not support online personality change
  ",
  		       mdname(mddev), mddev->pers->name);
  		return -EINVAL;
  	}
  
  	/* Now find the new personality */
f2859af67   Dan Williams   md: allow integer...
3274
  	if (len == 0 || len >= sizeof(clevel))
245f46c2c   NeilBrown   md: add ->takeove...
3275
  		return -EINVAL;
f2859af67   Dan Williams   md: allow integer...
3276
3277
3278
  	strncpy(clevel, buf, len);
  	if (clevel[len-1] == '
  ')
d9d166c2a   NeilBrown   [PATCH] md: allow...
3279
  		len--;
f2859af67   Dan Williams   md: allow integer...
3280
3281
3282
  	clevel[len] = 0;
  	if (strict_strtol(clevel, 10, &level))
  		level = LEVEL_NONE;
245f46c2c   NeilBrown   md: add ->takeove...
3283

f2859af67   Dan Williams   md: allow integer...
3284
3285
  	if (request_module("md-%s", clevel) != 0)
  		request_module("md-level-%s", clevel);
245f46c2c   NeilBrown   md: add ->takeove...
3286
  	spin_lock(&pers_lock);
f2859af67   Dan Williams   md: allow integer...
3287
  	pers = find_pers(level, clevel);
245f46c2c   NeilBrown   md: add ->takeove...
3288
3289
  	if (!pers || !try_module_get(pers->owner)) {
  		spin_unlock(&pers_lock);
f2859af67   Dan Williams   md: allow integer...
3290
3291
  		printk(KERN_WARNING "md: personality %s not loaded
  ", clevel);
245f46c2c   NeilBrown   md: add ->takeove...
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
  		return -EINVAL;
  	}
  	spin_unlock(&pers_lock);
  
  	if (pers == mddev->pers) {
  		/* Nothing to do! */
  		module_put(pers->owner);
  		return rv;
  	}
  	if (!pers->takeover) {
  		module_put(pers->owner);
  		printk(KERN_WARNING "md: %s: %s does not support personality takeover
  ",
f2859af67   Dan Williams   md: allow integer...
3305
  		       mdname(mddev), clevel);
245f46c2c   NeilBrown   md: add ->takeove...
3306
3307
  		return -EINVAL;
  	}
e93f68a1f   NeilBrown   md: fix handling ...
3308
3309
  	list_for_each_entry(rdev, &mddev->disks, same_set)
  		rdev->new_raid_disk = rdev->raid_disk;
245f46c2c   NeilBrown   md: add ->takeove...
3310
3311
3312
3313
3314
3315
3316
  	/* ->takeover must set new_* and/or delta_disks
  	 * if it succeeds, and may set them when it fails.
  	 */
  	priv = pers->takeover(mddev);
  	if (IS_ERR(priv)) {
  		mddev->new_level = mddev->level;
  		mddev->new_layout = mddev->layout;
664e7c413   Andre Noll   md: Convert mddev...
3317
  		mddev->new_chunk_sectors = mddev->chunk_sectors;
245f46c2c   NeilBrown   md: add ->takeove...
3318
3319
3320
3321
3322
  		mddev->raid_disks -= mddev->delta_disks;
  		mddev->delta_disks = 0;
  		module_put(pers->owner);
  		printk(KERN_WARNING "md: %s: %s would not accept array
  ",
f2859af67   Dan Williams   md: allow integer...
3323
  		       mdname(mddev), clevel);
245f46c2c   NeilBrown   md: add ->takeove...
3324
3325
3326
3327
3328
3329
  		return PTR_ERR(priv);
  	}
  
  	/* Looks like we have a winner */
  	mddev_suspend(mddev);
  	mddev->pers->stop(mddev);
a64c876fd   NeilBrown   md: manage redund...
3330
3331
3332
3333
3334
3335
3336
3337
3338
  	
  	if (mddev->pers->sync_request == NULL &&
  	    pers->sync_request != NULL) {
  		/* need to add the md_redundancy_group */
  		if (sysfs_create_group(&mddev->kobj, &md_redundancy_group))
  			printk(KERN_WARNING
  			       "md: cannot register extra attributes for %s
  ",
  			       mdname(mddev));
19fdb9eef   NeilBrown   Merge commit '3ff...
3339
  		mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, NULL, "sync_action");
a64c876fd   NeilBrown   md: manage redund...
3340
3341
3342
3343
3344
3345
3346
  	}		
  	if (mddev->pers->sync_request != NULL &&
  	    pers->sync_request == NULL) {
  		/* need to remove the md_redundancy_group */
  		if (mddev->to_remove == NULL)
  			mddev->to_remove = &md_redundancy_group;
  	}
54071b380   Trela Maciej   md:Add support fo...
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
  	if (mddev->pers->sync_request == NULL &&
  	    mddev->external) {
  		/* We are converting from a no-redundancy array
  		 * to a redundancy array and metadata is managed
  		 * externally so we need to be sure that writes
  		 * won't block due to a need to transition
  		 *      clean->dirty
  		 * until external management is started.
  		 */
  		mddev->in_sync = 0;
  		mddev->safemode_delay = 0;
  		mddev->safemode = 0;
  	}
e93f68a1f   NeilBrown   md: fix handling ...
3360
  	list_for_each_entry(rdev, &mddev->disks, same_set) {
e93f68a1f   NeilBrown   md: fix handling ...
3361
3362
  		if (rdev->raid_disk < 0)
  			continue;
bf2cb0dab   NeilBrown   md: Fix removal o...
3363
  		if (rdev->new_raid_disk >= mddev->raid_disks)
e93f68a1f   NeilBrown   md: fix handling ...
3364
3365
3366
  			rdev->new_raid_disk = -1;
  		if (rdev->new_raid_disk == rdev->raid_disk)
  			continue;
36fad858a   Namhyung Kim   md: introduce lin...
3367
  		sysfs_unlink_rdev(mddev, rdev);
e93f68a1f   NeilBrown   md: fix handling ...
3368
3369
3370
3371
3372
3373
3374
3375
  	}
  	list_for_each_entry(rdev, &mddev->disks, same_set) {
  		if (rdev->raid_disk < 0)
  			continue;
  		if (rdev->new_raid_disk == rdev->raid_disk)
  			continue;
  		rdev->raid_disk = rdev->new_raid_disk;
  		if (rdev->raid_disk < 0)
3a981b03f   NeilBrown   md: when a level ...
3376
  			clear_bit(In_sync, &rdev->flags);
e93f68a1f   NeilBrown   md: fix handling ...
3377
  		else {
36fad858a   Namhyung Kim   md: introduce lin...
3378
3379
3380
3381
3382
  			if (sysfs_link_rdev(mddev, rdev))
  				printk(KERN_WARNING "md: cannot register rd%d"
  				       " for %s after level change
  ",
  				       rdev->raid_disk, mdname(mddev));
3a981b03f   NeilBrown   md: when a level ...
3383
  		}
e93f68a1f   NeilBrown   md: fix handling ...
3384
3385
3386
  	}
  
  	module_put(mddev->pers->owner);
245f46c2c   NeilBrown   md: add ->takeove...
3387
3388
3389
3390
3391
  	mddev->pers = pers;
  	mddev->private = priv;
  	strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
  	mddev->level = mddev->new_level;
  	mddev->layout = mddev->new_layout;
664e7c413   Andre Noll   md: Convert mddev...
3392
  	mddev->chunk_sectors = mddev->new_chunk_sectors;
245f46c2c   NeilBrown   md: add ->takeove...
3393
  	mddev->delta_disks = 0;
fee68723c   Krzysztof Wojcik   md: Cleanup after...
3394
  	mddev->degraded = 0;
9af204cf7   Trela, Maciej   md: Add support f...
3395
3396
3397
3398
3399
3400
3401
  	if (mddev->pers->sync_request == NULL) {
  		/* this is now an array without redundancy, so
  		 * it must always be in_sync
  		 */
  		mddev->in_sync = 1;
  		del_timer_sync(&mddev->safemode_timer);
  	}
245f46c2c   NeilBrown   md: add ->takeove...
3402
3403
3404
3405
3406
  	pers->run(mddev);
  	mddev_resume(mddev);
  	set_bit(MD_CHANGE_DEVS, &mddev->flags);
  	set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
  	md_wakeup_thread(mddev->thread);
5cac7861b   Maciej Trela   md: notify level ...
3407
  	sysfs_notify(&mddev->kobj, NULL, "level");
bb7f8d221   Dan Williams   md: notify mdstat...
3408
  	md_new_event(mddev);
d9d166c2a   NeilBrown   [PATCH] md: allow...
3409
3410
3411
3412
  	return rv;
  }
  
  static struct md_sysfs_entry md_level =
80ca3a44f   NeilBrown   [PATCH] md: unify...
3413
  __ATTR(level, S_IRUGO|S_IWUSR, level_show, level_store);
eae1701fb   NeilBrown   [PATCH] md: initi...
3414

d4dbd0250   NeilBrown   [PATCH] md: Allow...
3415
3416
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3417
  layout_show(struct mddev *mddev, char *page)
d4dbd0250   NeilBrown   [PATCH] md: Allow...
3418
3419
  {
  	/* just a number, not meaningful for all levels */
08a02ecd2   NeilBrown   md: allow reshape...
3420
3421
3422
3423
3424
  	if (mddev->reshape_position != MaxSector &&
  	    mddev->layout != mddev->new_layout)
  		return sprintf(page, "%d (%d)
  ",
  			       mddev->new_layout, mddev->layout);
d4dbd0250   NeilBrown   [PATCH] md: Allow...
3425
3426
3427
3428
3429
  	return sprintf(page, "%d
  ", mddev->layout);
  }
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3430
  layout_store(struct mddev *mddev, const char *buf, size_t len)
d4dbd0250   NeilBrown   [PATCH] md: Allow...
3431
3432
3433
  {
  	char *e;
  	unsigned long n = simple_strtoul(buf, &e, 10);
d4dbd0250   NeilBrown   [PATCH] md: Allow...
3434
3435
3436
3437
  
  	if (!*buf || (*e && *e != '
  '))
  		return -EINVAL;
b35460352   NeilBrown   md/raid5: allow l...
3438
3439
  	if (mddev->pers) {
  		int err;
50ac168a6   NeilBrown   md: merge reconfi...
3440
  		if (mddev->pers->check_reshape == NULL)
b35460352   NeilBrown   md/raid5: allow l...
3441
  			return -EBUSY;
597a711b6   NeilBrown   md: remove unnece...
3442
  		mddev->new_layout = n;
50ac168a6   NeilBrown   md: merge reconfi...
3443
  		err = mddev->pers->check_reshape(mddev);
597a711b6   NeilBrown   md: remove unnece...
3444
3445
  		if (err) {
  			mddev->new_layout = mddev->layout;
b35460352   NeilBrown   md/raid5: allow l...
3446
  			return err;
597a711b6   NeilBrown   md: remove unnece...
3447
  		}
b35460352   NeilBrown   md/raid5: allow l...
3448
  	} else {
08a02ecd2   NeilBrown   md: allow reshape...
3449
  		mddev->new_layout = n;
b35460352   NeilBrown   md/raid5: allow l...
3450
3451
3452
  		if (mddev->reshape_position == MaxSector)
  			mddev->layout = n;
  	}
d4dbd0250   NeilBrown   [PATCH] md: Allow...
3453
3454
3455
  	return len;
  }
  static struct md_sysfs_entry md_layout =
80ca3a44f   NeilBrown   [PATCH] md: unify...
3456
  __ATTR(layout, S_IRUGO|S_IWUSR, layout_show, layout_store);
d4dbd0250   NeilBrown   [PATCH] md: Allow...
3457

eae1701fb   NeilBrown   [PATCH] md: initi...
3458
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3459
  raid_disks_show(struct mddev *mddev, char *page)
eae1701fb   NeilBrown   [PATCH] md: initi...
3460
  {
bb636547b   NeilBrown   [PATCH] md: docum...
3461
3462
  	if (mddev->raid_disks == 0)
  		return 0;
08a02ecd2   NeilBrown   md: allow reshape...
3463
3464
3465
3466
3467
  	if (mddev->reshape_position != MaxSector &&
  	    mddev->delta_disks != 0)
  		return sprintf(page, "%d (%d)
  ", mddev->raid_disks,
  			       mddev->raid_disks - mddev->delta_disks);
eae1701fb   NeilBrown   [PATCH] md: initi...
3468
3469
3470
  	return sprintf(page, "%d
  ", mddev->raid_disks);
  }
fd01b88c7   NeilBrown   md: remove typede...
3471
  static int update_raid_disks(struct mddev *mddev, int raid_disks);
da943b991   NeilBrown   [PATCH] md: allow...
3472
3473
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3474
  raid_disks_store(struct mddev *mddev, const char *buf, size_t len)
da943b991   NeilBrown   [PATCH] md: allow...
3475
  {
da943b991   NeilBrown   [PATCH] md: allow...
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
  	char *e;
  	int rv = 0;
  	unsigned long n = simple_strtoul(buf, &e, 10);
  
  	if (!*buf || (*e && *e != '
  '))
  		return -EINVAL;
  
  	if (mddev->pers)
  		rv = update_raid_disks(mddev, n);
08a02ecd2   NeilBrown   md: allow reshape...
3486
3487
3488
3489
3490
  	else if (mddev->reshape_position != MaxSector) {
  		int olddisks = mddev->raid_disks - mddev->delta_disks;
  		mddev->delta_disks = n - olddisks;
  		mddev->raid_disks = n;
  	} else
da943b991   NeilBrown   [PATCH] md: allow...
3491
3492
3493
3494
  		mddev->raid_disks = n;
  	return rv ? rv : len;
  }
  static struct md_sysfs_entry md_raid_disks =
80ca3a44f   NeilBrown   [PATCH] md: unify...
3495
  __ATTR(raid_disks, S_IRUGO|S_IWUSR, raid_disks_show, raid_disks_store);
eae1701fb   NeilBrown   [PATCH] md: initi...
3496

24dd469d7   NeilBrown   [PATCH] md: allow...
3497
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3498
  chunk_size_show(struct mddev *mddev, char *page)
3b34380ae   NeilBrown   [PATCH] md: allow...
3499
  {
08a02ecd2   NeilBrown   md: allow reshape...
3500
  	if (mddev->reshape_position != MaxSector &&
664e7c413   Andre Noll   md: Convert mddev...
3501
3502
3503
3504
  	    mddev->chunk_sectors != mddev->new_chunk_sectors)
  		return sprintf(page, "%d (%d)
  ",
  			       mddev->new_chunk_sectors << 9,
9d8f03636   Andre Noll   md: Make mddev->c...
3505
3506
3507
  			       mddev->chunk_sectors << 9);
  	return sprintf(page, "%d
  ", mddev->chunk_sectors << 9);
3b34380ae   NeilBrown   [PATCH] md: allow...
3508
3509
3510
  }
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3511
  chunk_size_store(struct mddev *mddev, const char *buf, size_t len)
3b34380ae   NeilBrown   [PATCH] md: allow...
3512
  {
3b34380ae   NeilBrown   [PATCH] md: allow...
3513
3514
  	char *e;
  	unsigned long n = simple_strtoul(buf, &e, 10);
3b34380ae   NeilBrown   [PATCH] md: allow...
3515
3516
3517
  	if (!*buf || (*e && *e != '
  '))
  		return -EINVAL;
b35460352   NeilBrown   md/raid5: allow l...
3518
3519
  	if (mddev->pers) {
  		int err;
50ac168a6   NeilBrown   md: merge reconfi...
3520
  		if (mddev->pers->check_reshape == NULL)
b35460352   NeilBrown   md/raid5: allow l...
3521
  			return -EBUSY;
597a711b6   NeilBrown   md: remove unnece...
3522
  		mddev->new_chunk_sectors = n >> 9;
50ac168a6   NeilBrown   md: merge reconfi...
3523
  		err = mddev->pers->check_reshape(mddev);
597a711b6   NeilBrown   md: remove unnece...
3524
3525
  		if (err) {
  			mddev->new_chunk_sectors = mddev->chunk_sectors;
b35460352   NeilBrown   md/raid5: allow l...
3526
  			return err;
597a711b6   NeilBrown   md: remove unnece...
3527
  		}
b35460352   NeilBrown   md/raid5: allow l...
3528
  	} else {
664e7c413   Andre Noll   md: Convert mddev...
3529
  		mddev->new_chunk_sectors = n >> 9;
b35460352   NeilBrown   md/raid5: allow l...
3530
  		if (mddev->reshape_position == MaxSector)
9d8f03636   Andre Noll   md: Make mddev->c...
3531
  			mddev->chunk_sectors = n >> 9;
b35460352   NeilBrown   md/raid5: allow l...
3532
  	}
3b34380ae   NeilBrown   [PATCH] md: allow...
3533
3534
3535
  	return len;
  }
  static struct md_sysfs_entry md_chunk_size =
80ca3a44f   NeilBrown   [PATCH] md: unify...
3536
  __ATTR(chunk_size, S_IRUGO|S_IWUSR, chunk_size_show, chunk_size_store);
3b34380ae   NeilBrown   [PATCH] md: allow...
3537

a94213b1f   NeilBrown   [PATCH] md: Allow...
3538
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3539
  resync_start_show(struct mddev *mddev, char *page)
a94213b1f   NeilBrown   [PATCH] md: Allow...
3540
  {
d1a7c5036   NeilBrown   md: don't display...
3541
3542
3543
  	if (mddev->recovery_cp == MaxSector)
  		return sprintf(page, "none
  ");
a94213b1f   NeilBrown   [PATCH] md: Allow...
3544
3545
3546
3547
3548
  	return sprintf(page, "%llu
  ", (unsigned long long)mddev->recovery_cp);
  }
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3549
  resync_start_store(struct mddev *mddev, const char *buf, size_t len)
a94213b1f   NeilBrown   [PATCH] md: Allow...
3550
  {
a94213b1f   NeilBrown   [PATCH] md: Allow...
3551
3552
  	char *e;
  	unsigned long long n = simple_strtoull(buf, &e, 10);
b098636cf   NeilBrown   md: allow resync_...
3553
  	if (mddev->pers && !test_bit(MD_RECOVERY_FROZEN, &mddev->recovery))
a94213b1f   NeilBrown   [PATCH] md: Allow...
3554
  		return -EBUSY;
06e3c817b   Dan Williams   md: add 'recovery...
3555
3556
3557
3558
  	if (cmd_match(buf, "none"))
  		n = MaxSector;
  	else if (!*buf || (*e && *e != '
  '))
a94213b1f   NeilBrown   [PATCH] md: Allow...
3559
3560
3561
3562
3563
3564
  		return -EINVAL;
  
  	mddev->recovery_cp = n;
  	return len;
  }
  static struct md_sysfs_entry md_resync_start =
80ca3a44f   NeilBrown   [PATCH] md: unify...
3565
  __ATTR(resync_start, S_IRUGO|S_IWUSR, resync_start_show, resync_start_store);
a94213b1f   NeilBrown   [PATCH] md: Allow...
3566

9e653b634   NeilBrown   [PATCH] md: Set/g...
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
  /*
   * The array state can be:
   *
   * clear
   *     No devices, no size, no level
   *     Equivalent to STOP_ARRAY ioctl
   * inactive
   *     May have some settings, but array is not active
   *        all IO results in error
   *     When written, doesn't tear down array, but just stops it
   * suspended (not supported yet)
   *     All IO requests will block. The array can be reconfigured.
910d8cb3f   Andre Noll   md: Fix typo in a...
3579
   *     Writing this, if accepted, will block until array is quiescent
9e653b634   NeilBrown   [PATCH] md: Set/g...
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
   * readonly
   *     no resync can happen.  no superblocks get written.
   *     write requests fail
   * read-auto
   *     like readonly, but behaves like 'clean' on a write request.
   *
   * clean - no pending writes, but otherwise active.
   *     When written to inactive array, starts without resync
   *     If a write request arrives then
   *       if metadata is known, mark 'dirty' and switch to 'active'.
   *       if not known, block and switch to write-pending
   *     If written to an active array that has pending writes, then fails.
   * active
   *     fully active: IO and resync can be happening.
   *     When written to inactive array, starts with resync
   *
   * write-pending
   *     clean, but writes are blocked waiting for 'active' to be written.
   *
   * active-idle
   *     like active, but no writes have been seen for a while (100msec).
   *
   */
  enum array_state { clear, inactive, suspended, readonly, read_auto, clean, active,
  		   write_pending, active_idle, bad_word};
053819542   Adrian Bunk   [PATCH] drivers/m...
3605
  static char *array_states[] = {
9e653b634   NeilBrown   [PATCH] md: Set/g...
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
  	"clear", "inactive", "suspended", "readonly", "read-auto", "clean", "active",
  	"write-pending", "active-idle", NULL };
  
  static int match_word(const char *word, char **list)
  {
  	int n;
  	for (n=0; list[n]; n++)
  		if (cmd_match(word, list[n]))
  			break;
  	return n;
  }
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3619
  array_state_show(struct mddev *mddev, char *page)
9e653b634   NeilBrown   [PATCH] md: Set/g...
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
  {
  	enum array_state st = inactive;
  
  	if (mddev->pers)
  		switch(mddev->ro) {
  		case 1:
  			st = readonly;
  			break;
  		case 2:
  			st = read_auto;
  			break;
  		case 0:
  			if (mddev->in_sync)
  				st = clean;
070dc6dd7   NeilBrown   md: resolve confu...
3634
  			else if (test_bit(MD_CHANGE_PENDING, &mddev->flags))
e691063a6   NeilBrown   md: support 'exte...
3635
  				st = write_pending;
9e653b634   NeilBrown   [PATCH] md: Set/g...
3636
3637
3638
3639
3640
3641
3642
3643
  			else if (mddev->safemode)
  				st = active_idle;
  			else
  				st = active;
  		}
  	else {
  		if (list_empty(&mddev->disks) &&
  		    mddev->raid_disks == 0 &&
58c0fed40   Andre Noll   md: Make mddev->s...
3644
  		    mddev->dev_sectors == 0)
9e653b634   NeilBrown   [PATCH] md: Set/g...
3645
3646
3647
3648
3649
3650
3651
  			st = clear;
  		else
  			st = inactive;
  	}
  	return sprintf(page, "%s
  ", array_states[st]);
  }
fd01b88c7   NeilBrown   md: remove typede...
3652
3653
3654
3655
  static int do_md_stop(struct mddev * mddev, int ro, int is_open);
  static int md_set_readonly(struct mddev * mddev, int is_open);
  static int do_md_run(struct mddev * mddev);
  static int restart_array(struct mddev *mddev);
9e653b634   NeilBrown   [PATCH] md: Set/g...
3656
3657
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3658
  array_state_store(struct mddev *mddev, const char *buf, size_t len)
9e653b634   NeilBrown   [PATCH] md: Set/g...
3659
3660
3661
3662
3663
3664
3665
3666
  {
  	int err = -EINVAL;
  	enum array_state st = match_word(buf, array_states);
  	switch(st) {
  	case bad_word:
  		break;
  	case clear:
  		/* stopping an active array */
f2ea68cf4   NeilBrown   md: only count ac...
3667
  		if (atomic_read(&mddev->openers) > 0)
e691063a6   NeilBrown   md: support 'exte...
3668
  			return -EBUSY;
df5b20cf6   Neil Brown   md: Better contro...
3669
  		err = do_md_stop(mddev, 0, 0);
9e653b634   NeilBrown   [PATCH] md: Set/g...
3670
3671
3672
3673
  		break;
  	case inactive:
  		/* stopping an active array */
  		if (mddev->pers) {
f2ea68cf4   NeilBrown   md: only count ac...
3674
  			if (atomic_read(&mddev->openers) > 0)
9e653b634   NeilBrown   [PATCH] md: Set/g...
3675
  				return -EBUSY;
df5b20cf6   Neil Brown   md: Better contro...
3676
  			err = do_md_stop(mddev, 2, 0);
e691063a6   NeilBrown   md: support 'exte...
3677
3678
  		} else
  			err = 0; /* already inactive */
9e653b634   NeilBrown   [PATCH] md: Set/g...
3679
3680
3681
3682
3683
  		break;
  	case suspended:
  		break; /* not supported yet */
  	case readonly:
  		if (mddev->pers)
a4bd82d0d   NeilBrown   md: split md_set_...
3684
  			err = md_set_readonly(mddev, 0);
9e653b634   NeilBrown   [PATCH] md: Set/g...
3685
3686
  		else {
  			mddev->ro = 1;
648b629ed   NeilBrown   md: fix up switch...
3687
  			set_disk_ro(mddev->gendisk, 1);
9e653b634   NeilBrown   [PATCH] md: Set/g...
3688
3689
3690
3691
  			err = do_md_run(mddev);
  		}
  		break;
  	case read_auto:
9e653b634   NeilBrown   [PATCH] md: Set/g...
3692
  		if (mddev->pers) {
80268ee92   NeilBrown   md: Don't try to ...
3693
  			if (mddev->ro == 0)
a4bd82d0d   NeilBrown   md: split md_set_...
3694
  				err = md_set_readonly(mddev, 0);
80268ee92   NeilBrown   md: Don't try to ...
3695
  			else if (mddev->ro == 1)
648b629ed   NeilBrown   md: fix up switch...
3696
3697
3698
3699
3700
  				err = restart_array(mddev);
  			if (err == 0) {
  				mddev->ro = 2;
  				set_disk_ro(mddev->gendisk, 0);
  			}
9e653b634   NeilBrown   [PATCH] md: Set/g...
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
  		} else {
  			mddev->ro = 2;
  			err = do_md_run(mddev);
  		}
  		break;
  	case clean:
  		if (mddev->pers) {
  			restart_array(mddev);
  			spin_lock_irq(&mddev->write_lock);
  			if (atomic_read(&mddev->writes_pending) == 0) {
e691063a6   NeilBrown   md: support 'exte...
3711
3712
  				if (mddev->in_sync == 0) {
  					mddev->in_sync = 1;
31a59e342   NeilBrown   md: fix 'safemode...
3713
3714
  					if (mddev->safemode == 1)
  						mddev->safemode = 0;
070dc6dd7   NeilBrown   md: resolve confu...
3715
  					set_bit(MD_CHANGE_CLEAN, &mddev->flags);
e691063a6   NeilBrown   md: support 'exte...
3716
3717
3718
3719
  				}
  				err = 0;
  			} else
  				err = -EBUSY;
9e653b634   NeilBrown   [PATCH] md: Set/g...
3720
  			spin_unlock_irq(&mddev->write_lock);
5bf295975   NeilBrown   md: remove abilit...
3721
3722
  		} else
  			err = -EINVAL;
9e653b634   NeilBrown   [PATCH] md: Set/g...
3723
3724
3725
3726
  		break;
  	case active:
  		if (mddev->pers) {
  			restart_array(mddev);
070dc6dd7   NeilBrown   md: resolve confu...
3727
  			clear_bit(MD_CHANGE_PENDING, &mddev->flags);
9e653b634   NeilBrown   [PATCH] md: Set/g...
3728
3729
3730
3731
  			wake_up(&mddev->sb_wait);
  			err = 0;
  		} else {
  			mddev->ro = 0;
648b629ed   NeilBrown   md: fix up switch...
3732
  			set_disk_ro(mddev->gendisk, 0);
9e653b634   NeilBrown   [PATCH] md: Set/g...
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
  			err = do_md_run(mddev);
  		}
  		break;
  	case write_pending:
  	case active_idle:
  		/* these cannot be set */
  		break;
  	}
  	if (err)
  		return err;
0fd62b861   Neil Brown   Make sure all cha...
3743
  	else {
1d23f178d   NeilBrown   md: refine interp...
3744
3745
  		if (mddev->hold_active == UNTIL_IOCTL)
  			mddev->hold_active = 0;
00bcb4ac7   NeilBrown   md: reduce depend...
3746
  		sysfs_notify_dirent_safe(mddev->sysfs_state);
9e653b634   NeilBrown   [PATCH] md: Set/g...
3747
  		return len;
0fd62b861   Neil Brown   Make sure all cha...
3748
  	}
9e653b634   NeilBrown   [PATCH] md: Set/g...
3749
  }
80ca3a44f   NeilBrown   [PATCH] md: unify...
3750
3751
  static struct md_sysfs_entry md_array_state =
  __ATTR(array_state, S_IRUGO|S_IWUSR, array_state_show, array_state_store);
9e653b634   NeilBrown   [PATCH] md: Set/g...
3752

6d7ff7380   NeilBrown   [PATCH] md: suppo...
3753
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3754
  max_corrected_read_errors_show(struct mddev *mddev, char *page) {
1e50915fe   Robert Becker   raid: improve MD/...
3755
3756
3757
3758
3759
3760
  	return sprintf(page, "%d
  ",
  		       atomic_read(&mddev->max_corr_read_errors));
  }
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3761
  max_corrected_read_errors_store(struct mddev *mddev, const char *buf, size_t len)
1e50915fe   Robert Becker   raid: improve MD/...
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
  {
  	char *e;
  	unsigned long n = simple_strtoul(buf, &e, 10);
  
  	if (*buf && (*e == 0 || *e == '
  ')) {
  		atomic_set(&mddev->max_corr_read_errors, n);
  		return len;
  	}
  	return -EINVAL;
  }
  
  static struct md_sysfs_entry max_corr_read_errors =
  __ATTR(max_read_errors, S_IRUGO|S_IWUSR, max_corrected_read_errors_show,
  	max_corrected_read_errors_store);
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3779
  null_show(struct mddev *mddev, char *page)
6d7ff7380   NeilBrown   [PATCH] md: suppo...
3780
3781
3782
3783
3784
  {
  	return -EINVAL;
  }
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3785
  new_dev_store(struct mddev *mddev, const char *buf, size_t len)
6d7ff7380   NeilBrown   [PATCH] md: suppo...
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
  {
  	/* buf must be %d:%d
  ? giving major and minor numbers */
  	/* The new device is added to the array.
  	 * If the array has a persistent superblock, we read the
  	 * superblock to initialise info and check validity.
  	 * Otherwise, only checking done is that in bind_rdev_to_array,
  	 * which mainly checks size.
  	 */
  	char *e;
  	int major = simple_strtoul(buf, &e, 10);
  	int minor;
  	dev_t dev;
3cb030020   NeilBrown   md: removing type...
3799
  	struct md_rdev *rdev;
6d7ff7380   NeilBrown   [PATCH] md: suppo...
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
  	int err;
  
  	if (!*buf || *e != ':' || !e[1] || e[1] == '
  ')
  		return -EINVAL;
  	minor = simple_strtoul(e+1, &e, 10);
  	if (*e && *e != '
  ')
  		return -EINVAL;
  	dev = MKDEV(major, minor);
  	if (major != MAJOR(dev) ||
  	    minor != MINOR(dev))
  		return -EOVERFLOW;
  
  
  	if (mddev->persistent) {
  		rdev = md_import_device(dev, mddev->major_version,
  					mddev->minor_version);
  		if (!IS_ERR(rdev) && !list_empty(&mddev->disks)) {
3cb030020   NeilBrown   md: removing type...
3819
3820
3821
  			struct md_rdev *rdev0
  				= list_entry(mddev->disks.next,
  					     struct md_rdev, same_set);
6d7ff7380   NeilBrown   [PATCH] md: suppo...
3822
3823
3824
3825
3826
  			err = super_types[mddev->major_version]
  				.load_super(rdev, rdev0, mddev->minor_version);
  			if (err < 0)
  				goto out;
  		}
c5d79adba   NeilBrown   md: allow devices...
3827
3828
3829
  	} else if (mddev->external)
  		rdev = md_import_device(dev, -2, -1);
  	else
6d7ff7380   NeilBrown   [PATCH] md: suppo...
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
  		rdev = md_import_device(dev, -1, -1);
  
  	if (IS_ERR(rdev))
  		return PTR_ERR(rdev);
  	err = bind_rdev_to_array(rdev, mddev);
   out:
  	if (err)
  		export_rdev(rdev);
  	return err ? err : len;
  }
  
  static struct md_sysfs_entry md_new_device =
80ca3a44f   NeilBrown   [PATCH] md: unify...
3842
  __ATTR(new_dev, S_IWUSR, null_show, new_dev_store);
3b34380ae   NeilBrown   [PATCH] md: allow...
3843
3844
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3845
  bitmap_store(struct mddev *mddev, const char *buf, size_t len)
9b1d1dac1   Paul Clements   [PATCH] md: new s...
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
  {
  	char *end;
  	unsigned long chunk, end_chunk;
  
  	if (!mddev->bitmap)
  		goto out;
  	/* buf should be <chunk> <chunk> ... or <chunk>-<chunk> ... (range) */
  	while (*buf) {
  		chunk = end_chunk = simple_strtoul(buf, &end, 0);
  		if (buf == end) break;
  		if (*end == '-') { /* range */
  			buf = end + 1;
  			end_chunk = simple_strtoul(buf, &end, 0);
  			if (buf == end) break;
  		}
  		if (*end && !isspace(*end)) break;
  		bitmap_dirty_bits(mddev->bitmap, chunk, end_chunk);
e7d2860b6   AndrĂ© Goddard Rosa   tree-wide: conver...
3863
  		buf = skip_spaces(end);
9b1d1dac1   Paul Clements   [PATCH] md: new s...
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
  	}
  	bitmap_unplug(mddev->bitmap); /* flush the bits to disk */
  out:
  	return len;
  }
  
  static struct md_sysfs_entry md_bitmap =
  __ATTR(bitmap_set_bits, S_IWUSR, null_show, bitmap_store);
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3874
  size_show(struct mddev *mddev, char *page)
a35b0d695   NeilBrown   [PATCH] md: allow...
3875
  {
58c0fed40   Andre Noll   md: Make mddev->s...
3876
3877
3878
  	return sprintf(page, "%llu
  ",
  		(unsigned long long)mddev->dev_sectors / 2);
a35b0d695   NeilBrown   [PATCH] md: allow...
3879
  }
fd01b88c7   NeilBrown   md: remove typede...
3880
  static int update_size(struct mddev *mddev, sector_t num_sectors);
a35b0d695   NeilBrown   [PATCH] md: allow...
3881
3882
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3883
  size_store(struct mddev *mddev, const char *buf, size_t len)
a35b0d695   NeilBrown   [PATCH] md: allow...
3884
3885
3886
3887
3888
  {
  	/* If array is inactive, we can reduce the component size, but
  	 * not increase it (except from 0).
  	 * If array is active, we can try an on-line resize
  	 */
b522adcde   Dan Williams   md: 'array_size' ...
3889
3890
  	sector_t sectors;
  	int err = strict_blocks_to_sectors(buf, &sectors);
a35b0d695   NeilBrown   [PATCH] md: allow...
3891

58c0fed40   Andre Noll   md: Make mddev->s...
3892
3893
  	if (err < 0)
  		return err;
a35b0d695   NeilBrown   [PATCH] md: allow...
3894
  	if (mddev->pers) {
58c0fed40   Andre Noll   md: Make mddev->s...
3895
  		err = update_size(mddev, sectors);
850b2b420   NeilBrown   [PATCH] md: repla...
3896
  		md_update_sb(mddev, 1);
a35b0d695   NeilBrown   [PATCH] md: allow...
3897
  	} else {
58c0fed40   Andre Noll   md: Make mddev->s...
3898
3899
3900
  		if (mddev->dev_sectors == 0 ||
  		    mddev->dev_sectors > sectors)
  			mddev->dev_sectors = sectors;
a35b0d695   NeilBrown   [PATCH] md: allow...
3901
3902
3903
3904
3905
3906
3907
  		else
  			err = -ENOSPC;
  	}
  	return err ? err : len;
  }
  
  static struct md_sysfs_entry md_size =
80ca3a44f   NeilBrown   [PATCH] md: unify...
3908
  __ATTR(component_size, S_IRUGO|S_IWUSR, size_show, size_store);
a35b0d695   NeilBrown   [PATCH] md: allow...
3909

8bb93aaca   NeilBrown   [PATCH] md: expos...
3910
3911
  
  /* Metdata version.
e691063a6   NeilBrown   md: support 'exte...
3912
3913
3914
   * This is one of
   *   'none' for arrays with no metadata (good luck...)
   *   'external' for arrays with externally managed metadata,
8bb93aaca   NeilBrown   [PATCH] md: expos...
3915
3916
3917
   * or N.M for internally known formats
   */
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3918
  metadata_show(struct mddev *mddev, char *page)
8bb93aaca   NeilBrown   [PATCH] md: expos...
3919
3920
3921
3922
3923
  {
  	if (mddev->persistent)
  		return sprintf(page, "%d.%d
  ",
  			       mddev->major_version, mddev->minor_version);
e691063a6   NeilBrown   md: support 'exte...
3924
3925
3926
  	else if (mddev->external)
  		return sprintf(page, "external:%s
  ", mddev->metadata_type);
8bb93aaca   NeilBrown   [PATCH] md: expos...
3927
3928
3929
3930
3931
3932
  	else
  		return sprintf(page, "none
  ");
  }
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3933
  metadata_store(struct mddev *mddev, const char *buf, size_t len)
8bb93aaca   NeilBrown   [PATCH] md: expos...
3934
3935
3936
  {
  	int major, minor;
  	char *e;
ea43ddd84   NeilBrown   md: Allow metadat...
3937
3938
3939
3940
3941
3942
3943
  	/* Changing the details of 'external' metadata is
  	 * always permitted.  Otherwise there must be
  	 * no devices attached to the array.
  	 */
  	if (mddev->external && strncmp(buf, "external:", 9) == 0)
  		;
  	else if (!list_empty(&mddev->disks))
8bb93aaca   NeilBrown   [PATCH] md: expos...
3944
3945
3946
3947
  		return -EBUSY;
  
  	if (cmd_match(buf, "none")) {
  		mddev->persistent = 0;
e691063a6   NeilBrown   md: support 'exte...
3948
3949
3950
3951
3952
3953
  		mddev->external = 0;
  		mddev->major_version = 0;
  		mddev->minor_version = 90;
  		return len;
  	}
  	if (strncmp(buf, "external:", 9) == 0) {
20a49ff67   NeilBrown   md: change a few ...
3954
  		size_t namelen = len-9;
e691063a6   NeilBrown   md: support 'exte...
3955
3956
3957
3958
3959
3960
3961
3962
3963
  		if (namelen >= sizeof(mddev->metadata_type))
  			namelen = sizeof(mddev->metadata_type)-1;
  		strncpy(mddev->metadata_type, buf+9, namelen);
  		mddev->metadata_type[namelen] = 0;
  		if (namelen && mddev->metadata_type[namelen-1] == '
  ')
  			mddev->metadata_type[--namelen] = 0;
  		mddev->persistent = 0;
  		mddev->external = 1;
8bb93aaca   NeilBrown   [PATCH] md: expos...
3964
3965
3966
3967
3968
3969
3970
3971
3972
  		mddev->major_version = 0;
  		mddev->minor_version = 90;
  		return len;
  	}
  	major = simple_strtoul(buf, &e, 10);
  	if (e==buf || *e != '.')
  		return -EINVAL;
  	buf = e+1;
  	minor = simple_strtoul(buf, &e, 10);
3f9d7b0d8   NeilBrown   [PATCH] md: fix a...
3973
3974
  	if (e==buf || (*e && *e != '
  ') )
8bb93aaca   NeilBrown   [PATCH] md: expos...
3975
  		return -EINVAL;
50511da3d   Ahmed S. Darwish   drivers/md.c: Use...
3976
  	if (major >= ARRAY_SIZE(super_types) || super_types[major].name == NULL)
8bb93aaca   NeilBrown   [PATCH] md: expos...
3977
3978
3979
3980
  		return -ENOENT;
  	mddev->major_version = major;
  	mddev->minor_version = minor;
  	mddev->persistent = 1;
e691063a6   NeilBrown   md: support 'exte...
3981
  	mddev->external = 0;
8bb93aaca   NeilBrown   [PATCH] md: expos...
3982
3983
3984
3985
  	return len;
  }
  
  static struct md_sysfs_entry md_metadata =
80ca3a44f   NeilBrown   [PATCH] md: unify...
3986
  __ATTR(metadata_version, S_IRUGO|S_IWUSR, metadata_show, metadata_store);
8bb93aaca   NeilBrown   [PATCH] md: expos...
3987

a35b0d695   NeilBrown   [PATCH] md: allow...
3988
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
3989
  action_show(struct mddev *mddev, char *page)
24dd469d7   NeilBrown   [PATCH] md: allow...
3990
  {
7eec314d7   NeilBrown   [PATCH] md: impro...
3991
  	char *type = "idle";
b6a9ce688   NeilBrown   md: export 'froze...
3992
3993
3994
  	if (test_bit(MD_RECOVERY_FROZEN, &mddev->recovery))
  		type = "frozen";
  	else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
2b12ab6d3   NeilBrown   md: 'sync_action'...
3995
  	    (!mddev->ro && test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))) {
ccfcc3c10   NeilBrown   [PATCH] md: Core ...
3996
3997
3998
  		if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
  			type = "reshape";
  		else if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
24dd469d7   NeilBrown   [PATCH] md: allow...
3999
4000
4001
4002
4003
4004
  			if (!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
  				type = "resync";
  			else if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
  				type = "check";
  			else
  				type = "repair";
72a23c211   Neil Brown   Make sure all cha...
4005
  		} else if (test_bit(MD_RECOVERY_RECOVER, &mddev->recovery))
24dd469d7   NeilBrown   [PATCH] md: allow...
4006
4007
4008
4009
4010
  			type = "recover";
  	}
  	return sprintf(page, "%s
  ", type);
  }
fd01b88c7   NeilBrown   md: remove typede...
4011
  static void reap_sync_thread(struct mddev *mddev);
7ebc0be7f   NeilBrown   md: Be more caref...
4012

24dd469d7   NeilBrown   [PATCH] md: allow...
4013
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4014
  action_store(struct mddev *mddev, const char *page, size_t len)
24dd469d7   NeilBrown   [PATCH] md: allow...
4015
  {
7eec314d7   NeilBrown   [PATCH] md: impro...
4016
4017
  	if (!mddev->pers || !mddev->pers->sync_request)
  		return -EINVAL;
b6a9ce688   NeilBrown   md: export 'froze...
4018
4019
4020
4021
4022
4023
  	if (cmd_match(page, "frozen"))
  		set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
  	else
  		clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
  
  	if (cmd_match(page, "idle") || cmd_match(page, "frozen")) {
7eec314d7   NeilBrown   [PATCH] md: impro...
4024
4025
  		if (mddev->sync_thread) {
  			set_bit(MD_RECOVERY_INTR, &mddev->recovery);
7ebc0be7f   NeilBrown   md: Be more caref...
4026
  			reap_sync_thread(mddev);
7eec314d7   NeilBrown   [PATCH] md: impro...
4027
  		}
03c902e17   NeilBrown   [PATCH] md: fix r...
4028
4029
  	} else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
  		   test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
24dd469d7   NeilBrown   [PATCH] md: allow...
4030
  		return -EBUSY;
72a23c211   Neil Brown   Make sure all cha...
4031
4032
4033
4034
  	else if (cmd_match(page, "resync"))
  		set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
  	else if (cmd_match(page, "recover")) {
  		set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
7eec314d7   NeilBrown   [PATCH] md: impro...
4035
  		set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
72a23c211   Neil Brown   Make sure all cha...
4036
  	} else if (cmd_match(page, "reshape")) {
16484bf59   NeilBrown   [PATCH] md: Make ...
4037
4038
4039
4040
4041
4042
  		int err;
  		if (mddev->pers->start_reshape == NULL)
  			return -EINVAL;
  		err = mddev->pers->start_reshape(mddev);
  		if (err)
  			return err;
a99ac9711   Neil Brown   Make sure all cha...
4043
  		sysfs_notify(&mddev->kobj, NULL, "degraded");
16484bf59   NeilBrown   [PATCH] md: Make ...
4044
  	} else {
bce74dac0   NeilBrown   [PATCH] md: helpe...
4045
  		if (cmd_match(page, "check"))
7eec314d7   NeilBrown   [PATCH] md: impro...
4046
  			set_bit(MD_RECOVERY_CHECK, &mddev->recovery);
2adc7d47c   NeilBrown   [PATCH] md: Fix i...
4047
  		else if (!cmd_match(page, "repair"))
7eec314d7   NeilBrown   [PATCH] md: impro...
4048
4049
4050
  			return -EINVAL;
  		set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
  		set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
7eec314d7   NeilBrown   [PATCH] md: impro...
4051
  	}
03c902e17   NeilBrown   [PATCH] md: fix r...
4052
  	set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
24dd469d7   NeilBrown   [PATCH] md: allow...
4053
  	md_wakeup_thread(mddev->thread);
00bcb4ac7   NeilBrown   md: reduce depend...
4054
  	sysfs_notify_dirent_safe(mddev->sysfs_action);
24dd469d7   NeilBrown   [PATCH] md: allow...
4055
4056
  	return len;
  }
9d88883e6   NeilBrown   [PATCH] md: teach...
4057
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4058
  mismatch_cnt_show(struct mddev *mddev, char *page)
9d88883e6   NeilBrown   [PATCH] md: teach...
4059
4060
4061
4062
4063
  {
  	return sprintf(page, "%llu
  ",
  		       (unsigned long long) mddev->resync_mismatches);
  }
80ca3a44f   NeilBrown   [PATCH] md: unify...
4064
4065
  static struct md_sysfs_entry md_scan_mode =
  __ATTR(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);
24dd469d7   NeilBrown   [PATCH] md: allow...
4066

96de1e663   NeilBrown   [PATCH] md: fix s...
4067

80ca3a44f   NeilBrown   [PATCH] md: unify...
4068
  static struct md_sysfs_entry md_mismatches = __ATTR_RO(mismatch_cnt);
9d88883e6   NeilBrown   [PATCH] md: teach...
4069

88202a0c8   NeilBrown   [PATCH] md: allow...
4070
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4071
  sync_min_show(struct mddev *mddev, char *page)
88202a0c8   NeilBrown   [PATCH] md: allow...
4072
4073
4074
4075
4076
4077
4078
  {
  	return sprintf(page, "%d (%s)
  ", speed_min(mddev),
  		       mddev->sync_speed_min ? "local": "system");
  }
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4079
  sync_min_store(struct mddev *mddev, const char *buf, size_t len)
88202a0c8   NeilBrown   [PATCH] md: allow...
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
  {
  	int min;
  	char *e;
  	if (strncmp(buf, "system", 6)==0) {
  		mddev->sync_speed_min = 0;
  		return len;
  	}
  	min = simple_strtoul(buf, &e, 10);
  	if (buf == e || (*e && *e != '
  ') || min <= 0)
  		return -EINVAL;
  	mddev->sync_speed_min = min;
  	return len;
  }
  
  static struct md_sysfs_entry md_sync_min =
  __ATTR(sync_speed_min, S_IRUGO|S_IWUSR, sync_min_show, sync_min_store);
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4099
  sync_max_show(struct mddev *mddev, char *page)
88202a0c8   NeilBrown   [PATCH] md: allow...
4100
4101
4102
4103
4104
4105
4106
  {
  	return sprintf(page, "%d (%s)
  ", speed_max(mddev),
  		       mddev->sync_speed_max ? "local": "system");
  }
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4107
  sync_max_store(struct mddev *mddev, const char *buf, size_t len)
88202a0c8   NeilBrown   [PATCH] md: allow...
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
  {
  	int max;
  	char *e;
  	if (strncmp(buf, "system", 6)==0) {
  		mddev->sync_speed_max = 0;
  		return len;
  	}
  	max = simple_strtoul(buf, &e, 10);
  	if (buf == e || (*e && *e != '
  ') || max <= 0)
  		return -EINVAL;
  	mddev->sync_speed_max = max;
  	return len;
  }
  
  static struct md_sysfs_entry md_sync_max =
  __ATTR(sync_speed_max, S_IRUGO|S_IWUSR, sync_max_show, sync_max_store);
d7f3d291a   Iustin Pop   md: expose the de...
4125
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4126
  degraded_show(struct mddev *mddev, char *page)
d7f3d291a   Iustin Pop   md: expose the de...
4127
4128
4129
4130
4131
  {
  	return sprintf(page, "%d
  ", mddev->degraded);
  }
  static struct md_sysfs_entry md_degraded = __ATTR_RO(degraded);
88202a0c8   NeilBrown   [PATCH] md: allow...
4132
4133
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4134
  sync_force_parallel_show(struct mddev *mddev, char *page)
90b08710e   Bernd Schubert   md: allow paralle...
4135
4136
4137
4138
4139
4140
  {
  	return sprintf(page, "%d
  ", mddev->parallel_resync);
  }
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4141
  sync_force_parallel_store(struct mddev *mddev, const char *buf, size_t len)
90b08710e   Bernd Schubert   md: allow paralle...
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
  {
  	long n;
  
  	if (strict_strtol(buf, 10, &n))
  		return -EINVAL;
  
  	if (n != 0 && n != 1)
  		return -EINVAL;
  
  	mddev->parallel_resync = n;
  
  	if (mddev->sync_thread)
  		wake_up(&resync_wait);
  
  	return len;
  }
  
  /* force parallel resync, even with shared block devices */
  static struct md_sysfs_entry md_sync_force_parallel =
  __ATTR(sync_force_parallel, S_IRUGO|S_IWUSR,
         sync_force_parallel_show, sync_force_parallel_store);
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4165
  sync_speed_show(struct mddev *mddev, char *page)
88202a0c8   NeilBrown   [PATCH] md: allow...
4166
4167
  {
  	unsigned long resync, dt, db;
d1a7c5036   NeilBrown   md: don't display...
4168
4169
4170
  	if (mddev->curr_resync == 0)
  		return sprintf(page, "none
  ");
9687a60c7   Andre Noll   md: sync_speed_sh...
4171
4172
  	resync = mddev->curr_mark_cnt - atomic_read(&mddev->recovery_active);
  	dt = (jiffies - mddev->resync_mark) / HZ;
88202a0c8   NeilBrown   [PATCH] md: allow...
4173
  	if (!dt) dt++;
9687a60c7   Andre Noll   md: sync_speed_sh...
4174
4175
4176
  	db = resync - mddev->resync_mark_cnt;
  	return sprintf(page, "%lu
  ", db/dt/2); /* K/sec */
88202a0c8   NeilBrown   [PATCH] md: allow...
4177
  }
80ca3a44f   NeilBrown   [PATCH] md: unify...
4178
  static struct md_sysfs_entry md_sync_speed = __ATTR_RO(sync_speed);
88202a0c8   NeilBrown   [PATCH] md: allow...
4179
4180
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4181
  sync_completed_show(struct mddev *mddev, char *page)
88202a0c8   NeilBrown   [PATCH] md: allow...
4182
  {
13ae864bc   RĂ©mi RĂ©rolle   md: fix sync_comp...
4183
  	unsigned long long max_sectors, resync;
88202a0c8   NeilBrown   [PATCH] md: allow...
4184

acb180b0e   NeilBrown   md: improve usefu...
4185
4186
4187
  	if (!test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
  		return sprintf(page, "none
  ");
88202a0c8   NeilBrown   [PATCH] md: allow...
4188
  	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
58c0fed40   Andre Noll   md: Make mddev->s...
4189
  		max_sectors = mddev->resync_max_sectors;
88202a0c8   NeilBrown   [PATCH] md: allow...
4190
  	else
58c0fed40   Andre Noll   md: Make mddev->s...
4191
  		max_sectors = mddev->dev_sectors;
88202a0c8   NeilBrown   [PATCH] md: allow...
4192

acb180b0e   NeilBrown   md: improve usefu...
4193
  	resync = mddev->curr_resync_completed;
13ae864bc   RĂ©mi RĂ©rolle   md: fix sync_comp...
4194
4195
  	return sprintf(page, "%llu / %llu
  ", resync, max_sectors);
88202a0c8   NeilBrown   [PATCH] md: allow...
4196
  }
80ca3a44f   NeilBrown   [PATCH] md: unify...
4197
  static struct md_sysfs_entry md_sync_completed = __ATTR_RO(sync_completed);
88202a0c8   NeilBrown   [PATCH] md: allow...
4198

e464eafdb   NeilBrown   [PATCH] md: Suppo...
4199
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4200
  min_sync_show(struct mddev *mddev, char *page)
5e96ee65c   Neil Brown   Allow setting sta...
4201
4202
4203
4204
4205
4206
  {
  	return sprintf(page, "%llu
  ",
  		       (unsigned long long)mddev->resync_min);
  }
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4207
  min_sync_store(struct mddev *mddev, const char *buf, size_t len)
5e96ee65c   Neil Brown   Allow setting sta...
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
  {
  	unsigned long long min;
  	if (strict_strtoull(buf, 10, &min))
  		return -EINVAL;
  	if (min > mddev->resync_max)
  		return -EINVAL;
  	if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
  		return -EBUSY;
  
  	/* Must be a multiple of chunk_size */
9d8f03636   Andre Noll   md: Make mddev->c...
4218
  	if (mddev->chunk_sectors) {
2ac06c333   raz ben yehuda   md: prepare for n...
4219
  		sector_t temp = min;
9d8f03636   Andre Noll   md: Make mddev->c...
4220
  		if (sector_div(temp, mddev->chunk_sectors))
5e96ee65c   Neil Brown   Allow setting sta...
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
  			return -EINVAL;
  	}
  	mddev->resync_min = min;
  
  	return len;
  }
  
  static struct md_sysfs_entry md_min_sync =
  __ATTR(sync_min, S_IRUGO|S_IWUSR, min_sync_show, min_sync_store);
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4232
  max_sync_show(struct mddev *mddev, char *page)
c62072777   NeilBrown   md: allow a maxim...
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
  {
  	if (mddev->resync_max == MaxSector)
  		return sprintf(page, "max
  ");
  	else
  		return sprintf(page, "%llu
  ",
  			       (unsigned long long)mddev->resync_max);
  }
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4243
  max_sync_store(struct mddev *mddev, const char *buf, size_t len)
c62072777   NeilBrown   md: allow a maxim...
4244
4245
4246
4247
  {
  	if (strncmp(buf, "max", 3) == 0)
  		mddev->resync_max = MaxSector;
  	else {
5e96ee65c   Neil Brown   Allow setting sta...
4248
4249
4250
4251
  		unsigned long long max;
  		if (strict_strtoull(buf, 10, &max))
  			return -EINVAL;
  		if (max < mddev->resync_min)
c62072777   NeilBrown   md: allow a maxim...
4252
4253
  			return -EINVAL;
  		if (max < mddev->resync_max &&
4d484a4a7   NeilBrown   md: allow upper l...
4254
  		    mddev->ro == 0 &&
c62072777   NeilBrown   md: allow a maxim...
4255
4256
4257
4258
  		    test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
  			return -EBUSY;
  
  		/* Must be a multiple of chunk_size */
9d8f03636   Andre Noll   md: Make mddev->c...
4259
  		if (mddev->chunk_sectors) {
2ac06c333   raz ben yehuda   md: prepare for n...
4260
  			sector_t temp = max;
9d8f03636   Andre Noll   md: Make mddev->c...
4261
  			if (sector_div(temp, mddev->chunk_sectors))
c62072777   NeilBrown   md: allow a maxim...
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
  				return -EINVAL;
  		}
  		mddev->resync_max = max;
  	}
  	wake_up(&mddev->recovery_wait);
  	return len;
  }
  
  static struct md_sysfs_entry md_max_sync =
  __ATTR(sync_max, S_IRUGO|S_IWUSR, max_sync_show, max_sync_store);
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4274
  suspend_lo_show(struct mddev *mddev, char *page)
e464eafdb   NeilBrown   [PATCH] md: Suppo...
4275
4276
4277
4278
4279
4280
  {
  	return sprintf(page, "%llu
  ", (unsigned long long)mddev->suspend_lo);
  }
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4281
  suspend_lo_store(struct mddev *mddev, const char *buf, size_t len)
e464eafdb   NeilBrown   [PATCH] md: Suppo...
4282
4283
4284
  {
  	char *e;
  	unsigned long long new = simple_strtoull(buf, &e, 10);
23ddff379   NeilBrown   md: allow suspend...
4285
  	unsigned long long old = mddev->suspend_lo;
e464eafdb   NeilBrown   [PATCH] md: Suppo...
4286

b8d966efd   NeilBrown   md: avoid derefer...
4287
4288
  	if (mddev->pers == NULL || 
  	    mddev->pers->quiesce == NULL)
e464eafdb   NeilBrown   [PATCH] md: Suppo...
4289
4290
4291
4292
  		return -EINVAL;
  	if (buf == e || (*e && *e != '
  '))
  		return -EINVAL;
23ddff379   NeilBrown   md: allow suspend...
4293
4294
4295
4296
  
  	mddev->suspend_lo = new;
  	if (new >= old)
  		/* Shrinking suspended region */
e464eafdb   NeilBrown   [PATCH] md: Suppo...
4297
  		mddev->pers->quiesce(mddev, 2);
23ddff379   NeilBrown   md: allow suspend...
4298
4299
4300
4301
4302
4303
  	else {
  		/* Expanding suspended region - need to wait */
  		mddev->pers->quiesce(mddev, 1);
  		mddev->pers->quiesce(mddev, 0);
  	}
  	return len;
e464eafdb   NeilBrown   [PATCH] md: Suppo...
4304
4305
4306
4307
4308
4309
  }
  static struct md_sysfs_entry md_suspend_lo =
  __ATTR(suspend_lo, S_IRUGO|S_IWUSR, suspend_lo_show, suspend_lo_store);
  
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4310
  suspend_hi_show(struct mddev *mddev, char *page)
e464eafdb   NeilBrown   [PATCH] md: Suppo...
4311
4312
4313
4314
4315
4316
  {
  	return sprintf(page, "%llu
  ", (unsigned long long)mddev->suspend_hi);
  }
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4317
  suspend_hi_store(struct mddev *mddev, const char *buf, size_t len)
e464eafdb   NeilBrown   [PATCH] md: Suppo...
4318
4319
4320
  {
  	char *e;
  	unsigned long long new = simple_strtoull(buf, &e, 10);
23ddff379   NeilBrown   md: allow suspend...
4321
  	unsigned long long old = mddev->suspend_hi;
e464eafdb   NeilBrown   [PATCH] md: Suppo...
4322

b8d966efd   NeilBrown   md: avoid derefer...
4323
4324
  	if (mddev->pers == NULL ||
  	    mddev->pers->quiesce == NULL)
e464eafdb   NeilBrown   [PATCH] md: Suppo...
4325
4326
4327
4328
  		return -EINVAL;
  	if (buf == e || (*e && *e != '
  '))
  		return -EINVAL;
23ddff379   NeilBrown   md: allow suspend...
4329
4330
4331
4332
4333
4334
4335
  
  	mddev->suspend_hi = new;
  	if (new <= old)
  		/* Shrinking suspended region */
  		mddev->pers->quiesce(mddev, 2);
  	else {
  		/* Expanding suspended region - need to wait */
e464eafdb   NeilBrown   [PATCH] md: Suppo...
4336
4337
  		mddev->pers->quiesce(mddev, 1);
  		mddev->pers->quiesce(mddev, 0);
23ddff379   NeilBrown   md: allow suspend...
4338
4339
  	}
  	return len;
e464eafdb   NeilBrown   [PATCH] md: Suppo...
4340
4341
4342
  }
  static struct md_sysfs_entry md_suspend_hi =
  __ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store);
08a02ecd2   NeilBrown   md: allow reshape...
4343
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4344
  reshape_position_show(struct mddev *mddev, char *page)
08a02ecd2   NeilBrown   md: allow reshape...
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
  {
  	if (mddev->reshape_position != MaxSector)
  		return sprintf(page, "%llu
  ",
  			       (unsigned long long)mddev->reshape_position);
  	strcpy(page, "none
  ");
  	return 5;
  }
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4356
  reshape_position_store(struct mddev *mddev, const char *buf, size_t len)
08a02ecd2   NeilBrown   md: allow reshape...
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
  {
  	char *e;
  	unsigned long long new = simple_strtoull(buf, &e, 10);
  	if (mddev->pers)
  		return -EBUSY;
  	if (buf == e || (*e && *e != '
  '))
  		return -EINVAL;
  	mddev->reshape_position = new;
  	mddev->delta_disks = 0;
  	mddev->new_level = mddev->level;
  	mddev->new_layout = mddev->layout;
664e7c413   Andre Noll   md: Convert mddev...
4369
  	mddev->new_chunk_sectors = mddev->chunk_sectors;
08a02ecd2   NeilBrown   md: allow reshape...
4370
4371
4372
4373
4374
4375
  	return len;
  }
  
  static struct md_sysfs_entry md_reshape_position =
  __ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show,
         reshape_position_store);
b522adcde   Dan Williams   md: 'array_size' ...
4376
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4377
  array_size_show(struct mddev *mddev, char *page)
b522adcde   Dan Williams   md: 'array_size' ...
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
  {
  	if (mddev->external_size)
  		return sprintf(page, "%llu
  ",
  			       (unsigned long long)mddev->array_sectors/2);
  	else
  		return sprintf(page, "default
  ");
  }
  
  static ssize_t
fd01b88c7   NeilBrown   md: remove typede...
4389
  array_size_store(struct mddev *mddev, const char *buf, size_t len)
b522adcde   Dan Williams   md: 'array_size' ...
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
  {
  	sector_t sectors;
  
  	if (strncmp(buf, "default", 7) == 0) {
  		if (mddev->pers)
  			sectors = mddev->pers->size(mddev, 0, 0);
  		else
  			sectors = mddev->array_sectors;
  
  		mddev->external_size = 0;
  	} else {
  		if (strict_blocks_to_sectors(buf, &sectors) < 0)
  			return -EINVAL;
  		if (mddev->pers && mddev->pers->size(mddev, 0, 0) < sectors)
2b69c8392   NeilBrown   md: improve errno...
4404
  			return -E2BIG;
b522adcde   Dan Williams   md: 'array_size' ...
4405
4406
4407
4408
4409
  
  		mddev->external_size = 1;
  	}
  
  	mddev->array_sectors = sectors;
cbe6ef1d2   NeilBrown   md: don't set_cap...
4410
4411
  	if (mddev->pers) {
  		set_capacity(mddev->gendisk, mddev->array_sectors);
449aad3e2   NeilBrown   md: Use revalidat...
4412
  		revalidate_disk(mddev->gendisk);
cbe6ef1d2   NeilBrown   md: don't set_cap...
4413
  	}
b522adcde   Dan Williams   md: 'array_size' ...
4414
4415
4416
4417
4418
4419
  	return len;
  }
  
  static struct md_sysfs_entry md_array_size =
  __ATTR(array_size, S_IRUGO|S_IWUSR, array_size_show,
         array_size_store);
e464eafdb   NeilBrown   [PATCH] md: Suppo...
4420

eae1701fb   NeilBrown   [PATCH] md: initi...
4421
4422
  static struct attribute *md_default_attrs[] = {
  	&md_level.attr,
d4dbd0250   NeilBrown   [PATCH] md: Allow...
4423
  	&md_layout.attr,
eae1701fb   NeilBrown   [PATCH] md: initi...
4424
  	&md_raid_disks.attr,
3b34380ae   NeilBrown   [PATCH] md: allow...
4425
  	&md_chunk_size.attr,
a35b0d695   NeilBrown   [PATCH] md: allow...
4426
  	&md_size.attr,
a94213b1f   NeilBrown   [PATCH] md: Allow...
4427
  	&md_resync_start.attr,
8bb93aaca   NeilBrown   [PATCH] md: expos...
4428
  	&md_metadata.attr,
6d7ff7380   NeilBrown   [PATCH] md: suppo...
4429
  	&md_new_device.attr,
16f17b39f   NeilBrown   [PATCH] md: incre...
4430
  	&md_safe_delay.attr,
9e653b634   NeilBrown   [PATCH] md: Set/g...
4431
  	&md_array_state.attr,
08a02ecd2   NeilBrown   md: allow reshape...
4432
  	&md_reshape_position.attr,
b522adcde   Dan Williams   md: 'array_size' ...
4433
  	&md_array_size.attr,
1e50915fe   Robert Becker   raid: improve MD/...
4434
  	&max_corr_read_errors.attr,
411036fa1   NeilBrown   [PATCH] md: split...
4435
4436
4437
4438
  	NULL,
  };
  
  static struct attribute *md_redundancy_attrs[] = {
24dd469d7   NeilBrown   [PATCH] md: allow...
4439
  	&md_scan_mode.attr,
9d88883e6   NeilBrown   [PATCH] md: teach...
4440
  	&md_mismatches.attr,
88202a0c8   NeilBrown   [PATCH] md: allow...
4441
4442
4443
  	&md_sync_min.attr,
  	&md_sync_max.attr,
  	&md_sync_speed.attr,
90b08710e   Bernd Schubert   md: allow paralle...
4444
  	&md_sync_force_parallel.attr,
88202a0c8   NeilBrown   [PATCH] md: allow...
4445
  	&md_sync_completed.attr,
5e96ee65c   Neil Brown   Allow setting sta...
4446
  	&md_min_sync.attr,
c62072777   NeilBrown   md: allow a maxim...
4447
  	&md_max_sync.attr,
e464eafdb   NeilBrown   [PATCH] md: Suppo...
4448
4449
  	&md_suspend_lo.attr,
  	&md_suspend_hi.attr,
9b1d1dac1   Paul Clements   [PATCH] md: new s...
4450
  	&md_bitmap.attr,
d7f3d291a   Iustin Pop   md: expose the de...
4451
  	&md_degraded.attr,
eae1701fb   NeilBrown   [PATCH] md: initi...
4452
4453
  	NULL,
  };
411036fa1   NeilBrown   [PATCH] md: split...
4454
4455
4456
4457
  static struct attribute_group md_redundancy_group = {
  	.name = NULL,
  	.attrs = md_redundancy_attrs,
  };
eae1701fb   NeilBrown   [PATCH] md: initi...
4458
4459
4460
4461
4462
  
  static ssize_t
  md_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
  {
  	struct md_sysfs_entry *entry = container_of(attr, struct md_sysfs_entry, attr);
fd01b88c7   NeilBrown   md: remove typede...
4463
  	struct mddev *mddev = container_of(kobj, struct mddev, kobj);
96de1e663   NeilBrown   [PATCH] md: fix s...
4464
  	ssize_t rv;
eae1701fb   NeilBrown   [PATCH] md: initi...
4465
4466
4467
  
  	if (!entry->show)
  		return -EIO;
af8a24347   NeilBrown   md: take a refere...
4468
4469
4470
4471
4472
4473
4474
  	spin_lock(&all_mddevs_lock);
  	if (list_empty(&mddev->all_mddevs)) {
  		spin_unlock(&all_mddevs_lock);
  		return -EBUSY;
  	}
  	mddev_get(mddev);
  	spin_unlock(&all_mddevs_lock);
5dc5cf7dd   Ingo Molnar   [PATCH] md: locki...
4475
4476
4477
4478
4479
  	rv = mddev_lock(mddev);
  	if (!rv) {
  		rv = entry->show(mddev, page);
  		mddev_unlock(mddev);
  	}
af8a24347   NeilBrown   md: take a refere...
4480
  	mddev_put(mddev);
96de1e663   NeilBrown   [PATCH] md: fix s...
4481
  	return rv;
eae1701fb   NeilBrown   [PATCH] md: initi...
4482
4483
4484
4485
4486
4487
4488
  }
  
  static ssize_t
  md_attr_store(struct kobject *kobj, struct attribute *attr,
  	      const char *page, size_t length)
  {
  	struct md_sysfs_entry *entry = container_of(attr, struct md_sysfs_entry, attr);
fd01b88c7   NeilBrown   md: remove typede...
4489
  	struct mddev *mddev = container_of(kobj, struct mddev, kobj);
96de1e663   NeilBrown   [PATCH] md: fix s...
4490
  	ssize_t rv;
eae1701fb   NeilBrown   [PATCH] md: initi...
4491
4492
4493
  
  	if (!entry->store)
  		return -EIO;
67463acb6   NeilBrown   [PATCH] md: requi...
4494
4495
  	if (!capable(CAP_SYS_ADMIN))
  		return -EACCES;
af8a24347   NeilBrown   md: take a refere...
4496
4497
4498
4499
4500
4501
4502
  	spin_lock(&all_mddevs_lock);
  	if (list_empty(&mddev->all_mddevs)) {
  		spin_unlock(&all_mddevs_lock);
  		return -EBUSY;
  	}
  	mddev_get(mddev);
  	spin_unlock(&all_mddevs_lock);
5dc5cf7dd   Ingo Molnar   [PATCH] md: locki...
4503
4504
4505
4506
4507
  	rv = mddev_lock(mddev);
  	if (!rv) {
  		rv = entry->store(mddev, page, length);
  		mddev_unlock(mddev);
  	}
af8a24347   NeilBrown   md: take a refere...
4508
  	mddev_put(mddev);
96de1e663   NeilBrown   [PATCH] md: fix s...
4509
  	return rv;
eae1701fb   NeilBrown   [PATCH] md: initi...
4510
4511
4512
4513
  }
  
  static void md_free(struct kobject *ko)
  {
fd01b88c7   NeilBrown   md: remove typede...
4514
  	struct mddev *mddev = container_of(ko, struct mddev, kobj);
a21d15042   NeilBrown   md: centralise al...
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
  
  	if (mddev->sysfs_state)
  		sysfs_put(mddev->sysfs_state);
  
  	if (mddev->gendisk) {
  		del_gendisk(mddev->gendisk);
  		put_disk(mddev->gendisk);
  	}
  	if (mddev->queue)
  		blk_cleanup_queue(mddev->queue);
eae1701fb   NeilBrown   [PATCH] md: initi...
4525
4526
  	kfree(mddev);
  }
52cf25d0a   Emese Revfy   Driver core: Cons...
4527
  static const struct sysfs_ops md_sysfs_ops = {
eae1701fb   NeilBrown   [PATCH] md: initi...
4528
4529
4530
4531
4532
4533
4534
4535
  	.show	= md_attr_show,
  	.store	= md_attr_store,
  };
  static struct kobj_type md_ktype = {
  	.release	= md_free,
  	.sysfs_ops	= &md_sysfs_ops,
  	.default_attrs	= md_default_attrs,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4536
  int mdp_major = 0;
5fd3a17ed   Dan Williams   md: fix deadlock ...
4537
4538
  static void mddev_delayed_delete(struct work_struct *ws)
  {
fd01b88c7   NeilBrown   md: remove typede...
4539
  	struct mddev *mddev = container_of(ws, struct mddev, del_work);
5fd3a17ed   Dan Williams   md: fix deadlock ...
4540

43a705076   NeilBrown   md: support updat...
4541
  	sysfs_remove_group(&mddev->kobj, &md_bitmap_group);
5fd3a17ed   Dan Williams   md: fix deadlock ...
4542
4543
4544
  	kobject_del(&mddev->kobj);
  	kobject_put(&mddev->kobj);
  }
efeb53c0e   NeilBrown   md: Allow md devi...
4545
  static int md_alloc(dev_t dev, char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4546
  {
48c9c27b8   Arjan van de Ven   [PATCH] sem2mutex...
4547
  	static DEFINE_MUTEX(disks_mutex);
fd01b88c7   NeilBrown   md: remove typede...
4548
  	struct mddev *mddev = mddev_find(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4549
  	struct gendisk *disk;
efeb53c0e   NeilBrown   md: Allow md devi...
4550
4551
4552
  	int partitioned;
  	int shift;
  	int unit;
3830c62fe   Greg Kroah-Hartman   Kobject: change d...
4553
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4554
4555
  
  	if (!mddev)
efeb53c0e   NeilBrown   md: Allow md devi...
4556
4557
4558
4559
4560
  		return -ENODEV;
  
  	partitioned = (MAJOR(mddev->unit) != MD_MAJOR);
  	shift = partitioned ? MdpMinorShift : 0;
  	unit = MINOR(mddev->unit) >> shift;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4561

e804ac780   Tejun Heo   md: fix and updat...
4562
4563
  	/* wait for any previous instance of this device to be
  	 * completely removed (mddev_delayed_delete).
d3374825c   NeilBrown   md: make devices ...
4564
  	 */
e804ac780   Tejun Heo   md: fix and updat...
4565
  	flush_workqueue(md_misc_wq);
d3374825c   NeilBrown   md: make devices ...
4566

48c9c27b8   Arjan van de Ven   [PATCH] sem2mutex...
4567
  	mutex_lock(&disks_mutex);
0909dc448   NeilBrown   md: tidy up error...
4568
4569
4570
  	error = -EEXIST;
  	if (mddev->gendisk)
  		goto abort;
efeb53c0e   NeilBrown   md: Allow md devi...
4571
4572
4573
4574
  
  	if (name) {
  		/* Need to ensure that 'name' is not a duplicate.
  		 */
fd01b88c7   NeilBrown   md: remove typede...
4575
  		struct mddev *mddev2;
efeb53c0e   NeilBrown   md: Allow md devi...
4576
4577
4578
4579
4580
4581
  		spin_lock(&all_mddevs_lock);
  
  		list_for_each_entry(mddev2, &all_mddevs, all_mddevs)
  			if (mddev2->gendisk &&
  			    strcmp(mddev2->gendisk->disk_name, name) == 0) {
  				spin_unlock(&all_mddevs_lock);
0909dc448   NeilBrown   md: tidy up error...
4582
  				goto abort;
efeb53c0e   NeilBrown   md: Allow md devi...
4583
4584
  			}
  		spin_unlock(&all_mddevs_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4585
  	}
8b7653982   NeilBrown   md: move allocati...
4586

0909dc448   NeilBrown   md: tidy up error...
4587
  	error = -ENOMEM;
8b7653982   NeilBrown   md: move allocati...
4588
  	mddev->queue = blk_alloc_queue(GFP_KERNEL);
0909dc448   NeilBrown   md: tidy up error...
4589
4590
  	if (!mddev->queue)
  		goto abort;
409c57f38   NeilBrown   md: enable suspen...
4591
  	mddev->queue->queuedata = mddev;
409c57f38   NeilBrown   md: enable suspen...
4592
  	blk_queue_make_request(mddev->queue, md_make_request);
8b7653982   NeilBrown   md: move allocati...
4593

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4594
4595
  	disk = alloc_disk(1 << shift);
  	if (!disk) {
8b7653982   NeilBrown   md: move allocati...
4596
4597
  		blk_cleanup_queue(mddev->queue);
  		mddev->queue = NULL;
0909dc448   NeilBrown   md: tidy up error...
4598
  		goto abort;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4599
  	}
efeb53c0e   NeilBrown   md: Allow md devi...
4600
  	disk->major = MAJOR(mddev->unit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4601
  	disk->first_minor = unit << shift;
efeb53c0e   NeilBrown   md: Allow md devi...
4602
4603
4604
  	if (name)
  		strcpy(disk->disk_name, name);
  	else if (partitioned)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4605
  		sprintf(disk->disk_name, "md_d%d", unit);
ce7b0f46b   Greg Kroah-Hartman   [PATCH] devfs: Re...
4606
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4607
  		sprintf(disk->disk_name, "md%d", unit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4608
4609
4610
  	disk->fops = &md_fops;
  	disk->private_data = mddev;
  	disk->queue = mddev->queue;
b0140891a   NeilBrown   md: Fix race when...
4611
  	blk_queue_flush(mddev->queue, REQ_FLUSH | REQ_FUA);
92850bbd7   NeilBrown   md: allow extende...
4612
  	/* Allow extended partitions.  This makes the
d3374825c   NeilBrown   md: make devices ...
4613
  	 * 'mdp' device redundant, but we can't really
92850bbd7   NeilBrown   md: allow extende...
4614
4615
4616
  	 * remove it now.
  	 */
  	disk->flags |= GENHD_FL_EXT_DEVT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4617
  	mddev->gendisk = disk;
b0140891a   NeilBrown   md: Fix race when...
4618
4619
4620
4621
4622
  	/* As soon as we call add_disk(), another thread could get
  	 * through to md_open, so make sure it doesn't get too far
  	 */
  	mutex_lock(&mddev->open_mutex);
  	add_disk(disk);
ed9e19823   Tejun Heo   block: implement ...
4623
4624
  	error = kobject_init_and_add(&mddev->kobj, &md_ktype,
  				     &disk_to_dev(disk)->kobj, "%s", "md");
0909dc448   NeilBrown   md: tidy up error...
4625
4626
4627
4628
  	if (error) {
  		/* This isn't possible, but as kobject_init_and_add is marked
  		 * __must_check, we must do something with the result
  		 */
5e55e2f5f   NeilBrown   [PATCH] md: conve...
4629
4630
4631
  		printk(KERN_WARNING "md: cannot register %s/md - name in use
  ",
  		       disk->disk_name);
0909dc448   NeilBrown   md: tidy up error...
4632
4633
  		error = 0;
  	}
00bcb4ac7   NeilBrown   md: reduce depend...
4634
4635
  	if (mddev->kobj.sd &&
  	    sysfs_create_group(&mddev->kobj, &md_bitmap_group))
43a705076   NeilBrown   md: support updat...
4636
4637
  		printk(KERN_DEBUG "pointless warning
  ");
b0140891a   NeilBrown   md: Fix race when...
4638
  	mutex_unlock(&mddev->open_mutex);
0909dc448   NeilBrown   md: tidy up error...
4639
4640
   abort:
  	mutex_unlock(&disks_mutex);
00bcb4ac7   NeilBrown   md: reduce depend...
4641
  	if (!error && mddev->kobj.sd) {
3830c62fe   Greg Kroah-Hartman   Kobject: change d...
4642
  		kobject_uevent(&mddev->kobj, KOBJ_ADD);
00bcb4ac7   NeilBrown   md: reduce depend...
4643
  		mddev->sysfs_state = sysfs_get_dirent_safe(mddev->kobj.sd, "array_state");
b62b75905   NeilBrown   md: use sysfs_not...
4644
  	}
d3374825c   NeilBrown   md: make devices ...
4645
  	mddev_put(mddev);
0909dc448   NeilBrown   md: tidy up error...
4646
  	return error;
efeb53c0e   NeilBrown   md: Allow md devi...
4647
4648
4649
4650
4651
  }
  
  static struct kobject *md_probe(dev_t dev, int *part, void *data)
  {
  	md_alloc(dev, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4652
4653
  	return NULL;
  }
efeb53c0e   NeilBrown   md: Allow md devi...
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
  static int add_named_array(const char *val, struct kernel_param *kp)
  {
  	/* val must be "md_*" where * is not all digits.
  	 * We allocate an array with a large free minor number, and
  	 * set the name to val.  val must not already be an active name.
  	 */
  	int len = strlen(val);
  	char buf[DISK_NAME_LEN];
  
  	while (len && val[len-1] == '
  ')
  		len--;
  	if (len >= DISK_NAME_LEN)
  		return -E2BIG;
  	strlcpy(buf, val, len+1);
  	if (strncmp(buf, "md_", 3) != 0)
  		return -EINVAL;
  	return md_alloc(0, buf);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4673
4674
  static void md_safemode_timeout(unsigned long data)
  {
fd01b88c7   NeilBrown   md: remove typede...
4675
  	struct mddev *mddev = (struct mddev *) data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4676

0fd62b861   Neil Brown   Make sure all cha...
4677
4678
4679
  	if (!atomic_read(&mddev->writes_pending)) {
  		mddev->safemode = 1;
  		if (mddev->external)
00bcb4ac7   NeilBrown   md: reduce depend...
4680
  			sysfs_notify_dirent_safe(mddev->sysfs_state);
0fd62b861   Neil Brown   Make sure all cha...
4681
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4682
4683
  	md_wakeup_thread(mddev->thread);
  }
6ff8d8ec0   NeilBrown   [PATCH] md: allow...
4684
  static int start_dirty_degraded;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4685

fd01b88c7   NeilBrown   md: remove typede...
4686
  int md_run(struct mddev *mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4687
  {
2604b703b   NeilBrown   [PATCH] md: remov...
4688
  	int err;
3cb030020   NeilBrown   md: removing type...
4689
  	struct md_rdev *rdev;
84fc4b56d   NeilBrown   md: rename "mdk_p...
4690
  	struct md_personality *pers;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4691

a757e64cf   NeilBrown   [PATCH] md: remov...
4692
4693
  	if (list_empty(&mddev->disks))
  		/* cannot run an array with no devices.. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4694
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4695
4696
4697
  
  	if (mddev->pers)
  		return -EBUSY;
bb4f1e9d0   NeilBrown   md: fix another d...
4698
4699
4700
  	/* Cannot run until previous stop completes properly */
  	if (mddev->sysfs_active)
  		return -EBUSY;
b6eb127d2   NeilBrown   md: remove unneed...
4701

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4702
4703
4704
  	/*
  	 * Analyze all RAID superblock(s)
  	 */
1ec4a9398   NeilBrown   md: set and test ...
4705
4706
4707
  	if (!mddev->raid_disks) {
  		if (!mddev->persistent)
  			return -EINVAL;
a757e64cf   NeilBrown   [PATCH] md: remov...
4708
  		analyze_sbs(mddev);
1ec4a9398   NeilBrown   md: set and test ...
4709
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4710

d9d166c2a   NeilBrown   [PATCH] md: allow...
4711
4712
4713
4714
  	if (mddev->level != LEVEL_NONE)
  		request_module("md-level-%d", mddev->level);
  	else if (mddev->clevel[0])
  		request_module("md-%s", mddev->clevel);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4715
4716
4717
4718
4719
  
  	/*
  	 * Drop all container device buffers, from now on
  	 * the only valid external interface is through the md
  	 * device.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4720
  	 */
159ec1fc0   Cheng Renquan   md: use list_for_...
4721
  	list_for_each_entry(rdev, &mddev->disks, same_set) {
b2d444d7a   NeilBrown   [PATCH] md: conve...
4722
  		if (test_bit(Faulty, &rdev->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4723
4724
  			continue;
  		sync_blockdev(rdev->bdev);
f98393a64   Peter Zijlstra   mm: remove destro...
4725
  		invalidate_bdev(rdev->bdev);
f0d76d70b   NeilBrown   md: check that in...
4726
4727
4728
  
  		/* perform some consistency tests on the device.
  		 * We don't want the data to overlap the metadata,
58c0fed40   Andre Noll   md: Make mddev->s...
4729
  		 * Internal Bitmap issues have been handled elsewhere.
f0d76d70b   NeilBrown   md: check that in...
4730
  		 */
a6ff7e089   Jonathan Brassow   md: separate meta...
4731
4732
4733
  		if (rdev->meta_bdev) {
  			/* Nothing to check */;
  		} else if (rdev->data_offset < rdev->sb_start) {
58c0fed40   Andre Noll   md: Make mddev->s...
4734
4735
  			if (mddev->dev_sectors &&
  			    rdev->data_offset + mddev->dev_sectors
0f420358e   Andre Noll   md: Turn rdev->sb...
4736
  			    > rdev->sb_start) {
f0d76d70b   NeilBrown   md: check that in...
4737
4738
4739
4740
4741
4742
  				printk("md: %s: data overlaps metadata
  ",
  				       mdname(mddev));
  				return -EINVAL;
  			}
  		} else {
0f420358e   Andre Noll   md: Turn rdev->sb...
4743
  			if (rdev->sb_start + rdev->sb_size/512
f0d76d70b   NeilBrown   md: check that in...
4744
4745
4746
4747
4748
4749
4750
  			    > rdev->data_offset) {
  				printk("md: %s: metadata overlaps data
  ",
  				       mdname(mddev));
  				return -EINVAL;
  			}
  		}
00bcb4ac7   NeilBrown   md: reduce depend...
4751
  		sysfs_notify_dirent_safe(rdev->sysfs_state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4752
  	}
a167f6632   NeilBrown   md: use separate ...
4753
  	if (mddev->bio_set == NULL)
a519b26db   NeilBrown   md: remove suspic...
4754
  		mddev->bio_set = bioset_create(BIO_POOL_SIZE,
fd01b88c7   NeilBrown   md: remove typede...
4755
  					       sizeof(struct mddev *));
a167f6632   NeilBrown   md: use separate ...
4756

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4757
  	spin_lock(&pers_lock);
d9d166c2a   NeilBrown   [PATCH] md: allow...
4758
  	pers = find_pers(mddev->level, mddev->clevel);
2604b703b   NeilBrown   [PATCH] md: remov...
4759
  	if (!pers || !try_module_get(pers->owner)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4760
  		spin_unlock(&pers_lock);
d9d166c2a   NeilBrown   [PATCH] md: allow...
4761
4762
4763
4764
4765
4766
4767
4768
  		if (mddev->level != LEVEL_NONE)
  			printk(KERN_WARNING "md: personality for level %d is not loaded!
  ",
  			       mddev->level);
  		else
  			printk(KERN_WARNING "md: personality for level %s is not loaded!
  ",
  			       mddev->clevel);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4769
4770
  		return -EINVAL;
  	}
2604b703b   NeilBrown   [PATCH] md: remov...
4771
  	mddev->pers = pers;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4772
  	spin_unlock(&pers_lock);
34817e8c3   NeilBrown   md: make sure new...
4773
4774
4775
4776
  	if (mddev->level != pers->level) {
  		mddev->level = pers->level;
  		mddev->new_level = pers->level;
  	}
d9d166c2a   NeilBrown   [PATCH] md: allow...
4777
  	strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4778

f67055780   NeilBrown   [PATCH] md: Check...
4779
  	if (mddev->reshape_position != MaxSector &&
63c70c4f3   NeilBrown   [PATCH] md: Split...
4780
  	    pers->start_reshape == NULL) {
f67055780   NeilBrown   [PATCH] md: Check...
4781
4782
4783
4784
4785
  		/* This personality cannot handle reshaping... */
  		mddev->pers = NULL;
  		module_put(pers->owner);
  		return -EINVAL;
  	}
7dd5e7c3d   NeilBrown   [PATCH] md: move ...
4786
4787
4788
4789
4790
  	if (pers->sync_request) {
  		/* Warn if this is a potentially silly
  		 * configuration.
  		 */
  		char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
3cb030020   NeilBrown   md: removing type...
4791
  		struct md_rdev *rdev2;
7dd5e7c3d   NeilBrown   [PATCH] md: move ...
4792
  		int warned = 0;
159ec1fc0   Cheng Renquan   md: use list_for_...
4793
4794
4795
  
  		list_for_each_entry(rdev, &mddev->disks, same_set)
  			list_for_each_entry(rdev2, &mddev->disks, same_set) {
7dd5e7c3d   NeilBrown   [PATCH] md: move ...
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
  				if (rdev < rdev2 &&
  				    rdev->bdev->bd_contains ==
  				    rdev2->bdev->bd_contains) {
  					printk(KERN_WARNING
  					       "%s: WARNING: %s appears to be"
  					       " on the same physical disk as"
  					       " %s.
  ",
  					       mdname(mddev),
  					       bdevname(rdev->bdev,b),
  					       bdevname(rdev2->bdev,b2));
  					warned = 1;
  				}
  			}
159ec1fc0   Cheng Renquan   md: use list_for_...
4810

7dd5e7c3d   NeilBrown   [PATCH] md: move ...
4811
4812
4813
4814
4815
4816
  		if (warned)
  			printk(KERN_WARNING
  			       "True protection against single-disk"
  			       " failure might be compromised.
  ");
  	}
657390d25   NeilBrown   [PATCH] md: clear...
4817
  	mddev->recovery = 0;
58c0fed40   Andre Noll   md: Make mddev->s...
4818
4819
  	/* may be over-ridden by personality */
  	mddev->resync_max_sectors = mddev->dev_sectors;
6ff8d8ec0   NeilBrown   [PATCH] md: allow...
4820
  	mddev->ok_start_degraded = start_dirty_degraded;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4821

0f9552b5d   NeilBrown   md: fix small irr...
4822
  	if (start_readonly && mddev->ro == 0)
f91de92ed   NeilBrown   [PATCH] md: allow...
4823
  		mddev->ro = 2; /* read-only, but switch on first write */
b15c2e57f   NeilBrown   [PATCH] md: move ...
4824
  	err = mddev->pers->run(mddev);
13e53df35   Andre Noll   md: do_md_run(): ...
4825
4826
4827
  	if (err)
  		printk(KERN_ERR "md: pers->run() failed ...
  ");
b522adcde   Dan Williams   md: 'array_size' ...
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
  	else if (mddev->pers->size(mddev, 0, 0) < mddev->array_sectors) {
  		WARN_ONCE(!mddev->external_size, "%s: default size too small,"
  			  " but 'external_size' not in effect?
  ", __func__);
  		printk(KERN_ERR
  		       "md: invalid array_size %llu > default size %llu
  ",
  		       (unsigned long long)mddev->array_sectors / 2,
  		       (unsigned long long)mddev->pers->size(mddev, 0, 0) / 2);
  		err = -EINVAL;
  		mddev->pers->stop(mddev);
  	}
  	if (err == 0 && mddev->pers->sync_request) {
b15c2e57f   NeilBrown   [PATCH] md: move ...
4841
4842
4843
4844
4845
4846
4847
4848
  		err = bitmap_create(mddev);
  		if (err) {
  			printk(KERN_ERR "%s: failed to create bitmap (%d)
  ",
  			       mdname(mddev), err);
  			mddev->pers->stop(mddev);
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4849
  	if (err) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4850
4851
  		module_put(mddev->pers->owner);
  		mddev->pers = NULL;
32a7627cf   NeilBrown   [PATCH] md: optim...
4852
4853
  		bitmap_destroy(mddev);
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4854
  	}
5e55e2f5f   NeilBrown   [PATCH] md: conve...
4855
  	if (mddev->pers->sync_request) {
00bcb4ac7   NeilBrown   md: reduce depend...
4856
4857
  		if (mddev->kobj.sd &&
  		    sysfs_create_group(&mddev->kobj, &md_redundancy_group))
5e55e2f5f   NeilBrown   [PATCH] md: conve...
4858
4859
4860
4861
  			printk(KERN_WARNING
  			       "md: cannot register extra attributes for %s
  ",
  			       mdname(mddev));
00bcb4ac7   NeilBrown   md: reduce depend...
4862
  		mddev->sysfs_action = sysfs_get_dirent_safe(mddev->kobj.sd, "sync_action");
5e55e2f5f   NeilBrown   [PATCH] md: conve...
4863
  	} else if (mddev->ro == 2) /* auto-readonly not meaningful */
fd9d49cac   NeilBrown   [PATCH] md: ignor...
4864
  		mddev->ro = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4865
   	atomic_set(&mddev->writes_pending,0);
1e50915fe   Robert Becker   raid: improve MD/...
4866
4867
  	atomic_set(&mddev->max_corr_read_errors,
  		   MD_DEFAULT_MAX_CORRECTED_READ_ERRORS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4868
4869
4870
  	mddev->safemode = 0;
  	mddev->safemode_timer.function = md_safemode_timeout;
  	mddev->safemode_timer.data = (unsigned long) mddev;
16f17b39f   NeilBrown   [PATCH] md: incre...
4871
  	mddev->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4872
  	mddev->in_sync = 1;
0ca69886a   NeilBrown   md: Ensure no IO ...
4873
4874
  	smp_wmb();
  	mddev->ready = 1;
159ec1fc0   Cheng Renquan   md: use list_for_...
4875
  	list_for_each_entry(rdev, &mddev->disks, same_set)
36fad858a   Namhyung Kim   md: introduce lin...
4876
4877
  		if (rdev->raid_disk >= 0)
  			if (sysfs_link_rdev(mddev, rdev))
00bcb4ac7   NeilBrown   md: reduce depend...
4878
  				/* failure here is OK */;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4879
4880
4881
  	
  	set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
  	
850b2b420   NeilBrown   [PATCH] md: repla...
4882
4883
  	if (mddev->flags)
  		md_update_sb(mddev, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4884

d7603b7e3   NeilBrown   [PATCH] md: make ...
4885
  	md_new_event(mddev);
00bcb4ac7   NeilBrown   md: reduce depend...
4886
4887
  	sysfs_notify_dirent_safe(mddev->sysfs_state);
  	sysfs_notify_dirent_safe(mddev->sysfs_action);
a99ac9711   Neil Brown   Make sure all cha...
4888
  	sysfs_notify(&mddev->kobj, NULL, "degraded");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4889
4890
  	return 0;
  }
390ee602a   NeilBrown   md: export variou...
4891
  EXPORT_SYMBOL_GPL(md_run);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4892

fd01b88c7   NeilBrown   md: remove typede...
4893
  static int do_md_run(struct mddev *mddev)
fe60b0142   NeilBrown   md: factor do_md_...
4894
4895
4896
4897
4898
4899
  {
  	int err;
  
  	err = md_run(mddev);
  	if (err)
  		goto out;
69e51b449   NeilBrown   md/bitmap: separ...
4900
4901
4902
4903
4904
  	err = bitmap_load(mddev);
  	if (err) {
  		bitmap_destroy(mddev);
  		goto out;
  	}
0fd018af3   Jonathan Brassow   MD: move thread w...
4905
4906
4907
  
  	md_wakeup_thread(mddev->thread);
  	md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
fe60b0142   NeilBrown   md: factor do_md_...
4908
4909
  	set_capacity(mddev->gendisk, mddev->array_sectors);
  	revalidate_disk(mddev->gendisk);
f0b4f7e2f   NeilBrown   md: Fix - again -...
4910
  	mddev->changed = 1;
fe60b0142   NeilBrown   md: factor do_md_...
4911
4912
4913
4914
  	kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE);
  out:
  	return err;
  }
fd01b88c7   NeilBrown   md: remove typede...
4915
  static int restart_array(struct mddev *mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4916
4917
  {
  	struct gendisk *disk = mddev->gendisk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4918

80fab1d77   Andre Noll   md: Simplify rest...
4919
  	/* Complain if it has no devices */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4920
  	if (list_empty(&mddev->disks))
80fab1d77   Andre Noll   md: Simplify rest...
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
  		return -ENXIO;
  	if (!mddev->pers)
  		return -EINVAL;
  	if (!mddev->ro)
  		return -EBUSY;
  	mddev->safemode = 0;
  	mddev->ro = 0;
  	set_disk_ro(disk, 0);
  	printk(KERN_INFO "md: %s switched to read-write mode.
  ",
  		mdname(mddev));
  	/* Kick recovery or resync if necessary */
  	set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
  	md_wakeup_thread(mddev->thread);
  	md_wakeup_thread(mddev->sync_thread);
00bcb4ac7   NeilBrown   md: reduce depend...
4936
  	sysfs_notify_dirent_safe(mddev->sysfs_state);
80fab1d77   Andre Noll   md: Simplify rest...
4937
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4938
  }
acc55e220   NeilBrown   [PATCH] md/bitmap...
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
  /* similar to deny_write_access, but accounts for our holding a reference
   * to the file ourselves */
  static int deny_bitmap_write_access(struct file * file)
  {
  	struct inode *inode = file->f_mapping->host;
  
  	spin_lock(&inode->i_lock);
  	if (atomic_read(&inode->i_writecount) > 1) {
  		spin_unlock(&inode->i_lock);
  		return -ETXTBSY;
  	}
  	atomic_set(&inode->i_writecount, -1);
  	spin_unlock(&inode->i_lock);
  
  	return 0;
  }
43a705076   NeilBrown   md: support updat...
4955
  void restore_bitmap_write_access(struct file *file)
acc55e220   NeilBrown   [PATCH] md/bitmap...
4956
4957
4958
4959
4960
4961
4962
  {
  	struct inode *inode = file->f_mapping->host;
  
  	spin_lock(&inode->i_lock);
  	atomic_set(&inode->i_writecount, 1);
  	spin_unlock(&inode->i_lock);
  }
fd01b88c7   NeilBrown   md: remove typede...
4963
  static void md_clean(struct mddev *mddev)
6177b472a   NeilBrown   md: start to refa...
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
  {
  	mddev->array_sectors = 0;
  	mddev->external_size = 0;
  	mddev->dev_sectors = 0;
  	mddev->raid_disks = 0;
  	mddev->recovery_cp = 0;
  	mddev->resync_min = 0;
  	mddev->resync_max = MaxSector;
  	mddev->reshape_position = MaxSector;
  	mddev->external = 0;
  	mddev->persistent = 0;
  	mddev->level = LEVEL_NONE;
  	mddev->clevel[0] = 0;
  	mddev->flags = 0;
  	mddev->ro = 0;
  	mddev->metadata_type[0] = 0;
  	mddev->chunk_sectors = 0;
  	mddev->ctime = mddev->utime = 0;
  	mddev->layout = 0;
  	mddev->max_disks = 0;
  	mddev->events = 0;
a8707c08f   NeilBrown   md: simplify upda...
4985
  	mddev->can_decrease_events = 0;
6177b472a   NeilBrown   md: start to refa...
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
  	mddev->delta_disks = 0;
  	mddev->new_level = LEVEL_NONE;
  	mddev->new_layout = 0;
  	mddev->new_chunk_sectors = 0;
  	mddev->curr_resync = 0;
  	mddev->resync_mismatches = 0;
  	mddev->suspend_lo = mddev->suspend_hi = 0;
  	mddev->sync_speed_min = mddev->sync_speed_max = 0;
  	mddev->recovery = 0;
  	mddev->in_sync = 0;
f0b4f7e2f   NeilBrown   md: Fix - again -...
4996
  	mddev->changed = 0;
6177b472a   NeilBrown   md: start to refa...
4997
  	mddev->degraded = 0;
6177b472a   NeilBrown   md: start to refa...
4998
4999
5000
5001
5002
5003
5004
  	mddev->safemode = 0;
  	mddev->bitmap_info.offset = 0;
  	mddev->bitmap_info.default_offset = 0;
  	mddev->bitmap_info.chunksize = 0;
  	mddev->bitmap_info.daemon_sleep = 0;
  	mddev->bitmap_info.max_write_behind = 0;
  }
fd01b88c7   NeilBrown   md: remove typede...
5005
  static void __md_stop_writes(struct mddev *mddev)
a047e1254   NeilBrown   md: factor md_sto...
5006
5007
5008
5009
  {
  	if (mddev->sync_thread) {
  		set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
  		set_bit(MD_RECOVERY_INTR, &mddev->recovery);
7ebc0be7f   NeilBrown   md: Be more caref...
5010
  		reap_sync_thread(mddev);
a047e1254   NeilBrown   md: factor md_sto...
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
  	}
  
  	del_timer_sync(&mddev->safemode_timer);
  
  	bitmap_flush(mddev);
  	md_super_wait(mddev);
  
  	if (!mddev->in_sync || mddev->flags) {
  		/* mark array as shutdown cleanly */
  		mddev->in_sync = 1;
  		md_update_sb(mddev, 1);
  	}
  }
defad61a5   NeilBrown   md: md_stop_write...
5024

fd01b88c7   NeilBrown   md: remove typede...
5025
  void md_stop_writes(struct mddev *mddev)
defad61a5   NeilBrown   md: md_stop_write...
5026
5027
5028
5029
5030
  {
  	mddev_lock(mddev);
  	__md_stop_writes(mddev);
  	mddev_unlock(mddev);
  }
390ee602a   NeilBrown   md: export variou...
5031
  EXPORT_SYMBOL_GPL(md_stop_writes);
a047e1254   NeilBrown   md: factor md_sto...
5032

fd01b88c7   NeilBrown   md: remove typede...
5033
  void md_stop(struct mddev *mddev)
6177b472a   NeilBrown   md: start to refa...
5034
  {
0ca69886a   NeilBrown   md: Ensure no IO ...
5035
  	mddev->ready = 0;
6177b472a   NeilBrown   md: start to refa...
5036
5037
5038
5039
5040
  	mddev->pers->stop(mddev);
  	if (mddev->pers->sync_request && mddev->to_remove == NULL)
  		mddev->to_remove = &md_redundancy_group;
  	module_put(mddev->pers->owner);
  	mddev->pers = NULL;
cca9cf90c   NeilBrown   md: call md_stop_...
5041
  	clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
6177b472a   NeilBrown   md: start to refa...
5042
  }
390ee602a   NeilBrown   md: export variou...
5043
  EXPORT_SYMBOL_GPL(md_stop);
6177b472a   NeilBrown   md: start to refa...
5044

fd01b88c7   NeilBrown   md: remove typede...
5045
  static int md_set_readonly(struct mddev *mddev, int is_open)
a4bd82d0d   NeilBrown   md: split md_set_...
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
  {
  	int err = 0;
  	mutex_lock(&mddev->open_mutex);
  	if (atomic_read(&mddev->openers) > is_open) {
  		printk("md: %s still in use.
  ",mdname(mddev));
  		err = -EBUSY;
  		goto out;
  	}
  	if (mddev->pers) {
defad61a5   NeilBrown   md: md_stop_write...
5056
  		__md_stop_writes(mddev);
a4bd82d0d   NeilBrown   md: split md_set_...
5057
5058
5059
5060
5061
5062
5063
  
  		err  = -ENXIO;
  		if (mddev->ro==1)
  			goto out;
  		mddev->ro = 1;
  		set_disk_ro(mddev->gendisk, 1);
  		clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
00bcb4ac7   NeilBrown   md: reduce depend...
5064
  		sysfs_notify_dirent_safe(mddev->sysfs_state);
a4bd82d0d   NeilBrown   md: split md_set_...
5065
5066
5067
5068
5069
5070
  		err = 0;	
  	}
  out:
  	mutex_unlock(&mddev->open_mutex);
  	return err;
  }
9e653b634   NeilBrown   [PATCH] md: Set/g...
5071
5072
  /* mode:
   *   0 - completely stop and dis-assemble array
9e653b634   NeilBrown   [PATCH] md: Set/g...
5073
5074
   *   2 - stop but do not disassemble array
   */
fd01b88c7   NeilBrown   md: remove typede...
5075
  static int do_md_stop(struct mddev * mddev, int mode, int is_open)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5076
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5077
  	struct gendisk *disk = mddev->gendisk;
3cb030020   NeilBrown   md: removing type...
5078
  	struct md_rdev *rdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5079

c8c00a691   NeilBrown   Remove deadlock p...
5080
  	mutex_lock(&mddev->open_mutex);
bb4f1e9d0   NeilBrown   md: fix another d...
5081
5082
  	if (atomic_read(&mddev->openers) > is_open ||
  	    mddev->sysfs_active) {
df5b20cf6   Neil Brown   md: Better contro...
5083
5084
  		printk("md: %s still in use.
  ",mdname(mddev));
6e17b0276   NeilBrown   md: clean up do_m...
5085
5086
5087
  		mutex_unlock(&mddev->open_mutex);
  		return -EBUSY;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5088

6e17b0276   NeilBrown   md: clean up do_m...
5089
  	if (mddev->pers) {
a4bd82d0d   NeilBrown   md: split md_set_...
5090
5091
  		if (mddev->ro)
  			set_disk_ro(disk, 0);
409c57f38   NeilBrown   md: enable suspen...
5092

defad61a5   NeilBrown   md: md_stop_write...
5093
  		__md_stop_writes(mddev);
a4bd82d0d   NeilBrown   md: split md_set_...
5094
5095
  		md_stop(mddev);
  		mddev->queue->merge_bvec_fn = NULL;
a4bd82d0d   NeilBrown   md: split md_set_...
5096
  		mddev->queue->backing_dev_info.congested_fn = NULL;
6177b472a   NeilBrown   md: start to refa...
5097

a4bd82d0d   NeilBrown   md: split md_set_...
5098
  		/* tell userspace to handle 'inactive' */
00bcb4ac7   NeilBrown   md: reduce depend...
5099
  		sysfs_notify_dirent_safe(mddev->sysfs_state);
0d4ca600f   NeilBrown   [PATCH] md: tidy ...
5100

a4bd82d0d   NeilBrown   md: split md_set_...
5101
  		list_for_each_entry(rdev, &mddev->disks, same_set)
36fad858a   Namhyung Kim   md: introduce lin...
5102
5103
  			if (rdev->raid_disk >= 0)
  				sysfs_unlink_rdev(mddev, rdev);
c4647292f   NeilBrown   md: remove rd%d l...
5104

a4bd82d0d   NeilBrown   md: split md_set_...
5105
  		set_capacity(disk, 0);
6e17b0276   NeilBrown   md: clean up do_m...
5106
  		mutex_unlock(&mddev->open_mutex);
f0b4f7e2f   NeilBrown   md: Fix - again -...
5107
  		mddev->changed = 1;
a4bd82d0d   NeilBrown   md: split md_set_...
5108
  		revalidate_disk(disk);
0d4ca600f   NeilBrown   [PATCH] md: tidy ...
5109

a4bd82d0d   NeilBrown   md: split md_set_...
5110
5111
  		if (mddev->ro)
  			mddev->ro = 0;
6e17b0276   NeilBrown   md: clean up do_m...
5112
5113
  	} else
  		mutex_unlock(&mddev->open_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5114
5115
5116
  	/*
  	 * Free resources if final stop
  	 */
9e653b634   NeilBrown   [PATCH] md: Set/g...
5117
  	if (mode == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5118
5119
  		printk(KERN_INFO "md: %s stopped.
  ", mdname(mddev));
978f946bb   NeilBrown   [PATCH] md: Don't...
5120
  		bitmap_destroy(mddev);
c3d9714e8   NeilBrown   md: collect bitma...
5121
5122
5123
5124
  		if (mddev->bitmap_info.file) {
  			restore_bitmap_write_access(mddev->bitmap_info.file);
  			fput(mddev->bitmap_info.file);
  			mddev->bitmap_info.file = NULL;
978f946bb   NeilBrown   [PATCH] md: Don't...
5125
  		}
c3d9714e8   NeilBrown   md: collect bitma...
5126
  		mddev->bitmap_info.offset = 0;
978f946bb   NeilBrown   [PATCH] md: Don't...
5127

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5128
  		export_array(mddev);
6177b472a   NeilBrown   md: start to refa...
5129
  		md_clean(mddev);
934d9c23b   NeilBrown   md: destroy parti...
5130
  		kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE);
efeb53c0e   NeilBrown   md: Allow md devi...
5131
5132
  		if (mddev->hold_active == UNTIL_STOP)
  			mddev->hold_active = 0;
a4bd82d0d   NeilBrown   md: split md_set_...
5133
  	}
3f9d99c12   Martin K. Petersen   MD data integrity...
5134
  	blk_integrity_unregister(disk);
d7603b7e3   NeilBrown   [PATCH] md: make ...
5135
  	md_new_event(mddev);
00bcb4ac7   NeilBrown   md: reduce depend...
5136
  	sysfs_notify_dirent_safe(mddev->sysfs_state);
6e17b0276   NeilBrown   md: clean up do_m...
5137
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5138
  }
fdee8ae44   Jeff Garzik   [PATCH] MD: condi...
5139
  #ifndef MODULE
fd01b88c7   NeilBrown   md: remove typede...
5140
  static void autorun_array(struct mddev *mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5141
  {
3cb030020   NeilBrown   md: removing type...
5142
  	struct md_rdev *rdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5143
  	int err;
a757e64cf   NeilBrown   [PATCH] md: remov...
5144
  	if (list_empty(&mddev->disks))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5145
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5146
5147
  
  	printk(KERN_INFO "md: running: ");
159ec1fc0   Cheng Renquan   md: use list_for_...
5148
  	list_for_each_entry(rdev, &mddev->disks, same_set) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5149
5150
5151
5152
5153
  		char b[BDEVNAME_SIZE];
  		printk("<%s>", bdevname(rdev->bdev,b));
  	}
  	printk("
  ");
d710e1381   NeilBrown   md: remove space ...
5154
  	err = do_md_run(mddev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5155
5156
5157
  	if (err) {
  		printk(KERN_WARNING "md: do_md_run() returned %d
  ", err);
d710e1381   NeilBrown   md: remove space ...
5158
  		do_md_stop(mddev, 0, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
  	}
  }
  
  /*
   * lets try to run arrays based on all disks that have arrived
   * until now. (those are in pending_raid_disks)
   *
   * the method: pick the first pending disk, collect all disks with
   * the same UUID, remove all from the pending list and put them into
   * the 'same_array' list. Then order this list based on superblock
   * update time (freshest comes first), kick out 'old' disks and
   * compare superblocks. If everything's fine then run it.
   *
   * If "unit" is allocated, then bump its reference count
   */
  static void autorun_devices(int part)
  {
3cb030020   NeilBrown   md: removing type...
5176
  	struct md_rdev *rdev0, *rdev, *tmp;
fd01b88c7   NeilBrown   md: remove typede...
5177
  	struct mddev *mddev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5178
5179
5180
5181
5182
  	char b[BDEVNAME_SIZE];
  
  	printk(KERN_INFO "md: autorun ...
  ");
  	while (!list_empty(&pending_raid_disks)) {
e8703fe1f   NeilBrown   [PATCH] md: remov...
5183
  		int unit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5184
  		dev_t dev;
ad01c9e37   NeilBrown   [PATCH] md: Allow...
5185
  		LIST_HEAD(candidates);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5186
  		rdev0 = list_entry(pending_raid_disks.next,
3cb030020   NeilBrown   md: removing type...
5187
  					 struct md_rdev, same_set);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5188
5189
5190
5191
5192
  
  		printk(KERN_INFO "md: considering %s ...
  ",
  			bdevname(rdev0->bdev,b));
  		INIT_LIST_HEAD(&candidates);
159ec1fc0   Cheng Renquan   md: use list_for_...
5193
  		rdev_for_each_list(rdev, tmp, &pending_raid_disks)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
  			if (super_90_load(rdev, rdev0, 0) >= 0) {
  				printk(KERN_INFO "md:  adding %s ...
  ",
  					bdevname(rdev->bdev,b));
  				list_move(&rdev->same_set, &candidates);
  			}
  		/*
  		 * now we have a set of devices, with all of them having
  		 * mostly sane superblocks. It's time to allocate the
  		 * mddev.
  		 */
e8703fe1f   NeilBrown   [PATCH] md: remov...
5205
5206
5207
5208
5209
5210
5211
5212
5213
  		if (part) {
  			dev = MKDEV(mdp_major,
  				    rdev0->preferred_minor << MdpMinorShift);
  			unit = MINOR(dev) >> MdpMinorShift;
  		} else {
  			dev = MKDEV(MD_MAJOR, rdev0->preferred_minor);
  			unit = MINOR(dev);
  		}
  		if (rdev0->preferred_minor != unit) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5214
5215
5216
5217
5218
  			printk(KERN_INFO "md: unit number in %s is bad: %d
  ",
  			       bdevname(rdev0->bdev, b), rdev0->preferred_minor);
  			break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5219
5220
5221
  
  		md_probe(dev, NULL, NULL);
  		mddev = mddev_find(dev);
9bbbca3a0   Neil Brown   Fix error paths i...
5222
5223
5224
5225
  		if (!mddev || !mddev->gendisk) {
  			if (mddev)
  				mddev_put(mddev);
  			printk(KERN_ERR
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
  				"md: cannot allocate memory for md drive.
  ");
  			break;
  		}
  		if (mddev_lock(mddev)) 
  			printk(KERN_WARNING "md: %s locked, cannot run
  ",
  			       mdname(mddev));
  		else if (mddev->raid_disks || mddev->major_version
  			 || !list_empty(&mddev->disks)) {
  			printk(KERN_WARNING 
  				"md: %s already running, cannot run %s
  ",
  				mdname(mddev), bdevname(rdev0->bdev,b));
  			mddev_unlock(mddev);
  		} else {
  			printk(KERN_INFO "md: created %s
  ", mdname(mddev));
1ec4a9398   NeilBrown   md: set and test ...
5244
  			mddev->persistent = 1;
159ec1fc0   Cheng Renquan   md: use list_for_...
5245
  			rdev_for_each_list(rdev, tmp, &candidates) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
  				list_del_init(&rdev->same_set);
  				if (bind_rdev_to_array(rdev, mddev))
  					export_rdev(rdev);
  			}
  			autorun_array(mddev);
  			mddev_unlock(mddev);
  		}
  		/* on success, candidates will be empty, on error
  		 * it won't...
  		 */
159ec1fc0   Cheng Renquan   md: use list_for_...
5256
  		rdev_for_each_list(rdev, tmp, &candidates) {
4b80991c6   NeilBrown   md: Protect acces...
5257
  			list_del_init(&rdev->same_set);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5258
  			export_rdev(rdev);
4b80991c6   NeilBrown   md: Protect acces...
5259
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5260
5261
5262
5263
5264
  		mddev_put(mddev);
  	}
  	printk(KERN_INFO "md: ... autorun DONE.
  ");
  }
fdee8ae44   Jeff Garzik   [PATCH] MD: condi...
5265
  #endif /* !MODULE */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5266

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
  static int get_version(void __user * arg)
  {
  	mdu_version_t ver;
  
  	ver.major = MD_MAJOR_VERSION;
  	ver.minor = MD_MINOR_VERSION;
  	ver.patchlevel = MD_PATCHLEVEL_VERSION;
  
  	if (copy_to_user(arg, &ver, sizeof(ver)))
  		return -EFAULT;
  
  	return 0;
  }
fd01b88c7   NeilBrown   md: remove typede...
5280
  static int get_array_info(struct mddev * mddev, void __user * arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5281
5282
  {
  	mdu_array_info_t info;
a9f326ebf   NeilBrown   md: remove sparse...
5283
  	int nr,working,insync,failed,spare;
3cb030020   NeilBrown   md: removing type...
5284
  	struct md_rdev *rdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5285

a9f326ebf   NeilBrown   md: remove sparse...
5286
  	nr=working=insync=failed=spare=0;
159ec1fc0   Cheng Renquan   md: use list_for_...
5287
  	list_for_each_entry(rdev, &mddev->disks, same_set) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5288
  		nr++;
b2d444d7a   NeilBrown   [PATCH] md: conve...
5289
  		if (test_bit(Faulty, &rdev->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5290
5291
5292
  			failed++;
  		else {
  			working++;
b2d444d7a   NeilBrown   [PATCH] md: conve...
5293
  			if (test_bit(In_sync, &rdev->flags))
a9f326ebf   NeilBrown   md: remove sparse...
5294
  				insync++;	
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
  			else
  				spare++;
  		}
  	}
  
  	info.major_version = mddev->major_version;
  	info.minor_version = mddev->minor_version;
  	info.patch_version = MD_PATCHLEVEL_VERSION;
  	info.ctime         = mddev->ctime;
  	info.level         = mddev->level;
58c0fed40   Andre Noll   md: Make mddev->s...
5305
5306
  	info.size          = mddev->dev_sectors / 2;
  	if (info.size != mddev->dev_sectors / 2) /* overflow */
284ae7cab   NeilBrown   [PATCH] md: Handl...
5307
  		info.size = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5308
5309
5310
5311
5312
5313
5314
5315
5316
  	info.nr_disks      = nr;
  	info.raid_disks    = mddev->raid_disks;
  	info.md_minor      = mddev->md_minor;
  	info.not_persistent= !mddev->persistent;
  
  	info.utime         = mddev->utime;
  	info.state         = 0;
  	if (mddev->in_sync)
  		info.state = (1<<MD_SB_CLEAN);
c3d9714e8   NeilBrown   md: collect bitma...
5317
  	if (mddev->bitmap && mddev->bitmap_info.offset)
36fa30636   NeilBrown   [PATCH] md: all h...
5318
  		info.state = (1<<MD_SB_BITMAP_PRESENT);
a9f326ebf   NeilBrown   md: remove sparse...
5319
  	info.active_disks  = insync;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5320
5321
5322
5323
5324
  	info.working_disks = working;
  	info.failed_disks  = failed;
  	info.spare_disks   = spare;
  
  	info.layout        = mddev->layout;
9d8f03636   Andre Noll   md: Make mddev->c...
5325
  	info.chunk_size    = mddev->chunk_sectors << 9;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5326
5327
5328
5329
5330
5331
  
  	if (copy_to_user(arg, &info, sizeof(info)))
  		return -EFAULT;
  
  	return 0;
  }
fd01b88c7   NeilBrown   md: remove typede...
5332
  static int get_bitmap_file(struct mddev * mddev, void __user * arg)
32a7627cf   NeilBrown   [PATCH] md: optim...
5333
5334
5335
5336
  {
  	mdu_bitmap_file_t *file = NULL; /* too big for stack allocation */
  	char *ptr, *buf = NULL;
  	int err = -ENOMEM;
b5470dc5f   Dan Williams   md: resolve exter...
5337
5338
5339
5340
  	if (md_allow_write(mddev))
  		file = kmalloc(sizeof(*file), GFP_NOIO);
  	else
  		file = kmalloc(sizeof(*file), GFP_KERNEL);
2a2275d63   NeilBrown   [PATCH] md: fix p...
5341

32a7627cf   NeilBrown   [PATCH] md: optim...
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
  	if (!file)
  		goto out;
  
  	/* bitmap disabled, zero the first byte and copy out */
  	if (!mddev->bitmap || !mddev->bitmap->file) {
  		file->pathname[0] = '\0';
  		goto copy_out;
  	}
  
  	buf = kmalloc(sizeof(file->pathname), GFP_KERNEL);
  	if (!buf)
  		goto out;
6bcfd6018   Christoph Hellwig   md: kill file_pat...
5354
5355
  	ptr = d_path(&mddev->bitmap->file->f_path, buf, sizeof(file->pathname));
  	if (IS_ERR(ptr))
32a7627cf   NeilBrown   [PATCH] md: optim...
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
5367
5368
  		goto out;
  
  	strcpy(file->pathname, ptr);
  
  copy_out:
  	err = 0;
  	if (copy_to_user(arg, file, sizeof(*file)))
  		err = -EFAULT;
  out:
  	kfree(buf);
  	kfree(file);
  	return err;
  }
fd01b88c7   NeilBrown   md: remove typede...
5369
  static int get_disk_info(struct mddev * mddev, void __user * arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5370
5371
  {
  	mdu_disk_info_t info;
3cb030020   NeilBrown   md: removing type...
5372
  	struct md_rdev *rdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5373
5374
5375
  
  	if (copy_from_user(&info, arg, sizeof(info)))
  		return -EFAULT;
26ef379f5   Andre Noll   md: get_disk_info...
5376
  	rdev = find_rdev_nr(mddev, info.number);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5377
5378
5379
5380
5381
  	if (rdev) {
  		info.major = MAJOR(rdev->bdev->bd_dev);
  		info.minor = MINOR(rdev->bdev->bd_dev);
  		info.raid_disk = rdev->raid_disk;
  		info.state = 0;
b2d444d7a   NeilBrown   [PATCH] md: conve...
5382
  		if (test_bit(Faulty, &rdev->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5383
  			info.state |= (1<<MD_DISK_FAULTY);
b2d444d7a   NeilBrown   [PATCH] md: conve...
5384
  		else if (test_bit(In_sync, &rdev->flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5385
5386
5387
  			info.state |= (1<<MD_DISK_ACTIVE);
  			info.state |= (1<<MD_DISK_SYNC);
  		}
8ddf9efe6   NeilBrown   [PATCH] md: suppo...
5388
5389
  		if (test_bit(WriteMostly, &rdev->flags))
  			info.state |= (1<<MD_DISK_WRITEMOSTLY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400
  	} else {
  		info.major = info.minor = 0;
  		info.raid_disk = -1;
  		info.state = (1<<MD_DISK_REMOVED);
  	}
  
  	if (copy_to_user(arg, &info, sizeof(info)))
  		return -EFAULT;
  
  	return 0;
  }
fd01b88c7   NeilBrown   md: remove typede...
5401
  static int add_new_disk(struct mddev * mddev, mdu_disk_info_t *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5402
5403
  {
  	char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
3cb030020   NeilBrown   md: removing type...
5404
  	struct md_rdev *rdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
  	dev_t dev = MKDEV(info->major,info->minor);
  
  	if (info->major != MAJOR(dev) || info->minor != MINOR(dev))
  		return -EOVERFLOW;
  
  	if (!mddev->raid_disks) {
  		int err;
  		/* expecting a device which has a superblock */
  		rdev = md_import_device(dev, mddev->major_version, mddev->minor_version);
  		if (IS_ERR(rdev)) {
  			printk(KERN_WARNING 
  				"md: md_import_device returned %ld
  ",
  				PTR_ERR(rdev));
  			return PTR_ERR(rdev);
  		}
  		if (!list_empty(&mddev->disks)) {
3cb030020   NeilBrown   md: removing type...
5422
5423
5424
  			struct md_rdev *rdev0
  				= list_entry(mddev->disks.next,
  					     struct md_rdev, same_set);
a9f326ebf   NeilBrown   md: remove sparse...
5425
  			err = super_types[mddev->major_version]
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437
5438
5439
5440
5441
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
  				.load_super(rdev, rdev0, mddev->minor_version);
  			if (err < 0) {
  				printk(KERN_WARNING 
  					"md: %s has different UUID to %s
  ",
  					bdevname(rdev->bdev,b), 
  					bdevname(rdev0->bdev,b2));
  				export_rdev(rdev);
  				return -EINVAL;
  			}
  		}
  		err = bind_rdev_to_array(rdev, mddev);
  		if (err)
  			export_rdev(rdev);
  		return err;
  	}
  
  	/*
  	 * add_new_disk can be used once the array is assembled
  	 * to add "hot spares".  They must already have a superblock
  	 * written
  	 */
  	if (mddev->pers) {
  		int err;
  		if (!mddev->pers->hot_add_disk) {
  			printk(KERN_WARNING 
  				"%s: personality does not support diskops!
  ",
  			       mdname(mddev));
  			return -EINVAL;
  		}
7b1e35f6d   NeilBrown   [PATCH] md: allow...
5457
5458
5459
5460
5461
  		if (mddev->persistent)
  			rdev = md_import_device(dev, mddev->major_version,
  						mddev->minor_version);
  		else
  			rdev = md_import_device(dev, -1, -1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5462
5463
5464
5465
5466
5467
5468
  		if (IS_ERR(rdev)) {
  			printk(KERN_WARNING 
  				"md: md_import_device returned %ld
  ",
  				PTR_ERR(rdev));
  			return PTR_ERR(rdev);
  		}
1a855a060   NeilBrown   md: fix bug with ...
5469
  		/* set saved_raid_disk if appropriate */
41158c7eb   NeilBrown   [PATCH] md: optim...
5470
5471
  		if (!mddev->persistent) {
  			if (info->state & (1<<MD_DISK_SYNC)  &&
bf572541a   NeilBrown   md: fix regressio...
5472
  			    info->raid_disk < mddev->raid_disks) {
41158c7eb   NeilBrown   [PATCH] md: optim...
5473
  				rdev->raid_disk = info->raid_disk;
bf572541a   NeilBrown   md: fix regressio...
5474
5475
  				set_bit(In_sync, &rdev->flags);
  			} else
41158c7eb   NeilBrown   [PATCH] md: optim...
5476
5477
5478
5479
  				rdev->raid_disk = -1;
  		} else
  			super_types[mddev->major_version].
  				validate_super(mddev, rdev);
bedd86b77   NeilBrown   md: reject a re-a...
5480
5481
5482
5483
5484
5485
5486
5487
5488
  		if ((info->state & (1<<MD_DISK_SYNC)) &&
  		    (!test_bit(In_sync, &rdev->flags) ||
  		     rdev->raid_disk != info->raid_disk)) {
  			/* This was a hot-add request, but events doesn't
  			 * match, so reject it.
  			 */
  			export_rdev(rdev);
  			return -EINVAL;
  		}
1a855a060   NeilBrown   md: fix bug with ...
5489
5490
5491
5492
  		if (test_bit(In_sync, &rdev->flags))
  			rdev->saved_raid_disk = rdev->raid_disk;
  		else
  			rdev->saved_raid_disk = -1;
41158c7eb   NeilBrown   [PATCH] md: optim...
5493

b2d444d7a   NeilBrown   [PATCH] md: conve...
5494
  		clear_bit(In_sync, &rdev->flags); /* just to be sure */
8ddf9efe6   NeilBrown   [PATCH] md: suppo...
5495
5496
  		if (info->state & (1<<MD_DISK_WRITEMOSTLY))
  			set_bit(WriteMostly, &rdev->flags);
575a80fa4   NeilBrown   md: be more consi...
5497
5498
  		else
  			clear_bit(WriteMostly, &rdev->flags);
8ddf9efe6   NeilBrown   [PATCH] md: suppo...
5499

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5500
5501
  		rdev->raid_disk = -1;
  		err = bind_rdev_to_array(rdev, mddev);
7c7546ccf   NeilBrown   [PATCH] md: allow...
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
  		if (!err && !mddev->pers->hot_remove_disk) {
  			/* If there is hot_add_disk but no hot_remove_disk
  			 * then added disks for geometry changes,
  			 * and should be added immediately.
  			 */
  			super_types[mddev->major_version].
  				validate_super(mddev, rdev);
  			err = mddev->pers->hot_add_disk(mddev, rdev);
  			if (err)
  				unbind_rdev_from_array(rdev);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5513
5514
  		if (err)
  			export_rdev(rdev);
526647320   Neil Brown   Make sure all cha...
5515
  		else
00bcb4ac7   NeilBrown   md: reduce depend...
5516
  			sysfs_notify_dirent_safe(rdev->sysfs_state);
c361777fb   NeilBrown   [PATCH] md: make ...
5517

175712843   NeilBrown   [PATCH] md: assor...
5518
  		md_update_sb(mddev, 1);
72a23c211   Neil Brown   Make sure all cha...
5519
5520
  		if (mddev->degraded)
  			set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
c361777fb   NeilBrown   [PATCH] md: make ...
5521
  		set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
9864c0053   马建朋   md: Using poll /...
5522
5523
  		if (!err)
  			md_new_event(mddev);
005eca5e7   NeilBrown   [PATCH] md: make ...
5524
  		md_wakeup_thread(mddev->thread);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5525
5526
5527
5528
5529
5530
5531
5532
5533
5534
5535
5536
5537
5538
5539
  		return err;
  	}
  
  	/* otherwise, add_new_disk is only allowed
  	 * for major_version==0 superblocks
  	 */
  	if (mddev->major_version != 0) {
  		printk(KERN_WARNING "%s: ADD_NEW_DISK not supported
  ",
  		       mdname(mddev));
  		return -EINVAL;
  	}
  
  	if (!(info->state & (1<<MD_DISK_FAULTY))) {
  		int err;
d710e1381   NeilBrown   md: remove space ...
5540
  		rdev = md_import_device(dev, -1, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
  		if (IS_ERR(rdev)) {
  			printk(KERN_WARNING 
  				"md: error, md_import_device() returned %ld
  ",
  				PTR_ERR(rdev));
  			return PTR_ERR(rdev);
  		}
  		rdev->desc_nr = info->number;
  		if (info->raid_disk < mddev->raid_disks)
  			rdev->raid_disk = info->raid_disk;
  		else
  			rdev->raid_disk = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5553
  		if (rdev->raid_disk < mddev->raid_disks)
b2d444d7a   NeilBrown   [PATCH] md: conve...
5554
5555
  			if (info->state & (1<<MD_DISK_SYNC))
  				set_bit(In_sync, &rdev->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5556

8ddf9efe6   NeilBrown   [PATCH] md: suppo...
5557
5558
  		if (info->state & (1<<MD_DISK_WRITEMOSTLY))
  			set_bit(WriteMostly, &rdev->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5559
5560
5561
  		if (!mddev->persistent) {
  			printk(KERN_INFO "md: nonpersistent superblock ...
  ");
77304d2ab   Mike Snitzer   block: read i_siz...
5562
5563
  			rdev->sb_start = i_size_read(rdev->bdev->bd_inode) / 512;
  		} else
57b2caa39   Jonathan Brassow   md-new-param-to-c...
5564
  			rdev->sb_start = calc_dev_sboffset(rdev);
8190e754e   NeilBrown   md: remove chunks...
5565
  		rdev->sectors = rdev->sb_start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5566

2bf071bf5   NeilBrown   [PATCH] md: keep ...
5567
5568
5569
5570
5571
  		err = bind_rdev_to_array(rdev, mddev);
  		if (err) {
  			export_rdev(rdev);
  			return err;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5572
5573
5574
5575
  	}
  
  	return 0;
  }
fd01b88c7   NeilBrown   md: remove typede...
5576
  static int hot_remove_disk(struct mddev * mddev, dev_t dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5577
5578
  {
  	char b[BDEVNAME_SIZE];
3cb030020   NeilBrown   md: removing type...
5579
  	struct md_rdev *rdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5580

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5581
5582
5583
5584
5585
5586
5587
5588
  	rdev = find_rdev(mddev, dev);
  	if (!rdev)
  		return -ENXIO;
  
  	if (rdev->raid_disk >= 0)
  		goto busy;
  
  	kick_rdev_from_array(rdev);
850b2b420   NeilBrown   [PATCH] md: repla...
5589
  	md_update_sb(mddev, 1);
d7603b7e3   NeilBrown   [PATCH] md: make ...
5590
  	md_new_event(mddev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5591
5592
5593
  
  	return 0;
  busy:
fdefa4d87   Nick Andrew   RAID: remove trai...
5594
5595
  	printk(KERN_WARNING "md: cannot remove active disk %s from %s ...
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5596
5597
5598
  		bdevname(rdev->bdev,b), mdname(mddev));
  	return -EBUSY;
  }
fd01b88c7   NeilBrown   md: remove typede...
5599
  static int hot_add_disk(struct mddev * mddev, dev_t dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5600
5601
5602
  {
  	char b[BDEVNAME_SIZE];
  	int err;
3cb030020   NeilBrown   md: removing type...
5603
  	struct md_rdev *rdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5604
5605
5606
5607
5608
5609
5610
5611
5612
5613
5614
5615
5616
5617
5618
5619
5620
5621
  
  	if (!mddev->pers)
  		return -ENODEV;
  
  	if (mddev->major_version != 0) {
  		printk(KERN_WARNING "%s: HOT_ADD may only be used with"
  			" version-0 superblocks.
  ",
  			mdname(mddev));
  		return -EINVAL;
  	}
  	if (!mddev->pers->hot_add_disk) {
  		printk(KERN_WARNING 
  			"%s: personality does not support diskops!
  ",
  			mdname(mddev));
  		return -EINVAL;
  	}
d710e1381   NeilBrown   md: remove space ...
5622
  	rdev = md_import_device(dev, -1, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5623
5624
5625
5626
5627
5628
5629
5630
5631
  	if (IS_ERR(rdev)) {
  		printk(KERN_WARNING 
  			"md: error, md_import_device() returned %ld
  ",
  			PTR_ERR(rdev));
  		return -EINVAL;
  	}
  
  	if (mddev->persistent)
57b2caa39   Jonathan Brassow   md-new-param-to-c...
5632
  		rdev->sb_start = calc_dev_sboffset(rdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5633
  	else
77304d2ab   Mike Snitzer   block: read i_siz...
5634
  		rdev->sb_start = i_size_read(rdev->bdev->bd_inode) / 512;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5635

8190e754e   NeilBrown   md: remove chunks...
5636
  	rdev->sectors = rdev->sb_start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5637

b2d444d7a   NeilBrown   [PATCH] md: conve...
5638
  	if (test_bit(Faulty, &rdev->flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5639
5640
5641
5642
5643
5644
5645
  		printk(KERN_WARNING 
  			"md: can not hot-add faulty %s disk to %s!
  ",
  			bdevname(rdev->bdev,b), mdname(mddev));
  		err = -EINVAL;
  		goto abort_export;
  	}
b2d444d7a   NeilBrown   [PATCH] md: conve...
5646
  	clear_bit(In_sync, &rdev->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5647
  	rdev->desc_nr = -1;
5842730de   NeilBrown   [PATCH] md: fix b...
5648
  	rdev->saved_raid_disk = -1;
2bf071bf5   NeilBrown   [PATCH] md: keep ...
5649
5650
5651
  	err = bind_rdev_to_array(rdev, mddev);
  	if (err)
  		goto abort_export;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5652
5653
5654
5655
5656
  
  	/*
  	 * The rest should better be atomic, we can have disk failures
  	 * noticed in interrupt contexts ...
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5657
  	rdev->raid_disk = -1;
850b2b420   NeilBrown   [PATCH] md: repla...
5658
  	md_update_sb(mddev, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5659
5660
5661
5662
5663
5664
5665
  
  	/*
  	 * Kick recovery, maybe this spare has to be added to the
  	 * array immediately.
  	 */
  	set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
  	md_wakeup_thread(mddev->thread);
d7603b7e3   NeilBrown   [PATCH] md: make ...
5666
  	md_new_event(mddev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5667
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5668
5669
5670
5671
  abort_export:
  	export_rdev(rdev);
  	return err;
  }
fd01b88c7   NeilBrown   md: remove typede...
5672
  static int set_bitmap_file(struct mddev *mddev, int fd)
32a7627cf   NeilBrown   [PATCH] md: optim...
5673
5674
  {
  	int err;
36fa30636   NeilBrown   [PATCH] md: all h...
5675
5676
5677
5678
5679
5680
5681
  	if (mddev->pers) {
  		if (!mddev->pers->quiesce)
  			return -EBUSY;
  		if (mddev->recovery || mddev->sync_thread)
  			return -EBUSY;
  		/* we should be able to change the bitmap.. */
  	}
32a7627cf   NeilBrown   [PATCH] md: optim...
5682

32a7627cf   NeilBrown   [PATCH] md: optim...
5683

36fa30636   NeilBrown   [PATCH] md: all h...
5684
5685
5686
  	if (fd >= 0) {
  		if (mddev->bitmap)
  			return -EEXIST; /* cannot add when bitmap is present */
c3d9714e8   NeilBrown   md: collect bitma...
5687
  		mddev->bitmap_info.file = fget(fd);
32a7627cf   NeilBrown   [PATCH] md: optim...
5688

c3d9714e8   NeilBrown   md: collect bitma...
5689
  		if (mddev->bitmap_info.file == NULL) {
36fa30636   NeilBrown   [PATCH] md: all h...
5690
5691
5692
5693
5694
  			printk(KERN_ERR "%s: error: failed to get bitmap file
  ",
  			       mdname(mddev));
  			return -EBADF;
  		}
c3d9714e8   NeilBrown   md: collect bitma...
5695
  		err = deny_bitmap_write_access(mddev->bitmap_info.file);
36fa30636   NeilBrown   [PATCH] md: all h...
5696
5697
5698
5699
  		if (err) {
  			printk(KERN_ERR "%s: error: bitmap file is already in use
  ",
  			       mdname(mddev));
c3d9714e8   NeilBrown   md: collect bitma...
5700
5701
  			fput(mddev->bitmap_info.file);
  			mddev->bitmap_info.file = NULL;
36fa30636   NeilBrown   [PATCH] md: all h...
5702
5703
  			return err;
  		}
c3d9714e8   NeilBrown   md: collect bitma...
5704
  		mddev->bitmap_info.offset = 0; /* file overrides offset */
36fa30636   NeilBrown   [PATCH] md: all h...
5705
5706
5707
5708
5709
  	} else if (mddev->bitmap == NULL)
  		return -ENOENT; /* cannot remove what isn't there */
  	err = 0;
  	if (mddev->pers) {
  		mddev->pers->quiesce(mddev, 1);
69e51b449   NeilBrown   md/bitmap: separ...
5710
  		if (fd >= 0) {
36fa30636   NeilBrown   [PATCH] md: all h...
5711
  			err = bitmap_create(mddev);
69e51b449   NeilBrown   md/bitmap: separ...
5712
5713
5714
  			if (!err)
  				err = bitmap_load(mddev);
  		}
d7375ab32   NeilBrown   [PATCH] md/bitmap...
5715
  		if (fd < 0 || err) {
36fa30636   NeilBrown   [PATCH] md: all h...
5716
  			bitmap_destroy(mddev);
d7375ab32   NeilBrown   [PATCH] md/bitmap...
5717
5718
  			fd = -1; /* make sure to put the file */
  		}
36fa30636   NeilBrown   [PATCH] md: all h...
5719
  		mddev->pers->quiesce(mddev, 0);
d7375ab32   NeilBrown   [PATCH] md/bitmap...
5720
5721
  	}
  	if (fd < 0) {
c3d9714e8   NeilBrown   md: collect bitma...
5722
5723
5724
  		if (mddev->bitmap_info.file) {
  			restore_bitmap_write_access(mddev->bitmap_info.file);
  			fput(mddev->bitmap_info.file);
acc55e220   NeilBrown   [PATCH] md/bitmap...
5725
  		}
c3d9714e8   NeilBrown   md: collect bitma...
5726
  		mddev->bitmap_info.file = NULL;
36fa30636   NeilBrown   [PATCH] md: all h...
5727
  	}
32a7627cf   NeilBrown   [PATCH] md: optim...
5728
5729
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5730
5731
5732
5733
5734
5735
5736
5737
5738
5739
5740
5741
5742
  /*
   * set_array_info is used two different ways
   * The original usage is when creating a new array.
   * In this usage, raid_disks is > 0 and it together with
   *  level, size, not_persistent,layout,chunksize determine the
   *  shape of the array.
   *  This will always create an array with a type-0.90.0 superblock.
   * The newer usage is when assembling an array.
   *  In this case raid_disks will be 0, and the major_version field is
   *  use to determine which style super-blocks are to be found on the devices.
   *  The minor and patch _version numbers are also kept incase the
   *  super_block handler wishes to interpret them.
   */
fd01b88c7   NeilBrown   md: remove typede...
5743
  static int set_array_info(struct mddev * mddev, mdu_array_info_t *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5744
5745
5746
5747
5748
  {
  
  	if (info->raid_disks == 0) {
  		/* just setting version number for superblock loading */
  		if (info->major_version < 0 ||
50511da3d   Ahmed S. Darwish   drivers/md.c: Use...
5749
  		    info->major_version >= ARRAY_SIZE(super_types) ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5750
5751
5752
5753
5754
5755
5756
5757
5758
5759
5760
  		    super_types[info->major_version].name == NULL) {
  			/* maybe try to auto-load a module? */
  			printk(KERN_INFO 
  				"md: superblock version %d not known
  ",
  				info->major_version);
  			return -EINVAL;
  		}
  		mddev->major_version = info->major_version;
  		mddev->minor_version = info->minor_version;
  		mddev->patch_version = info->patch_version;
3f9d7b0d8   NeilBrown   [PATCH] md: fix a...
5761
  		mddev->persistent = !info->not_persistent;
cbd199837   NeilBrown   md: Fix unfortuna...
5762
5763
5764
5765
  		/* ensure mddev_put doesn't delete this now that there
  		 * is some minimal configuration.
  		 */
  		mddev->ctime         = get_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5766
5767
5768
5769
5770
5771
5772
5773
  		return 0;
  	}
  	mddev->major_version = MD_MAJOR_VERSION;
  	mddev->minor_version = MD_MINOR_VERSION;
  	mddev->patch_version = MD_PATCHLEVEL_VERSION;
  	mddev->ctime         = get_seconds();
  
  	mddev->level         = info->level;
17115e038   NeilBrown   [PATCH] md: Clear...
5774
  	mddev->clevel[0]     = 0;
58c0fed40   Andre Noll   md: Make mddev->s...
5775
  	mddev->dev_sectors   = 2 * (sector_t)info->size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5776
5777
5778
5779
5780
5781
5782
5783
5784
  	mddev->raid_disks    = info->raid_disks;
  	/* don't set md_minor, it is determined by which /dev/md* was
  	 * openned
  	 */
  	if (info->state & (1<<MD_SB_CLEAN))
  		mddev->recovery_cp = MaxSector;
  	else
  		mddev->recovery_cp = 0;
  	mddev->persistent    = ! info->not_persistent;
e691063a6   NeilBrown   md: support 'exte...
5785
  	mddev->external	     = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5786
5787
  
  	mddev->layout        = info->layout;
9d8f03636   Andre Noll   md: Make mddev->c...
5788
  	mddev->chunk_sectors = info->chunk_size >> 9;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5789
5790
  
  	mddev->max_disks     = MD_SB_DISKS;
e691063a6   NeilBrown   md: support 'exte...
5791
5792
  	if (mddev->persistent)
  		mddev->flags         = 0;
850b2b420   NeilBrown   [PATCH] md: repla...
5793
  	set_bit(MD_CHANGE_DEVS, &mddev->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5794

c3d9714e8   NeilBrown   md: collect bitma...
5795
5796
  	mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
  	mddev->bitmap_info.offset = 0;
b2a2703c2   NeilBrown   [PATCH] md: set d...
5797

f67055780   NeilBrown   [PATCH] md: Check...
5798
  	mddev->reshape_position = MaxSector;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5799
5800
5801
5802
  	/*
  	 * Generate a 128 bit UUID
  	 */
  	get_random_bytes(mddev->uuid, 16);
f67055780   NeilBrown   [PATCH] md: Check...
5803
  	mddev->new_level = mddev->level;
664e7c413   Andre Noll   md: Convert mddev...
5804
  	mddev->new_chunk_sectors = mddev->chunk_sectors;
f67055780   NeilBrown   [PATCH] md: Check...
5805
5806
  	mddev->new_layout = mddev->layout;
  	mddev->delta_disks = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5807
5808
  	return 0;
  }
fd01b88c7   NeilBrown   md: remove typede...
5809
  void md_set_array_sectors(struct mddev *mddev, sector_t array_sectors)
1f403624b   Dan Williams   md: centralize ->...
5810
  {
b522adcde   Dan Williams   md: 'array_size' ...
5811
5812
5813
5814
5815
  	WARN(!mddev_is_locked(mddev), "%s: unlocked mddev!
  ", __func__);
  
  	if (mddev->external_size)
  		return;
1f403624b   Dan Williams   md: centralize ->...
5816
5817
5818
  	mddev->array_sectors = array_sectors;
  }
  EXPORT_SYMBOL(md_set_array_sectors);
fd01b88c7   NeilBrown   md: remove typede...
5819
  static int update_size(struct mddev *mddev, sector_t num_sectors)
a35b0d695   NeilBrown   [PATCH] md: allow...
5820
  {
3cb030020   NeilBrown   md: removing type...
5821
  	struct md_rdev *rdev;
a35b0d695   NeilBrown   [PATCH] md: allow...
5822
  	int rv;
d71f9f88d   Andre Noll   md: Make update_s...
5823
  	int fit = (num_sectors == 0);
a35b0d695   NeilBrown   [PATCH] md: allow...
5824
5825
5826
  
  	if (mddev->pers->resize == NULL)
  		return -EINVAL;
d71f9f88d   Andre Noll   md: Make update_s...
5827
5828
5829
5830
5831
  	/* The "num_sectors" is the number of sectors of each device that
  	 * is used.  This can only make sense for arrays with redundancy.
  	 * linear and raid0 always use whatever space is available. We can only
  	 * consider changing this number if no resync or reconstruction is
  	 * happening, and if the new size is acceptable. It must fit before the
0f420358e   Andre Noll   md: Turn rdev->sb...
5832
  	 * sb_start or, if that is <data_offset, it must fit before the size
d71f9f88d   Andre Noll   md: Make update_s...
5833
5834
  	 * of each device.  If num_sectors is zero, we find the largest size
  	 * that fits.
a35b0d695   NeilBrown   [PATCH] md: allow...
5835
5836
5837
  	 */
  	if (mddev->sync_thread)
  		return -EBUSY;
dba034eef   NeilBrown   Fail safely when ...
5838
5839
5840
5841
5842
  	if (mddev->bitmap)
  		/* Sorry, cannot grow a bitmap yet, just remove it,
  		 * grow, and re-add.
  		 */
  		return -EBUSY;
159ec1fc0   Cheng Renquan   md: use list_for_...
5843
  	list_for_each_entry(rdev, &mddev->disks, same_set) {
dd8ac336c   Andre Noll   md: Represent rai...
5844
  		sector_t avail = rdev->sectors;
01ab5662f   NeilBrown   [PATCH] md: simpl...
5845

d71f9f88d   Andre Noll   md: Make update_s...
5846
5847
5848
  		if (fit && (num_sectors == 0 || num_sectors > avail))
  			num_sectors = avail;
  		if (avail < num_sectors)
a35b0d695   NeilBrown   [PATCH] md: allow...
5849
5850
  			return -ENOSPC;
  	}
d71f9f88d   Andre Noll   md: Make update_s...
5851
  	rv = mddev->pers->resize(mddev, num_sectors);
449aad3e2   NeilBrown   md: Use revalidat...
5852
5853
  	if (!rv)
  		revalidate_disk(mddev->gendisk);
a35b0d695   NeilBrown   [PATCH] md: allow...
5854
5855
  	return rv;
  }
fd01b88c7   NeilBrown   md: remove typede...
5856
  static int update_raid_disks(struct mddev *mddev, int raid_disks)
da943b991   NeilBrown   [PATCH] md: allow...
5857
5858
5859
  {
  	int rv;
  	/* change the number of raid disks */
63c70c4f3   NeilBrown   [PATCH] md: Split...
5860
  	if (mddev->pers->check_reshape == NULL)
da943b991   NeilBrown   [PATCH] md: allow...
5861
5862
  		return -EINVAL;
  	if (raid_disks <= 0 ||
233fca36b   NeilBrown   md: Relax checks ...
5863
  	    (mddev->max_disks && raid_disks >= mddev->max_disks))
da943b991   NeilBrown   [PATCH] md: allow...
5864
  		return -EINVAL;
63c70c4f3   NeilBrown   [PATCH] md: Split...
5865
  	if (mddev->sync_thread || mddev->reshape_position != MaxSector)
da943b991   NeilBrown   [PATCH] md: allow...
5866
  		return -EBUSY;
63c70c4f3   NeilBrown   [PATCH] md: Split...
5867
5868
5869
  	mddev->delta_disks = raid_disks - mddev->raid_disks;
  
  	rv = mddev->pers->check_reshape(mddev);
de171cb9a   NeilBrown   md: revert change...
5870
5871
  	if (rv < 0)
  		mddev->delta_disks = 0;
da943b991   NeilBrown   [PATCH] md: allow...
5872
5873
  	return rv;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5874
5875
5876
5877
5878
5879
5880
5881
  /*
   * update_array_info is used to change the configuration of an
   * on-line array.
   * The version, ctime,level,size,raid_disks,not_persistent, layout,chunk_size
   * fields in the info are checked against the array.
   * Any differences that cannot be handled will cause an error.
   * Normally, only one change can be managed at a time.
   */
fd01b88c7   NeilBrown   md: remove typede...
5882
  static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5883
5884
5885
  {
  	int rv = 0;
  	int cnt = 0;
36fa30636   NeilBrown   [PATCH] md: all h...
5886
5887
5888
  	int state = 0;
  
  	/* calculate expected state,ignoring low bits */
c3d9714e8   NeilBrown   md: collect bitma...
5889
  	if (mddev->bitmap && mddev->bitmap_info.offset)
36fa30636   NeilBrown   [PATCH] md: all h...
5890
  		state |= (1 << MD_SB_BITMAP_PRESENT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5891
5892
5893
5894
5895
5896
5897
5898
  
  	if (mddev->major_version != info->major_version ||
  	    mddev->minor_version != info->minor_version ||
  /*	    mddev->patch_version != info->patch_version || */
  	    mddev->ctime         != info->ctime         ||
  	    mddev->level         != info->level         ||
  /*	    mddev->layout        != info->layout        || */
  	    !mddev->persistent	 != info->not_persistent||
9d8f03636   Andre Noll   md: Make mddev->c...
5899
  	    mddev->chunk_sectors != info->chunk_size >> 9 ||
36fa30636   NeilBrown   [PATCH] md: all h...
5900
5901
5902
  	    /* ignore bottom 8 bits of state, and allow SB_BITMAP_PRESENT to change */
  	    ((state^info->state) & 0xfffffe00)
  		)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5903
5904
  		return -EINVAL;
  	/* Check there is only one change */
58c0fed40   Andre Noll   md: Make mddev->s...
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
5915
5916
  	if (info->size >= 0 && mddev->dev_sectors / 2 != info->size)
  		cnt++;
  	if (mddev->raid_disks != info->raid_disks)
  		cnt++;
  	if (mddev->layout != info->layout)
  		cnt++;
  	if ((state ^ info->state) & (1<<MD_SB_BITMAP_PRESENT))
  		cnt++;
  	if (cnt == 0)
  		return 0;
  	if (cnt > 1)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5917
5918
5919
5920
5921
5922
  
  	if (mddev->layout != info->layout) {
  		/* Change layout
  		 * we don't need to do anything at the md level, the
  		 * personality will take care of it all.
  		 */
50ac168a6   NeilBrown   md: merge reconfi...
5923
  		if (mddev->pers->check_reshape == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5924
  			return -EINVAL;
597a711b6   NeilBrown   md: remove unnece...
5925
5926
  		else {
  			mddev->new_layout = info->layout;
50ac168a6   NeilBrown   md: merge reconfi...
5927
  			rv = mddev->pers->check_reshape(mddev);
597a711b6   NeilBrown   md: remove unnece...
5928
5929
5930
5931
  			if (rv)
  				mddev->new_layout = mddev->layout;
  			return rv;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5932
  	}
58c0fed40   Andre Noll   md: Make mddev->s...
5933
  	if (info->size >= 0 && mddev->dev_sectors / 2 != info->size)
d71f9f88d   Andre Noll   md: Make update_s...
5934
  		rv = update_size(mddev, (sector_t)info->size * 2);
a35b0d695   NeilBrown   [PATCH] md: allow...
5935

da943b991   NeilBrown   [PATCH] md: allow...
5936
5937
  	if (mddev->raid_disks    != info->raid_disks)
  		rv = update_raid_disks(mddev, info->raid_disks);
36fa30636   NeilBrown   [PATCH] md: all h...
5938
5939
5940
5941
5942
5943
5944
5945
5946
  	if ((state ^ info->state) & (1<<MD_SB_BITMAP_PRESENT)) {
  		if (mddev->pers->quiesce == NULL)
  			return -EINVAL;
  		if (mddev->recovery || mddev->sync_thread)
  			return -EBUSY;
  		if (info->state & (1<<MD_SB_BITMAP_PRESENT)) {
  			/* add the bitmap */
  			if (mddev->bitmap)
  				return -EEXIST;
c3d9714e8   NeilBrown   md: collect bitma...
5947
  			if (mddev->bitmap_info.default_offset == 0)
36fa30636   NeilBrown   [PATCH] md: all h...
5948
  				return -EINVAL;
c3d9714e8   NeilBrown   md: collect bitma...
5949
5950
  			mddev->bitmap_info.offset =
  				mddev->bitmap_info.default_offset;
36fa30636   NeilBrown   [PATCH] md: all h...
5951
5952
  			mddev->pers->quiesce(mddev, 1);
  			rv = bitmap_create(mddev);
69e51b449   NeilBrown   md/bitmap: separ...
5953
5954
  			if (!rv)
  				rv = bitmap_load(mddev);
36fa30636   NeilBrown   [PATCH] md: all h...
5955
5956
5957
5958
5959
5960
5961
5962
5963
5964
5965
5966
  			if (rv)
  				bitmap_destroy(mddev);
  			mddev->pers->quiesce(mddev, 0);
  		} else {
  			/* remove the bitmap */
  			if (!mddev->bitmap)
  				return -ENOENT;
  			if (mddev->bitmap->file)
  				return -EINVAL;
  			mddev->pers->quiesce(mddev, 1);
  			bitmap_destroy(mddev);
  			mddev->pers->quiesce(mddev, 0);
c3d9714e8   NeilBrown   md: collect bitma...
5967
  			mddev->bitmap_info.offset = 0;
36fa30636   NeilBrown   [PATCH] md: all h...
5968
5969
  		}
  	}
850b2b420   NeilBrown   [PATCH] md: repla...
5970
  	md_update_sb(mddev, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5971
5972
  	return rv;
  }
fd01b88c7   NeilBrown   md: remove typede...
5973
  static int set_disk_faulty(struct mddev *mddev, dev_t dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5974
  {
3cb030020   NeilBrown   md: removing type...
5975
  	struct md_rdev *rdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5976
5977
5978
5979
5980
5981
5982
5983
5984
  
  	if (mddev->pers == NULL)
  		return -ENODEV;
  
  	rdev = find_rdev(mddev, dev);
  	if (!rdev)
  		return -ENODEV;
  
  	md_error(mddev, rdev);
5ef56c8fe   NeilBrown   md: report failur...
5985
5986
  	if (!test_bit(Faulty, &rdev->flags))
  		return -EBUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5987
5988
  	return 0;
  }
2f9618ce6   Andre Noll   md: md_getgeo(): ...
5989
5990
5991
5992
5993
5994
  /*
   * We have a problem here : there is no easy way to give a CHS
   * virtual geometry. We currently pretend that we have a 2 heads
   * 4 sectors (with a BIG number of cylinders...). This drives
   * dosfs just mad... ;-)
   */
a885c8c43   Christoph Hellwig   [PATCH] Add block...
5995
5996
  static int md_getgeo(struct block_device *bdev, struct hd_geometry *geo)
  {
fd01b88c7   NeilBrown   md: remove typede...
5997
  	struct mddev *mddev = bdev->bd_disk->private_data;
a885c8c43   Christoph Hellwig   [PATCH] Add block...
5998
5999
6000
  
  	geo->heads = 2;
  	geo->sectors = 4;
49ce6cea8   NeilBrown   md: don't referen...
6001
  	geo->cylinders = mddev->array_sectors / 8;
a885c8c43   Christoph Hellwig   [PATCH] Add block...
6002
6003
  	return 0;
  }
a39907fa2   Al Viro   [PATCH] switch md
6004
  static int md_ioctl(struct block_device *bdev, fmode_t mode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6005
6006
6007
6008
  			unsigned int cmd, unsigned long arg)
  {
  	int err = 0;
  	void __user *argp = (void __user *)arg;
fd01b88c7   NeilBrown   md: remove typede...
6009
  	struct mddev *mddev = NULL;
e22183504   Dan Williams   md: set mddev rea...
6010
  	int ro;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
6021
6022
6023
6024
6025
6026
6027
6028
6029
6030
6031
6032
6033
6034
6035
6036
6037
6038
6039
6040
6041
  
  	if (!capable(CAP_SYS_ADMIN))
  		return -EACCES;
  
  	/*
  	 * Commands dealing with the RAID driver but not any
  	 * particular array:
  	 */
  	switch (cmd)
  	{
  		case RAID_VERSION:
  			err = get_version(argp);
  			goto done;
  
  		case PRINT_RAID_DEBUG:
  			err = 0;
  			md_print_devices();
  			goto done;
  
  #ifndef MODULE
  		case RAID_AUTORUN:
  			err = 0;
  			autostart_arrays(arg);
  			goto done;
  #endif
  		default:;
  	}
  
  	/*
  	 * Commands creating/starting a new array:
  	 */
a39907fa2   Al Viro   [PATCH] switch md
6042
  	mddev = bdev->bd_disk->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6043
6044
6045
6046
6047
  
  	if (!mddev) {
  		BUG();
  		goto abort;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6048
6049
6050
6051
6052
6053
6054
6055
6056
6057
6058
6059
6060
6061
6062
6063
6064
6065
6066
6067
6068
6069
6070
6071
6072
6073
6074
6075
6076
6077
6078
6079
6080
6081
6082
6083
6084
6085
6086
6087
6088
6089
6090
6091
6092
6093
6094
6095
6096
6097
6098
6099
6100
6101
6102
6103
6104
6105
6106
6107
6108
6109
  	err = mddev_lock(mddev);
  	if (err) {
  		printk(KERN_INFO 
  			"md: ioctl lock interrupted, reason %d, cmd %d
  ",
  			err, cmd);
  		goto abort;
  	}
  
  	switch (cmd)
  	{
  		case SET_ARRAY_INFO:
  			{
  				mdu_array_info_t info;
  				if (!arg)
  					memset(&info, 0, sizeof(info));
  				else if (copy_from_user(&info, argp, sizeof(info))) {
  					err = -EFAULT;
  					goto abort_unlock;
  				}
  				if (mddev->pers) {
  					err = update_array_info(mddev, &info);
  					if (err) {
  						printk(KERN_WARNING "md: couldn't update"
  						       " array info. %d
  ", err);
  						goto abort_unlock;
  					}
  					goto done_unlock;
  				}
  				if (!list_empty(&mddev->disks)) {
  					printk(KERN_WARNING
  					       "md: array %s already has disks!
  ",
  					       mdname(mddev));
  					err = -EBUSY;
  					goto abort_unlock;
  				}
  				if (mddev->raid_disks) {
  					printk(KERN_WARNING
  					       "md: array %s already initialised!
  ",
  					       mdname(mddev));
  					err = -EBUSY;
  					goto abort_unlock;
  				}
  				err = set_array_info(mddev, &info);
  				if (err) {
  					printk(KERN_WARNING "md: couldn't set"
  					       " array info. %d
  ", err);
  					goto abort_unlock;
  				}
  			}
  			goto done_unlock;
  
  		default:;
  	}
  
  	/*
  	 * Commands querying/configuring an existing array:
  	 */
32a7627cf   NeilBrown   [PATCH] md: optim...
6110
  	/* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY,
3f9d7b0d8   NeilBrown   [PATCH] md: fix a...
6111
  	 * RUN_ARRAY, and GET_ and SET_BITMAP_FILE are allowed */
a17184a91   NeilBrown   md: allow an md a...
6112
6113
6114
6115
  	if ((!mddev->raid_disks && !mddev->external)
  	    && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY
  	    && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE
  	    && cmd != GET_BITMAP_FILE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6116
6117
6118
6119
6120
6121
6122
6123
6124
6125
6126
6127
  		err = -ENODEV;
  		goto abort_unlock;
  	}
  
  	/*
  	 * Commands even a read-only array can execute:
  	 */
  	switch (cmd)
  	{
  		case GET_ARRAY_INFO:
  			err = get_array_info(mddev, argp);
  			goto done_unlock;
32a7627cf   NeilBrown   [PATCH] md: optim...
6128
  		case GET_BITMAP_FILE:
87162a28a   Al Viro   [PATCH] trivial _...
6129
  			err = get_bitmap_file(mddev, argp);
32a7627cf   NeilBrown   [PATCH] md: optim...
6130
  			goto done_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6131
6132
6133
6134
6135
6136
6137
6138
6139
  		case GET_DISK_INFO:
  			err = get_disk_info(mddev, argp);
  			goto done_unlock;
  
  		case RESTART_ARRAY_RW:
  			err = restart_array(mddev);
  			goto done_unlock;
  
  		case STOP_ARRAY:
d710e1381   NeilBrown   md: remove space ...
6140
  			err = do_md_stop(mddev, 0, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6141
6142
6143
  			goto done_unlock;
  
  		case STOP_ARRAY_RO:
a4bd82d0d   NeilBrown   md: split md_set_...
6144
  			err = md_set_readonly(mddev, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6145
  			goto done_unlock;
e22183504   Dan Williams   md: set mddev rea...
6146
6147
6148
6149
6150
6151
6152
6153
6154
6155
6156
6157
6158
6159
6160
6161
6162
6163
6164
6165
6166
6167
6168
6169
6170
6171
6172
6173
  		case BLKROSET:
  			if (get_user(ro, (int __user *)(arg))) {
  				err = -EFAULT;
  				goto done_unlock;
  			}
  			err = -EINVAL;
  
  			/* if the bdev is going readonly the value of mddev->ro
  			 * does not matter, no writes are coming
  			 */
  			if (ro)
  				goto done_unlock;
  
  			/* are we are already prepared for writes? */
  			if (mddev->ro != 1)
  				goto done_unlock;
  
  			/* transitioning to readauto need only happen for
  			 * arrays that call md_write_start
  			 */
  			if (mddev->pers) {
  				err = restart_array(mddev);
  				if (err == 0) {
  					mddev->ro = 2;
  					set_disk_ro(mddev->gendisk, 0);
  				}
  			}
  			goto done_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6174
6175
6176
6177
  	}
  
  	/*
  	 * The remaining ioctls are changing the state of the
f91de92ed   NeilBrown   [PATCH] md: allow...
6178
6179
6180
6181
  	 * superblock, so we do not allow them on read-only arrays.
  	 * However non-MD ioctls (e.g. get-size) will still come through
  	 * here and hit the 'default' below, so only disallow
  	 * 'md' ioctls, and switch to rw mode if started auto-readonly.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6182
  	 */
bb57fc64b   Andre Noll   md: md_ioctl(): F...
6183
  	if (_IOC_TYPE(cmd) == MD_MAJOR && mddev->ro && mddev->pers) {
f91de92ed   NeilBrown   [PATCH] md: allow...
6184
6185
  		if (mddev->ro == 2) {
  			mddev->ro = 0;
00bcb4ac7   NeilBrown   md: reduce depend...
6186
  			sysfs_notify_dirent_safe(mddev->sysfs_state);
0fd62b861   Neil Brown   Make sure all cha...
6187
6188
  			set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
  			md_wakeup_thread(mddev->thread);
f91de92ed   NeilBrown   [PATCH] md: allow...
6189
6190
6191
6192
  		} else {
  			err = -EROFS;
  			goto abort_unlock;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6193
6194
6195
6196
6197
6198
6199
6200
6201
6202
6203
6204
6205
6206
6207
6208
6209
6210
6211
6212
6213
6214
6215
6216
6217
6218
6219
  	}
  
  	switch (cmd)
  	{
  		case ADD_NEW_DISK:
  		{
  			mdu_disk_info_t info;
  			if (copy_from_user(&info, argp, sizeof(info)))
  				err = -EFAULT;
  			else
  				err = add_new_disk(mddev, &info);
  			goto done_unlock;
  		}
  
  		case HOT_REMOVE_DISK:
  			err = hot_remove_disk(mddev, new_decode_dev(arg));
  			goto done_unlock;
  
  		case HOT_ADD_DISK:
  			err = hot_add_disk(mddev, new_decode_dev(arg));
  			goto done_unlock;
  
  		case SET_DISK_FAULTY:
  			err = set_disk_faulty(mddev, new_decode_dev(arg));
  			goto done_unlock;
  
  		case RUN_ARRAY:
d710e1381   NeilBrown   md: remove space ...
6220
  			err = do_md_run(mddev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6221
  			goto done_unlock;
32a7627cf   NeilBrown   [PATCH] md: optim...
6222
6223
6224
  		case SET_BITMAP_FILE:
  			err = set_bitmap_file(mddev, (int)arg);
  			goto done_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6225
  		default:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6226
6227
6228
6229
6230
6231
  			err = -EINVAL;
  			goto abort_unlock;
  	}
  
  done_unlock:
  abort_unlock:
d3374825c   NeilBrown   md: make devices ...
6232
6233
6234
  	if (mddev->hold_active == UNTIL_IOCTL &&
  	    err != -EINVAL)
  		mddev->hold_active = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6235
6236
6237
6238
6239
6240
6241
6242
6243
  	mddev_unlock(mddev);
  
  	return err;
  done:
  	if (err)
  		MD_BUG();
  abort:
  	return err;
  }
aa98aa319   Arnd Bergmann   md: move compat_i...
6244
6245
6246
6247
6248
6249
6250
6251
6252
6253
6254
6255
6256
6257
6258
6259
6260
6261
6262
  #ifdef CONFIG_COMPAT
  static int md_compat_ioctl(struct block_device *bdev, fmode_t mode,
  		    unsigned int cmd, unsigned long arg)
  {
  	switch (cmd) {
  	case HOT_REMOVE_DISK:
  	case HOT_ADD_DISK:
  	case SET_DISK_FAULTY:
  	case SET_BITMAP_FILE:
  		/* These take in integer arg, do not convert */
  		break;
  	default:
  		arg = (unsigned long)compat_ptr(arg);
  		break;
  	}
  
  	return md_ioctl(bdev, mode, cmd, arg);
  }
  #endif /* CONFIG_COMPAT */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6263

a39907fa2   Al Viro   [PATCH] switch md
6264
  static int md_open(struct block_device *bdev, fmode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6265
6266
6267
6268
6269
  {
  	/*
  	 * Succeed if we can lock the mddev, which confirms that
  	 * it isn't being stopped right now.
  	 */
fd01b88c7   NeilBrown   md: remove typede...
6270
  	struct mddev *mddev = mddev_find(bdev->bd_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6271
  	int err;
d3374825c   NeilBrown   md: make devices ...
6272
6273
6274
6275
6276
6277
  	if (mddev->gendisk != bdev->bd_disk) {
  		/* we are racing with mddev_put which is discarding this
  		 * bd_disk.
  		 */
  		mddev_put(mddev);
  		/* Wait until bdev->bd_disk is definitely gone */
e804ac780   Tejun Heo   md: fix and updat...
6278
  		flush_workqueue(md_misc_wq);
d3374825c   NeilBrown   md: make devices ...
6279
6280
6281
6282
  		/* Then retry the open from the top */
  		return -ERESTARTSYS;
  	}
  	BUG_ON(mddev != bdev->bd_disk->private_data);
c8c00a691   NeilBrown   Remove deadlock p...
6283
  	if ((err = mutex_lock_interruptible(&mddev->open_mutex)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6284
6285
6286
  		goto out;
  
  	err = 0;
f2ea68cf4   NeilBrown   md: only count ac...
6287
  	atomic_inc(&mddev->openers);
c8c00a691   NeilBrown   Remove deadlock p...
6288
  	mutex_unlock(&mddev->open_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6289

f0b4f7e2f   NeilBrown   md: Fix - again -...
6290
  	check_disk_change(bdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6291
6292
6293
   out:
  	return err;
  }
a39907fa2   Al Viro   [PATCH] switch md
6294
  static int md_release(struct gendisk *disk, fmode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6295
  {
fd01b88c7   NeilBrown   md: remove typede...
6296
   	struct mddev *mddev = disk->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6297

52e5f9d1c   Eric Sesterhenn   BUG_ON cleanup fo...
6298
  	BUG_ON(!mddev);
f2ea68cf4   NeilBrown   md: only count ac...
6299
  	atomic_dec(&mddev->openers);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6300
6301
6302
6303
  	mddev_put(mddev);
  
  	return 0;
  }
f0b4f7e2f   NeilBrown   md: Fix - again -...
6304
6305
6306
  
  static int md_media_changed(struct gendisk *disk)
  {
fd01b88c7   NeilBrown   md: remove typede...
6307
  	struct mddev *mddev = disk->private_data;
f0b4f7e2f   NeilBrown   md: Fix - again -...
6308
6309
6310
6311
6312
6313
  
  	return mddev->changed;
  }
  
  static int md_revalidate(struct gendisk *disk)
  {
fd01b88c7   NeilBrown   md: remove typede...
6314
  	struct mddev *mddev = disk->private_data;
f0b4f7e2f   NeilBrown   md: Fix - again -...
6315
6316
6317
6318
  
  	mddev->changed = 0;
  	return 0;
  }
83d5cde47   Alexey Dobriyan   const: make block...
6319
  static const struct block_device_operations md_fops =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6320
6321
  {
  	.owner		= THIS_MODULE,
a39907fa2   Al Viro   [PATCH] switch md
6322
6323
  	.open		= md_open,
  	.release	= md_release,
b492b852c   NeilBrown   md: don't use loc...
6324
  	.ioctl		= md_ioctl,
aa98aa319   Arnd Bergmann   md: move compat_i...
6325
6326
6327
  #ifdef CONFIG_COMPAT
  	.compat_ioctl	= md_compat_ioctl,
  #endif
a885c8c43   Christoph Hellwig   [PATCH] Add block...
6328
  	.getgeo		= md_getgeo,
f0b4f7e2f   NeilBrown   md: Fix - again -...
6329
6330
  	.media_changed  = md_media_changed,
  	.revalidate_disk= md_revalidate,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6331
  };
75c96f858   Adrian Bunk   [PATCH] make some...
6332
  static int md_thread(void * arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6333
  {
2b8bf3451   NeilBrown   md: remove typede...
6334
  	struct md_thread *thread = arg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6335

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6336
6337
6338
6339
6340
6341
6342
6343
6344
6345
6346
  	/*
  	 * md_thread is a 'system-thread', it's priority should be very
  	 * high. We avoid resource deadlocks individually in each
  	 * raid personality. (RAID5 does preallocation) We also use RR and
  	 * the very same RT priority as kswapd, thus we will never get
  	 * into a priority inversion deadlock.
  	 *
  	 * we definitely have to have equal or higher priority than
  	 * bdflush, otherwise bdflush will deadlock if there are too
  	 * many dirty RAID5 blocks.
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6347

6985c43f3   NeilBrown   [PATCH] Three one...
6348
  	allow_signal(SIGKILL);
a6fb0934f   NeilBrown   [PATCH] md: use k...
6349
  	while (!kthread_should_stop()) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6350

93588e228   NeilBrown   [PATCH] md: make ...
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
6362
6363
  		/* We need to wait INTERRUPTIBLE so that
  		 * we don't add to the load-average.
  		 * That means we need to be sure no signals are
  		 * pending
  		 */
  		if (signal_pending(current))
  			flush_signals(current);
  
  		wait_event_interruptible_timeout
  			(thread->wqueue,
  			 test_bit(THREAD_WAKEUP, &thread->flags)
  			 || kthread_should_stop(),
  			 thread->timeout);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6364

6c9879101   NeilBrown   md: fix regressio...
6365
6366
  		clear_bit(THREAD_WAKEUP, &thread->flags);
  		if (!kthread_should_stop())
589a594be   NeilBrown   md: protect again...
6367
  			thread->run(thread->mddev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6368
  	}
a6fb0934f   NeilBrown   [PATCH] md: use k...
6369

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6370
6371
  	return 0;
  }
2b8bf3451   NeilBrown   md: remove typede...
6372
  void md_wakeup_thread(struct md_thread *thread)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6373
6374
  {
  	if (thread) {
36a4e1fe0   NeilBrown   md: remove PRINTK...
6375
6376
  		pr_debug("md: waking up MD thread %s.
  ", thread->tsk->comm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6377
6378
6379
6380
  		set_bit(THREAD_WAKEUP, &thread->flags);
  		wake_up(&thread->wqueue);
  	}
  }
2b8bf3451   NeilBrown   md: remove typede...
6381
  struct md_thread *md_register_thread(void (*run) (struct mddev *), struct mddev *mddev,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6382
6383
  				 const char *name)
  {
2b8bf3451   NeilBrown   md: remove typede...
6384
  	struct md_thread *thread;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6385

2b8bf3451   NeilBrown   md: remove typede...
6386
  	thread = kzalloc(sizeof(struct md_thread), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6387
6388
  	if (!thread)
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6389
  	init_waitqueue_head(&thread->wqueue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6390
6391
  	thread->run = run;
  	thread->mddev = mddev;
32a7627cf   NeilBrown   [PATCH] md: optim...
6392
  	thread->timeout = MAX_SCHEDULE_TIMEOUT;
0da3c6194   NeilBrown   md: Improve name ...
6393
6394
6395
6396
  	thread->tsk = kthread_run(md_thread, thread,
  				  "%s_%s",
  				  mdname(thread->mddev),
  				  name ?: mddev->pers->name);
a6fb0934f   NeilBrown   [PATCH] md: use k...
6397
  	if (IS_ERR(thread->tsk)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6398
6399
6400
  		kfree(thread);
  		return NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6401
6402
  	return thread;
  }
2b8bf3451   NeilBrown   md: remove typede...
6403
  void md_unregister_thread(struct md_thread **threadp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6404
  {
2b8bf3451   NeilBrown   md: remove typede...
6405
  	struct md_thread *thread = *threadp;
e0cf8f045   NeilBrown   md: md_unregister...
6406
6407
  	if (!thread)
  		return;
36a4e1fe0   NeilBrown   md: remove PRINTK...
6408
6409
  	pr_debug("interrupting MD-thread pid %d
  ", task_pid_nr(thread->tsk));
01f96c0a9   NeilBrown   md: Avoid waking ...
6410
6411
6412
6413
6414
6415
  	/* Locking ensures that mddev_unlock does not wake_up a
  	 * non-existent thread
  	 */
  	spin_lock(&pers_lock);
  	*threadp = NULL;
  	spin_unlock(&pers_lock);
a6fb0934f   NeilBrown   [PATCH] md: use k...
6416
6417
  
  	kthread_stop(thread->tsk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6418
6419
  	kfree(thread);
  }
fd01b88c7   NeilBrown   md: remove typede...
6420
  void md_error(struct mddev *mddev, struct md_rdev *rdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6421
6422
6423
6424
6425
  {
  	if (!mddev) {
  		MD_BUG();
  		return;
  	}
b2d444d7a   NeilBrown   [PATCH] md: conve...
6426
  	if (!rdev || test_bit(Faulty, &rdev->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6427
  		return;
6bfe0b499   Dan Williams   md: support block...
6428

de393cdea   NeilBrown   md: make it easie...
6429
  	if (!mddev->pers || !mddev->pers->error_handler)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6430
6431
  		return;
  	mddev->pers->error_handler(mddev,rdev);
72a23c211   Neil Brown   Make sure all cha...
6432
6433
  	if (mddev->degraded)
  		set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
00bcb4ac7   NeilBrown   md: reduce depend...
6434
  	sysfs_notify_dirent_safe(rdev->sysfs_state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6435
6436
6437
  	set_bit(MD_RECOVERY_INTR, &mddev->recovery);
  	set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
  	md_wakeup_thread(mddev->thread);
768a418db   NeilBrown   md: add support f...
6438
  	if (mddev->event_work.func)
e804ac780   Tejun Heo   md: fix and updat...
6439
  		queue_work(md_misc_wq, &mddev->event_work);
c331eb04b   NeilBrown   [PATCH] md: Fix b...
6440
  	md_new_event_inintr(mddev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6441
6442
6443
6444
6445
6446
6447
  }
  
  /* seq_file implementation /proc/mdstat */
  
  static void status_unused(struct seq_file *seq)
  {
  	int i = 0;
3cb030020   NeilBrown   md: removing type...
6448
  	struct md_rdev *rdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6449
6450
  
  	seq_printf(seq, "unused devices: ");
159ec1fc0   Cheng Renquan   md: use list_for_...
6451
  	list_for_each_entry(rdev, &pending_raid_disks, same_set) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6452
6453
6454
6455
6456
6457
6458
6459
6460
6461
6462
  		char b[BDEVNAME_SIZE];
  		i++;
  		seq_printf(seq, "%s ",
  			      bdevname(rdev->bdev,b));
  	}
  	if (!i)
  		seq_printf(seq, "<none>");
  
  	seq_printf(seq, "
  ");
  }
fd01b88c7   NeilBrown   md: remove typede...
6463
  static void status_resync(struct seq_file *seq, struct mddev * mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6464
  {
dd71cf6b2   NeilBrown   md: tidy up statu...
6465
6466
6467
  	sector_t max_sectors, resync, res;
  	unsigned long dt, db;
  	sector_t rt;
4588b42e9   NeilBrown   [PATCH] md: Updat...
6468
6469
  	int scale;
  	unsigned int per_milli;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6470

dd71cf6b2   NeilBrown   md: tidy up statu...
6471
  	resync = mddev->curr_resync - atomic_read(&mddev->recovery_active);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6472
6473
  
  	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
dd71cf6b2   NeilBrown   md: tidy up statu...
6474
  		max_sectors = mddev->resync_max_sectors;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6475
  	else
dd71cf6b2   NeilBrown   md: tidy up statu...
6476
  		max_sectors = mddev->dev_sectors;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6477
6478
6479
6480
  
  	/*
  	 * Should not happen.
  	 */
dd71cf6b2   NeilBrown   md: tidy up statu...
6481
  	if (!max_sectors) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6482
6483
6484
  		MD_BUG();
  		return;
  	}
4588b42e9   NeilBrown   [PATCH] md: Updat...
6485
  	/* Pick 'scale' such that (resync>>scale)*1000 will fit
dd71cf6b2   NeilBrown   md: tidy up statu...
6486
  	 * in a sector_t, and (max_sectors>>scale) will fit in a
4588b42e9   NeilBrown   [PATCH] md: Updat...
6487
6488
6489
6490
6491
  	 * u32, as those are the requirements for sector_div.
  	 * Thus 'scale' must be at least 10
  	 */
  	scale = 10;
  	if (sizeof(sector_t) > sizeof(unsigned long)) {
dd71cf6b2   NeilBrown   md: tidy up statu...
6492
  		while ( max_sectors/2 > (1ULL<<(scale+32)))
4588b42e9   NeilBrown   [PATCH] md: Updat...
6493
6494
6495
  			scale++;
  	}
  	res = (resync>>scale)*1000;
dd71cf6b2   NeilBrown   md: tidy up statu...
6496
  	sector_div(res, (u32)((max_sectors>>scale)+1));
4588b42e9   NeilBrown   [PATCH] md: Updat...
6497
6498
  
  	per_milli = res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6499
  	{
4588b42e9   NeilBrown   [PATCH] md: Updat...
6500
  		int i, x = per_milli/50, y = 20-x;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6501
6502
6503
6504
6505
6506
6507
6508
  		seq_printf(seq, "[");
  		for (i = 0; i < x; i++)
  			seq_printf(seq, "=");
  		seq_printf(seq, ">");
  		for (i = 0; i < y; i++)
  			seq_printf(seq, ".");
  		seq_printf(seq, "] ");
  	}
4588b42e9   NeilBrown   [PATCH] md: Updat...
6509
  	seq_printf(seq, " %s =%3u.%u%% (%llu/%llu)",
ccfcc3c10   NeilBrown   [PATCH] md: Core ...
6510
6511
  		   (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)?
  		    "reshape" :
61df9d91e   NeilBrown   [PATCH] md: make ...
6512
6513
6514
6515
6516
  		    (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)?
  		     "check" :
  		     (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ?
  		      "resync" : "recovery"))),
  		   per_milli/10, per_milli % 10,
dd71cf6b2   NeilBrown   md: tidy up statu...
6517
6518
  		   (unsigned long long) resync/2,
  		   (unsigned long long) max_sectors/2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6519
6520
  
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6521
6522
6523
  	 * dt: time from mark until now
  	 * db: blocks written from mark until now
  	 * rt: remaining time
dd71cf6b2   NeilBrown   md: tidy up statu...
6524
6525
6526
6527
  	 *
  	 * rt is a sector_t, so could be 32bit or 64bit.
  	 * So we divide before multiply in case it is 32bit and close
  	 * to the limit.
25985edce   Lucas De Marchi   Fix common misspe...
6528
  	 * We scale the divisor (db) by 32 to avoid losing precision
dd71cf6b2   NeilBrown   md: tidy up statu...
6529
6530
6531
6532
  	 * near the end of resync when the number of remaining sectors
  	 * is close to 'db'.
  	 * We then divide rt by 32 after multiplying by db to compensate.
  	 * The '+1' avoids division by zero if db is very small.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6533
6534
6535
  	 */
  	dt = ((jiffies - mddev->resync_mark) / HZ);
  	if (!dt) dt++;
ff4e8d9a9   NeilBrown   [PATCH] md: fix r...
6536
6537
  	db = (mddev->curr_mark_cnt - atomic_read(&mddev->recovery_active))
  		- mddev->resync_mark_cnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6538

dd71cf6b2   NeilBrown   md: tidy up statu...
6539
6540
6541
6542
6543
6544
6545
  	rt = max_sectors - resync;    /* number of remaining sectors */
  	sector_div(rt, db/32+1);
  	rt *= dt;
  	rt >>= 5;
  
  	seq_printf(seq, " finish=%lu.%lumin", (unsigned long)rt / 60,
  		   ((unsigned long)rt % 60)/6);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6546

ff4e8d9a9   NeilBrown   [PATCH] md: fix r...
6547
  	seq_printf(seq, " speed=%ldK/sec", db/2/dt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6548
6549
6550
6551
6552
6553
  }
  
  static void *md_seq_start(struct seq_file *seq, loff_t *pos)
  {
  	struct list_head *tmp;
  	loff_t l = *pos;
fd01b88c7   NeilBrown   md: remove typede...
6554
  	struct mddev *mddev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6555
6556
6557
6558
6559
6560
6561
6562
6563
6564
  
  	if (l >= 0x10000)
  		return NULL;
  	if (!l--)
  		/* header */
  		return (void*)1;
  
  	spin_lock(&all_mddevs_lock);
  	list_for_each(tmp,&all_mddevs)
  		if (!l--) {
fd01b88c7   NeilBrown   md: remove typede...
6565
  			mddev = list_entry(tmp, struct mddev, all_mddevs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6566
6567
6568
6569
6570
6571
6572
6573
6574
6575
6576
6577
6578
  			mddev_get(mddev);
  			spin_unlock(&all_mddevs_lock);
  			return mddev;
  		}
  	spin_unlock(&all_mddevs_lock);
  	if (!l--)
  		return (void*)2;/* tail */
  	return NULL;
  }
  
  static void *md_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  {
  	struct list_head *tmp;
fd01b88c7   NeilBrown   md: remove typede...
6579
  	struct mddev *next_mddev, *mddev = v;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6580
6581
6582
6583
6584
6585
6586
6587
6588
6589
6590
  	
  	++*pos;
  	if (v == (void*)2)
  		return NULL;
  
  	spin_lock(&all_mddevs_lock);
  	if (v == (void*)1)
  		tmp = all_mddevs.next;
  	else
  		tmp = mddev->all_mddevs.next;
  	if (tmp != &all_mddevs)
fd01b88c7   NeilBrown   md: remove typede...
6591
  		next_mddev = mddev_get(list_entry(tmp,struct mddev,all_mddevs));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6592
6593
6594
6595
6596
6597
6598
6599
6600
6601
6602
6603
6604
6605
  	else {
  		next_mddev = (void*)2;
  		*pos = 0x10000;
  	}		
  	spin_unlock(&all_mddevs_lock);
  
  	if (v != (void*)1)
  		mddev_put(mddev);
  	return next_mddev;
  
  }
  
  static void md_seq_stop(struct seq_file *seq, void *v)
  {
fd01b88c7   NeilBrown   md: remove typede...
6606
  	struct mddev *mddev = v;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6607
6608
6609
6610
6611
6612
6613
  
  	if (mddev && v != (void*)1 && v != (void*)2)
  		mddev_put(mddev);
  }
  
  static int md_seq_show(struct seq_file *seq, void *v)
  {
fd01b88c7   NeilBrown   md: remove typede...
6614
  	struct mddev *mddev = v;
dd8ac336c   Andre Noll   md: Represent rai...
6615
  	sector_t sectors;
3cb030020   NeilBrown   md: removing type...
6616
  	struct md_rdev *rdev;
32a7627cf   NeilBrown   [PATCH] md: optim...
6617
  	struct bitmap *bitmap;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6618
6619
  
  	if (v == (void*)1) {
84fc4b56d   NeilBrown   md: rename "mdk_p...
6620
  		struct md_personality *pers;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6621
6622
  		seq_printf(seq, "Personalities : ");
  		spin_lock(&pers_lock);
2604b703b   NeilBrown   [PATCH] md: remov...
6623
6624
  		list_for_each_entry(pers, &pers_list, list)
  			seq_printf(seq, "[%s] ", pers->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6625
6626
6627
6628
  
  		spin_unlock(&pers_lock);
  		seq_printf(seq, "
  ");
f15146380   Kay Sievers   fs: seq_file - ad...
6629
  		seq->poll_event = atomic_read(&md_event_count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6630
6631
6632
6633
6634
6635
  		return 0;
  	}
  	if (v == (void*)2) {
  		status_unused(seq);
  		return 0;
  	}
5dc5cf7dd   Ingo Molnar   [PATCH] md: locki...
6636
  	if (mddev_lock(mddev) < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6637
  		return -EINTR;
5dc5cf7dd   Ingo Molnar   [PATCH] md: locki...
6638

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6639
6640
6641
6642
  	if (mddev->pers || mddev->raid_disks || !list_empty(&mddev->disks)) {
  		seq_printf(seq, "%s : %sactive", mdname(mddev),
  						mddev->pers ? "" : "in");
  		if (mddev->pers) {
f91de92ed   NeilBrown   [PATCH] md: allow...
6643
  			if (mddev->ro==1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6644
  				seq_printf(seq, " (read-only)");
f91de92ed   NeilBrown   [PATCH] md: allow...
6645
  			if (mddev->ro==2)
52720ae77   NeilBrown   md: fix formattin...
6646
  				seq_printf(seq, " (auto-read-only)");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6647
6648
  			seq_printf(seq, " %s", mddev->pers->name);
  		}
dd8ac336c   Andre Noll   md: Represent rai...
6649
  		sectors = 0;
159ec1fc0   Cheng Renquan   md: use list_for_...
6650
  		list_for_each_entry(rdev, &mddev->disks, same_set) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6651
6652
6653
  			char b[BDEVNAME_SIZE];
  			seq_printf(seq, " %s[%d]",
  				bdevname(rdev->bdev,b), rdev->desc_nr);
8ddf9efe6   NeilBrown   [PATCH] md: suppo...
6654
6655
  			if (test_bit(WriteMostly, &rdev->flags))
  				seq_printf(seq, "(W)");
b2d444d7a   NeilBrown   [PATCH] md: conve...
6656
  			if (test_bit(Faulty, &rdev->flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6657
6658
  				seq_printf(seq, "(F)");
  				continue;
b325a32e5   NeilBrown   [PATCH] md: repor...
6659
6660
  			} else if (rdev->raid_disk < 0)
  				seq_printf(seq, "(S)"); /* spare */
dd8ac336c   Andre Noll   md: Represent rai...
6661
  			sectors += rdev->sectors;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6662
6663
6664
6665
6666
6667
  		}
  
  		if (!list_empty(&mddev->disks)) {
  			if (mddev->pers)
  				seq_printf(seq, "
        %llu blocks",
f233ea5c9   Andre Noll   md: Make mddev->a...
6668
6669
  					   (unsigned long long)
  					   mddev->array_sectors / 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6670
6671
6672
  			else
  				seq_printf(seq, "
        %llu blocks",
dd8ac336c   Andre Noll   md: Represent rai...
6673
  					   (unsigned long long)sectors / 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6674
  		}
1cd6bf19b   NeilBrown   [PATCH] md: add i...
6675
6676
6677
6678
6679
6680
6681
  		if (mddev->persistent) {
  			if (mddev->major_version != 0 ||
  			    mddev->minor_version != 90) {
  				seq_printf(seq," super %d.%d",
  					   mddev->major_version,
  					   mddev->minor_version);
  			}
e691063a6   NeilBrown   md: support 'exte...
6682
6683
6684
6685
  		} else if (mddev->external)
  			seq_printf(seq, " super external:%s",
  				   mddev->metadata_type);
  		else
1cd6bf19b   NeilBrown   [PATCH] md: add i...
6686
  			seq_printf(seq, " super non-persistent");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6687
6688
  
  		if (mddev->pers) {
d710e1381   NeilBrown   md: remove space ...
6689
  			mddev->pers->status(seq, mddev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6690
6691
  	 		seq_printf(seq, "
        ");
8e1b39d62   NeilBrown   [PATCH] md: only ...
6692
6693
  			if (mddev->pers->sync_request) {
  				if (mddev->curr_resync > 2) {
d710e1381   NeilBrown   md: remove space ...
6694
  					status_resync(seq, mddev);
8e1b39d62   NeilBrown   [PATCH] md: only ...
6695
6696
6697
6698
6699
6700
6701
6702
6703
  					seq_printf(seq, "
        ");
  				} else if (mddev->curr_resync == 1 || mddev->curr_resync == 2)
  					seq_printf(seq, "\tresync=DELAYED
        ");
  				else if (mddev->recovery_cp < MaxSector)
  					seq_printf(seq, "\tresync=PENDING
        ");
  			}
32a7627cf   NeilBrown   [PATCH] md: optim...
6704
6705
6706
6707
6708
  		} else
  			seq_printf(seq, "
         ");
  
  		if ((bitmap = mddev->bitmap)) {
32a7627cf   NeilBrown   [PATCH] md: optim...
6709
6710
  			unsigned long chunk_kb;
  			unsigned long flags;
32a7627cf   NeilBrown   [PATCH] md: optim...
6711
  			spin_lock_irqsave(&bitmap->lock, flags);
42a04b507   NeilBrown   md: move offset, ...
6712
  			chunk_kb = mddev->bitmap_info.chunksize >> 10;
32a7627cf   NeilBrown   [PATCH] md: optim...
6713
6714
6715
6716
6717
6718
  			seq_printf(seq, "bitmap: %lu/%lu pages [%luKB], "
  				"%lu%s chunk",
  				bitmap->pages - bitmap->missing_pages,
  				bitmap->pages,
  				(bitmap->pages - bitmap->missing_pages)
  					<< (PAGE_SHIFT - 10),
42a04b507   NeilBrown   md: move offset, ...
6719
  				chunk_kb ? chunk_kb : mddev->bitmap_info.chunksize,
32a7627cf   NeilBrown   [PATCH] md: optim...
6720
  				chunk_kb ? "KB" : "B");
78d742d87   NeilBrown   [PATCH] md: a cou...
6721
6722
  			if (bitmap->file) {
  				seq_printf(seq, ", file: ");
c32c2f63a   Jan Blunck   d_path: Make seq_...
6723
6724
  				seq_path(seq, &bitmap->file->f_path, " \t
  ");
32a7627cf   NeilBrown   [PATCH] md: optim...
6725
  			}
78d742d87   NeilBrown   [PATCH] md: a cou...
6726

32a7627cf   NeilBrown   [PATCH] md: optim...
6727
6728
6729
  			seq_printf(seq, "
  ");
  			spin_unlock_irqrestore(&bitmap->lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6730
6731
6732
6733
6734
6735
6736
6737
6738
  		}
  
  		seq_printf(seq, "
  ");
  	}
  	mddev_unlock(mddev);
  	
  	return 0;
  }
110518bcc   Jan Engelhardt   md: constify VFTs
6739
  static const struct seq_operations md_seq_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6740
6741
6742
6743
6744
6745
6746
6747
  	.start  = md_seq_start,
  	.next   = md_seq_next,
  	.stop   = md_seq_stop,
  	.show   = md_seq_show,
  };
  
  static int md_seq_open(struct inode *inode, struct file *file)
  {
f15146380   Kay Sievers   fs: seq_file - ad...
6748
  	struct seq_file *seq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6749
6750
6751
  	int error;
  
  	error = seq_open(file, &md_seq_ops);
d7603b7e3   NeilBrown   [PATCH] md: make ...
6752
  	if (error)
f15146380   Kay Sievers   fs: seq_file - ad...
6753
6754
6755
6756
  		return error;
  
  	seq = file->private_data;
  	seq->poll_event = atomic_read(&md_event_count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6757
6758
  	return error;
  }
d7603b7e3   NeilBrown   [PATCH] md: make ...
6759
6760
  static unsigned int mdstat_poll(struct file *filp, poll_table *wait)
  {
f15146380   Kay Sievers   fs: seq_file - ad...
6761
  	struct seq_file *seq = filp->private_data;
d7603b7e3   NeilBrown   [PATCH] md: make ...
6762
6763
6764
6765
6766
6767
  	int mask;
  
  	poll_wait(filp, &md_event_waiters, wait);
  
  	/* always allow read */
  	mask = POLLIN | POLLRDNORM;
f15146380   Kay Sievers   fs: seq_file - ad...
6768
  	if (seq->poll_event != atomic_read(&md_event_count))
d7603b7e3   NeilBrown   [PATCH] md: make ...
6769
6770
6771
  		mask |= POLLERR | POLLPRI;
  	return mask;
  }
fa027c2a0   Arjan van de Ven   [PATCH] mark stru...
6772
  static const struct file_operations md_seq_fops = {
e24650c2e   Akinobu Mita   [PATCH] md: fix /...
6773
  	.owner		= THIS_MODULE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6774
6775
6776
  	.open           = md_seq_open,
  	.read           = seq_read,
  	.llseek         = seq_lseek,
c3f94b40e   Martin Peschke   md: cleanup: use ...
6777
  	.release	= seq_release_private,
d7603b7e3   NeilBrown   [PATCH] md: make ...
6778
  	.poll		= mdstat_poll,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6779
  };
84fc4b56d   NeilBrown   md: rename "mdk_p...
6780
  int register_md_personality(struct md_personality *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6781
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6782
  	spin_lock(&pers_lock);
2604b703b   NeilBrown   [PATCH] md: remov...
6783
6784
6785
  	list_add_tail(&p->list, &pers_list);
  	printk(KERN_INFO "md: %s personality registered for level %d
  ", p->name, p->level);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6786
6787
6788
  	spin_unlock(&pers_lock);
  	return 0;
  }
84fc4b56d   NeilBrown   md: rename "mdk_p...
6789
  int unregister_md_personality(struct md_personality *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6790
  {
2604b703b   NeilBrown   [PATCH] md: remov...
6791
6792
  	printk(KERN_INFO "md: %s personality unregistered
  ", p->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6793
  	spin_lock(&pers_lock);
2604b703b   NeilBrown   [PATCH] md: remov...
6794
  	list_del_init(&p->list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6795
6796
6797
  	spin_unlock(&pers_lock);
  	return 0;
  }
fd01b88c7   NeilBrown   md: remove typede...
6798
  static int is_mddev_idle(struct mddev *mddev, int init)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6799
  {
3cb030020   NeilBrown   md: removing type...
6800
  	struct md_rdev * rdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6801
  	int idle;
eea1bf384   NeilBrown   md: Fix is_mddev_...
6802
  	int curr_events;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6803
6804
  
  	idle = 1;
4b80991c6   NeilBrown   md: Protect acces...
6805
6806
  	rcu_read_lock();
  	rdev_for_each_rcu(rdev, mddev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6807
  		struct gendisk *disk = rdev->bdev->bd_contains->bd_disk;
eea1bf384   NeilBrown   md: Fix is_mddev_...
6808
6809
6810
  		curr_events = (int)part_stat_read(&disk->part0, sectors[0]) +
  			      (int)part_stat_read(&disk->part0, sectors[1]) -
  			      atomic_read(&disk->sync_io);
713f6ab18   NeilBrown   md: improve the i...
6811
6812
6813
6814
6815
6816
6817
6818
6819
6820
6821
6822
6823
6824
6825
6826
6827
6828
6829
6830
  		/* sync IO will cause sync_io to increase before the disk_stats
  		 * as sync_io is counted when a request starts, and
  		 * disk_stats is counted when it completes.
  		 * So resync activity will cause curr_events to be smaller than
  		 * when there was no such activity.
  		 * non-sync IO will cause disk_stat to increase without
  		 * increasing sync_io so curr_events will (eventually)
  		 * be larger than it was before.  Once it becomes
  		 * substantially larger, the test below will cause
  		 * the array to appear non-idle, and resync will slow
  		 * down.
  		 * If there is a lot of outstanding resync activity when
  		 * we set last_event to curr_events, then all that activity
  		 * completing might cause the array to appear non-idle
  		 * and resync will be slowed down even though there might
  		 * not have been non-resync activity.  This will only
  		 * happen once though.  'last_events' will soon reflect
  		 * the state where there is little or no outstanding
  		 * resync requests, and further resync activity will
  		 * always make curr_events less than last_events.
c0e485216   NeilBrown   [PATCH] md: fix i...
6831
  		 *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6832
  		 */
eea1bf384   NeilBrown   md: Fix is_mddev_...
6833
  		if (init || curr_events - rdev->last_events > 64) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6834
6835
6836
6837
  			rdev->last_events = curr_events;
  			idle = 0;
  		}
  	}
4b80991c6   NeilBrown   md: Protect acces...
6838
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6839
6840
  	return idle;
  }
fd01b88c7   NeilBrown   md: remove typede...
6841
  void md_done_sync(struct mddev *mddev, int blocks, int ok)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6842
6843
6844
6845
6846
  {
  	/* another "blocks" (512byte) blocks have been synced */
  	atomic_sub(blocks, &mddev->recovery_active);
  	wake_up(&mddev->recovery_wait);
  	if (!ok) {
dfc706450   NeilBrown   md: restart recov...
6847
  		set_bit(MD_RECOVERY_INTR, &mddev->recovery);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6848
6849
6850
6851
  		md_wakeup_thread(mddev->thread);
  		// stop recovery, signal do_sync ....
  	}
  }
06d91a5fe   NeilBrown   [PATCH] md: impro...
6852
6853
  /* md_write_start(mddev, bi)
   * If we need to update some array metadata (e.g. 'active' flag
3d310eb7b   NeilBrown   [PATCH] md: fix d...
6854
6855
   * in superblock) before writing, schedule a superblock update
   * and wait for it to complete.
06d91a5fe   NeilBrown   [PATCH] md: impro...
6856
   */
fd01b88c7   NeilBrown   md: remove typede...
6857
  void md_write_start(struct mddev *mddev, struct bio *bi)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6858
  {
0fd62b861   Neil Brown   Make sure all cha...
6859
  	int did_change = 0;
06d91a5fe   NeilBrown   [PATCH] md: impro...
6860
  	if (bio_data_dir(bi) != WRITE)
3d310eb7b   NeilBrown   [PATCH] md: fix d...
6861
  		return;
06d91a5fe   NeilBrown   [PATCH] md: impro...
6862

f91de92ed   NeilBrown   [PATCH] md: allow...
6863
6864
6865
6866
6867
6868
  	BUG_ON(mddev->ro == 1);
  	if (mddev->ro == 2) {
  		/* need to switch to read/write */
  		mddev->ro = 0;
  		set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
  		md_wakeup_thread(mddev->thread);
251561982   NeilBrown   md: make sure a r...
6869
  		md_wakeup_thread(mddev->sync_thread);
0fd62b861   Neil Brown   Make sure all cha...
6870
  		did_change = 1;
f91de92ed   NeilBrown   [PATCH] md: allow...
6871
  	}
06d91a5fe   NeilBrown   [PATCH] md: impro...
6872
  	atomic_inc(&mddev->writes_pending);
31a59e342   NeilBrown   md: fix 'safemode...
6873
6874
  	if (mddev->safemode == 1)
  		mddev->safemode = 0;
06d91a5fe   NeilBrown   [PATCH] md: impro...
6875
  	if (mddev->in_sync) {
a9701a304   NeilBrown   [PATCH] md: suppo...
6876
  		spin_lock_irq(&mddev->write_lock);
3d310eb7b   NeilBrown   [PATCH] md: fix d...
6877
6878
  		if (mddev->in_sync) {
  			mddev->in_sync = 0;
850b2b420   NeilBrown   [PATCH] md: repla...
6879
  			set_bit(MD_CHANGE_CLEAN, &mddev->flags);
070dc6dd7   NeilBrown   md: resolve confu...
6880
  			set_bit(MD_CHANGE_PENDING, &mddev->flags);
3d310eb7b   NeilBrown   [PATCH] md: fix d...
6881
  			md_wakeup_thread(mddev->thread);
0fd62b861   Neil Brown   Make sure all cha...
6882
  			did_change = 1;
3d310eb7b   NeilBrown   [PATCH] md: fix d...
6883
  		}
a9701a304   NeilBrown   [PATCH] md: suppo...
6884
  		spin_unlock_irq(&mddev->write_lock);
06d91a5fe   NeilBrown   [PATCH] md: impro...
6885
  	}
0fd62b861   Neil Brown   Make sure all cha...
6886
  	if (did_change)
00bcb4ac7   NeilBrown   md: reduce depend...
6887
  		sysfs_notify_dirent_safe(mddev->sysfs_state);
09a44cc15   NeilBrown   md: notify usersp...
6888
  	wait_event(mddev->sb_wait,
09a44cc15   NeilBrown   md: notify usersp...
6889
  		   !test_bit(MD_CHANGE_PENDING, &mddev->flags));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6890
  }
fd01b88c7   NeilBrown   md: remove typede...
6891
  void md_write_end(struct mddev *mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6892
6893
6894
6895
  {
  	if (atomic_dec_and_test(&mddev->writes_pending)) {
  		if (mddev->safemode == 2)
  			md_wakeup_thread(mddev->thread);
16f17b39f   NeilBrown   [PATCH] md: incre...
6896
  		else if (mddev->safemode_delay)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6897
6898
6899
  			mod_timer(&mddev->safemode_timer, jiffies + mddev->safemode_delay);
  	}
  }
2a2275d63   NeilBrown   [PATCH] md: fix p...
6900
6901
6902
6903
6904
  /* md_allow_write(mddev)
   * Calling this ensures that the array is marked 'active' so that writes
   * may proceed without blocking.  It is important to call this before
   * attempting a GFP_KERNEL allocation while holding the mddev lock.
   * Must be called with mddev_lock held.
b5470dc5f   Dan Williams   md: resolve exter...
6905
6906
6907
   *
   * In the ->external case MD_CHANGE_CLEAN can not be cleared until mddev->lock
   * is dropped, so return -EAGAIN after notifying userspace.
2a2275d63   NeilBrown   [PATCH] md: fix p...
6908
   */
fd01b88c7   NeilBrown   md: remove typede...
6909
  int md_allow_write(struct mddev *mddev)
2a2275d63   NeilBrown   [PATCH] md: fix p...
6910
6911
  {
  	if (!mddev->pers)
b5470dc5f   Dan Williams   md: resolve exter...
6912
  		return 0;
2a2275d63   NeilBrown   [PATCH] md: fix p...
6913
  	if (mddev->ro)
b5470dc5f   Dan Williams   md: resolve exter...
6914
  		return 0;
1a0fd4977   Neil Brown   Don't try to make...
6915
  	if (!mddev->pers->sync_request)
b5470dc5f   Dan Williams   md: resolve exter...
6916
  		return 0;
2a2275d63   NeilBrown   [PATCH] md: fix p...
6917
6918
6919
6920
6921
  
  	spin_lock_irq(&mddev->write_lock);
  	if (mddev->in_sync) {
  		mddev->in_sync = 0;
  		set_bit(MD_CHANGE_CLEAN, &mddev->flags);
070dc6dd7   NeilBrown   md: resolve confu...
6922
  		set_bit(MD_CHANGE_PENDING, &mddev->flags);
2a2275d63   NeilBrown   [PATCH] md: fix p...
6923
6924
6925
6926
6927
  		if (mddev->safemode_delay &&
  		    mddev->safemode == 0)
  			mddev->safemode = 1;
  		spin_unlock_irq(&mddev->write_lock);
  		md_update_sb(mddev, 0);
00bcb4ac7   NeilBrown   md: reduce depend...
6928
  		sysfs_notify_dirent_safe(mddev->sysfs_state);
2a2275d63   NeilBrown   [PATCH] md: fix p...
6929
6930
  	} else
  		spin_unlock_irq(&mddev->write_lock);
b5470dc5f   Dan Williams   md: resolve exter...
6931

070dc6dd7   NeilBrown   md: resolve confu...
6932
  	if (test_bit(MD_CHANGE_PENDING, &mddev->flags))
b5470dc5f   Dan Williams   md: resolve exter...
6933
6934
6935
  		return -EAGAIN;
  	else
  		return 0;
2a2275d63   NeilBrown   [PATCH] md: fix p...
6936
6937
  }
  EXPORT_SYMBOL_GPL(md_allow_write);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6938
6939
  #define SYNC_MARKS	10
  #define	SYNC_MARK_STEP	(3*HZ)
fd01b88c7   NeilBrown   md: remove typede...
6940
  void md_do_sync(struct mddev *mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6941
  {
fd01b88c7   NeilBrown   md: remove typede...
6942
  	struct mddev *mddev2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6943
6944
  	unsigned int currspeed = 0,
  		 window;
57afd89f9   NeilBrown   [PATCH] md: impro...
6945
  	sector_t max_sectors,j, io_sectors;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6946
6947
6948
6949
6950
  	unsigned long mark[SYNC_MARKS];
  	sector_t mark_cnt[SYNC_MARKS];
  	int last_mark,m;
  	struct list_head *tmp;
  	sector_t last_check;
57afd89f9   NeilBrown   [PATCH] md: impro...
6951
  	int skipped = 0;
3cb030020   NeilBrown   md: removing type...
6952
  	struct md_rdev *rdev;
61df9d91e   NeilBrown   [PATCH] md: make ...
6953
  	char *desc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6954
6955
6956
6957
  
  	/* just incase thread restarts... */
  	if (test_bit(MD_RECOVERY_DONE, &mddev->recovery))
  		return;
5fd6c1dce   NeilBrown   [PATCH] md: allow...
6958
6959
  	if (mddev->ro) /* never try to sync a read-only array */
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6960

61df9d91e   NeilBrown   [PATCH] md: make ...
6961
6962
6963
6964
6965
6966
6967
6968
6969
6970
6971
  	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
  		if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
  			desc = "data-check";
  		else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
  			desc = "requested-resync";
  		else
  			desc = "resync";
  	} else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
  		desc = "reshape";
  	else
  		desc = "recovery";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6972
6973
6974
6975
6976
6977
6978
6979
6980
6981
6982
6983
6984
6985
6986
6987
6988
6989
6990
6991
  	/* we overload curr_resync somewhat here.
  	 * 0 == not engaged in resync at all
  	 * 2 == checking that there is no conflict with another sync
  	 * 1 == like 2, but have yielded to allow conflicting resync to
  	 *		commense
  	 * other == active in resync - this many blocks
  	 *
  	 * Before starting a resync we must have set curr_resync to
  	 * 2, and then checked that every "conflicting" array has curr_resync
  	 * less than ours.  When we find one that is the same or higher
  	 * we wait on resync_wait.  To avoid deadlock, we reduce curr_resync
  	 * to 1 if we choose to yield (based arbitrarily on address of mddev structure).
  	 * This will mean we have to start checking from the beginning again.
  	 *
  	 */
  
  	do {
  		mddev->curr_resync = 2;
  
  	try_again:
404e4b43f   NeilBrown   md: allow a resyn...
6992
  		if (kthread_should_stop())
6985c43f3   NeilBrown   [PATCH] Three one...
6993
  			set_bit(MD_RECOVERY_INTR, &mddev->recovery);
404e4b43f   NeilBrown   md: allow a resyn...
6994
6995
  
  		if (test_bit(MD_RECOVERY_INTR, &mddev->recovery))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6996
  			goto skip;
29ac4aa3f   NeilBrown   md: change INTERA...
6997
  		for_each_mddev(mddev2, tmp) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6998
6999
  			if (mddev2 == mddev)
  				continue;
90b08710e   Bernd Schubert   md: allow paralle...
7000
7001
7002
  			if (!mddev->parallel_resync
  			&&  mddev2->curr_resync
  			&&  match_mddev_units(mddev, mddev2)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7003
7004
7005
7006
7007
7008
7009
7010
7011
7012
7013
  				DEFINE_WAIT(wq);
  				if (mddev < mddev2 && mddev->curr_resync == 2) {
  					/* arbitrarily yield */
  					mddev->curr_resync = 1;
  					wake_up(&resync_wait);
  				}
  				if (mddev > mddev2 && mddev->curr_resync == 1)
  					/* no need to wait here, we can wait the next
  					 * time 'round when curr_resync == 2
  					 */
  					continue;
9744197c3   NeilBrown   md: Don't wait UN...
7014
7015
7016
7017
7018
  				/* We need to wait 'interruptible' so as not to
  				 * contribute to the load average, and not to
  				 * be caught by 'softlockup'
  				 */
  				prepare_to_wait(&resync_wait, &wq, TASK_INTERRUPTIBLE);
787453c23   NeilBrown   [PATCH] md: compl...
7019
  				if (!kthread_should_stop() &&
8712e5535   NeilBrown   [PATCH] md: make ...
7020
  				    mddev2->curr_resync >= mddev->curr_resync) {
61df9d91e   NeilBrown   [PATCH] md: make ...
7021
7022
  					printk(KERN_INFO "md: delaying %s of %s"
  					       " until %s has finished (they"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7023
7024
  					       " share one or more physical units)
  ",
61df9d91e   NeilBrown   [PATCH] md: make ...
7025
  					       desc, mdname(mddev), mdname(mddev2));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7026
  					mddev_put(mddev2);
9744197c3   NeilBrown   md: Don't wait UN...
7027
7028
  					if (signal_pending(current))
  						flush_signals(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7029
7030
7031
7032
7033
7034
7035
7036
  					schedule();
  					finish_wait(&resync_wait, &wq);
  					goto try_again;
  				}
  				finish_wait(&resync_wait, &wq);
  			}
  		}
  	} while (mddev->curr_resync < 2);
5fd6c1dce   NeilBrown   [PATCH] md: allow...
7037
  	j = 0;
9d88883e6   NeilBrown   [PATCH] md: teach...
7038
  	if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7039
  		/* resync follows the size requested by the personality,
57afd89f9   NeilBrown   [PATCH] md: impro...
7040
  		 * which defaults to physical size, but can be virtual size
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7041
7042
  		 */
  		max_sectors = mddev->resync_max_sectors;
9d88883e6   NeilBrown   [PATCH] md: teach...
7043
  		mddev->resync_mismatches = 0;
5fd6c1dce   NeilBrown   [PATCH] md: allow...
7044
  		/* we don't use the checkpoint if there's a bitmap */
5e96ee65c   Neil Brown   Allow setting sta...
7045
7046
7047
  		if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
  			j = mddev->resync_min;
  		else if (!mddev->bitmap)
5fd6c1dce   NeilBrown   [PATCH] md: allow...
7048
  			j = mddev->recovery_cp;
5e96ee65c   Neil Brown   Allow setting sta...
7049

ccfcc3c10   NeilBrown   [PATCH] md: Core ...
7050
  	} else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
58c0fed40   Andre Noll   md: Make mddev->s...
7051
  		max_sectors = mddev->dev_sectors;
5fd6c1dce   NeilBrown   [PATCH] md: allow...
7052
  	else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7053
  		/* recovery follows the physical size of devices */
58c0fed40   Andre Noll   md: Make mddev->s...
7054
  		max_sectors = mddev->dev_sectors;
5fd6c1dce   NeilBrown   [PATCH] md: allow...
7055
  		j = MaxSector;
4e59ca7da   Dan Williams   md: rcu_read_lock...
7056
7057
  		rcu_read_lock();
  		list_for_each_entry_rcu(rdev, &mddev->disks, same_set)
5fd6c1dce   NeilBrown   [PATCH] md: allow...
7058
7059
7060
7061
7062
  			if (rdev->raid_disk >= 0 &&
  			    !test_bit(Faulty, &rdev->flags) &&
  			    !test_bit(In_sync, &rdev->flags) &&
  			    rdev->recovery_offset < j)
  				j = rdev->recovery_offset;
4e59ca7da   Dan Williams   md: rcu_read_lock...
7063
  		rcu_read_unlock();
5fd6c1dce   NeilBrown   [PATCH] md: allow...
7064
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7065

61df9d91e   NeilBrown   [PATCH] md: make ...
7066
7067
7068
7069
7070
  	printk(KERN_INFO "md: %s of RAID array %s
  ", desc, mdname(mddev));
  	printk(KERN_INFO "md: minimum _guaranteed_  speed:"
  		" %d KB/sec/disk.
  ", speed_min(mddev));
338cec325   Adrian Bunk   [PATCH] merge som...
7071
  	printk(KERN_INFO "md: using maximum available idle IO bandwidth "
61df9d91e   NeilBrown   [PATCH] md: make ...
7072
7073
7074
  	       "(but not more than %d KB/sec) for %s.
  ",
  	       speed_max(mddev), desc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7075

eea1bf384   NeilBrown   md: Fix is_mddev_...
7076
  	is_mddev_idle(mddev, 1); /* this initializes IO event counters */
5fd6c1dce   NeilBrown   [PATCH] md: allow...
7077

57afd89f9   NeilBrown   [PATCH] md: impro...
7078
  	io_sectors = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7079
7080
  	for (m = 0; m < SYNC_MARKS; m++) {
  		mark[m] = jiffies;
57afd89f9   NeilBrown   [PATCH] md: impro...
7081
  		mark_cnt[m] = io_sectors;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7082
7083
7084
7085
7086
7087
7088
7089
7090
  	}
  	last_mark = 0;
  	mddev->resync_mark = mark[last_mark];
  	mddev->resync_mark_cnt = mark_cnt[last_mark];
  
  	/*
  	 * Tune reconstruction:
  	 */
  	window = 32*(PAGE_SIZE/512);
ac42450c7   Jonathan Brassow   MD: possible typo
7091
7092
7093
  	printk(KERN_INFO "md: using %dk window, over a total of %lluk.
  ",
  		window/2, (unsigned long long)max_sectors/2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7094
7095
  
  	atomic_set(&mddev->recovery_active, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7096
7097
7098
7099
  	last_check = 0;
  
  	if (j>2) {
  		printk(KERN_INFO 
61df9d91e   NeilBrown   [PATCH] md: make ...
7100
7101
7102
  		       "md: resuming %s of %s from checkpoint.
  ",
  		       desc, mdname(mddev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7103
7104
  		mddev->curr_resync = j;
  	}
75d3da43c   NeilBrown   md: Don't let imp...
7105
  	mddev->curr_resync_completed = j;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7106
7107
  
  	while (j < max_sectors) {
57afd89f9   NeilBrown   [PATCH] md: impro...
7108
  		sector_t sectors;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7109

57afd89f9   NeilBrown   [PATCH] md: impro...
7110
  		skipped = 0;
97e4f42d6   NeilBrown   md: occasionally ...
7111

7a91ee1f6   NeilBrown   md: don't update ...
7112
7113
7114
7115
7116
7117
7118
  		if (!test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
  		    ((mddev->curr_resync > mddev->curr_resync_completed &&
  		      (mddev->curr_resync - mddev->curr_resync_completed)
  		      > (max_sectors >> 4)) ||
  		     (j - mddev->curr_resync_completed)*2
  		     >= mddev->resync_max - mddev->curr_resync_completed
  			    )) {
97e4f42d6   NeilBrown   md: occasionally ...
7119
  			/* time to update curr_resync_completed */
97e4f42d6   NeilBrown   md: occasionally ...
7120
7121
  			wait_event(mddev->recovery_wait,
  				   atomic_read(&mddev->recovery_active) == 0);
75d3da43c   NeilBrown   md: Don't let imp...
7122
  			mddev->curr_resync_completed = j;
070dc6dd7   NeilBrown   md: resolve confu...
7123
  			set_bit(MD_CHANGE_CLEAN, &mddev->flags);
acb180b0e   NeilBrown   md: improve usefu...
7124
  			sysfs_notify(&mddev->kobj, NULL, "sync_completed");
97e4f42d6   NeilBrown   md: occasionally ...
7125
  		}
acb180b0e   NeilBrown   md: improve usefu...
7126

e62e58a5f   NeilBrown   md: use interrupt...
7127
7128
7129
7130
7131
7132
7133
7134
7135
7136
  		while (j >= mddev->resync_max && !kthread_should_stop()) {
  			/* As this condition is controlled by user-space,
  			 * we can block indefinitely, so use '_interruptible'
  			 * to avoid triggering warnings.
  			 */
  			flush_signals(current); /* just in case */
  			wait_event_interruptible(mddev->recovery_wait,
  						 mddev->resync_max > j
  						 || kthread_should_stop());
  		}
acb180b0e   NeilBrown   md: improve usefu...
7137
7138
7139
  
  		if (kthread_should_stop())
  			goto interrupted;
57afd89f9   NeilBrown   [PATCH] md: impro...
7140
  		sectors = mddev->pers->sync_request(mddev, j, &skipped,
c62072777   NeilBrown   md: allow a maxim...
7141
  						  currspeed < speed_min(mddev));
57afd89f9   NeilBrown   [PATCH] md: impro...
7142
  		if (sectors == 0) {
dfc706450   NeilBrown   md: restart recov...
7143
  			set_bit(MD_RECOVERY_INTR, &mddev->recovery);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7144
7145
  			goto out;
  		}
57afd89f9   NeilBrown   [PATCH] md: impro...
7146
7147
7148
7149
7150
  
  		if (!skipped) { /* actual IO requested */
  			io_sectors += sectors;
  			atomic_add(sectors, &mddev->recovery_active);
  		}
e875ecea2   NeilBrown   md/raid10 record ...
7151
7152
  		if (test_bit(MD_RECOVERY_INTR, &mddev->recovery))
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7153
7154
  		j += sectors;
  		if (j>1) mddev->curr_resync = j;
ff4e8d9a9   NeilBrown   [PATCH] md: fix r...
7155
  		mddev->curr_mark_cnt = io_sectors;
d7603b7e3   NeilBrown   [PATCH] md: make ...
7156
  		if (last_check == 0)
e875ecea2   NeilBrown   md/raid10 record ...
7157
  			/* this is the earliest that rebuild will be
d7603b7e3   NeilBrown   [PATCH] md: make ...
7158
7159
7160
  			 * visible in /proc/mdstat
  			 */
  			md_new_event(mddev);
57afd89f9   NeilBrown   [PATCH] md: impro...
7161
7162
  
  		if (last_check + window > io_sectors || j == max_sectors)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7163
  			continue;
57afd89f9   NeilBrown   [PATCH] md: impro...
7164
  		last_check = io_sectors;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7165
7166
7167
7168
7169
7170
7171
7172
  	repeat:
  		if (time_after_eq(jiffies, mark[last_mark] + SYNC_MARK_STEP )) {
  			/* step marks */
  			int next = (last_mark+1) % SYNC_MARKS;
  
  			mddev->resync_mark = mark[next];
  			mddev->resync_mark_cnt = mark_cnt[next];
  			mark[next] = jiffies;
57afd89f9   NeilBrown   [PATCH] md: impro...
7173
  			mark_cnt[next] = io_sectors - atomic_read(&mddev->recovery_active);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7174
7175
  			last_mark = next;
  		}
c62072777   NeilBrown   md: allow a maxim...
7176
7177
  		if (kthread_should_stop())
  			goto interrupted;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7178
7179
7180
7181
7182
7183
7184
7185
7186
  
  		/*
  		 * this loop exits only if either when we are slower than
  		 * the 'hard' speed limit, or the system was IO-idle for
  		 * a jiffy.
  		 * the system might be non-idle CPU-wise, but we only care
  		 * about not overloading the IO subsystem. (things like an
  		 * e2fsck being done on the RAID array should execute fast)
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7187
  		cond_resched();
57afd89f9   NeilBrown   [PATCH] md: impro...
7188
7189
  		currspeed = ((unsigned long)(io_sectors-mddev->resync_mark_cnt))/2
  			/((jiffies-mddev->resync_mark)/HZ +1) +1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7190

88202a0c8   NeilBrown   [PATCH] md: allow...
7191
7192
  		if (currspeed > speed_min(mddev)) {
  			if ((currspeed > speed_max(mddev)) ||
eea1bf384   NeilBrown   md: Fix is_mddev_...
7193
  					!is_mddev_idle(mddev, 0)) {
c0e485216   NeilBrown   [PATCH] md: fix i...
7194
  				msleep(500);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7195
7196
7197
7198
  				goto repeat;
  			}
  		}
  	}
61df9d91e   NeilBrown   [PATCH] md: make ...
7199
7200
  	printk(KERN_INFO "md: %s: %s done.
  ",mdname(mddev), desc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7201
7202
7203
7204
  	/*
  	 * this also signals 'finished resyncing' to md_stop
  	 */
   out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7205
7206
7207
  	wait_event(mddev->recovery_wait, !atomic_read(&mddev->recovery_active));
  
  	/* tell personality that we are finished */
57afd89f9   NeilBrown   [PATCH] md: impro...
7208
  	mddev->pers->sync_request(mddev, max_sectors, &skipped, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7209

dfc706450   NeilBrown   md: restart recov...
7210
  	if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery) &&
5fd6c1dce   NeilBrown   [PATCH] md: allow...
7211
7212
7213
7214
7215
  	    mddev->curr_resync > 2) {
  		if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
  			if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
  				if (mddev->curr_resync >= mddev->recovery_cp) {
  					printk(KERN_INFO
61df9d91e   NeilBrown   [PATCH] md: make ...
7216
7217
7218
  					       "md: checkpointing %s of %s.
  ",
  					       desc, mdname(mddev));
5fd6c1dce   NeilBrown   [PATCH] md: allow...
7219
7220
7221
7222
7223
7224
7225
  					mddev->recovery_cp = mddev->curr_resync;
  				}
  			} else
  				mddev->recovery_cp = MaxSector;
  		} else {
  			if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
  				mddev->curr_resync = MaxSector;
4e59ca7da   Dan Williams   md: rcu_read_lock...
7226
7227
  			rcu_read_lock();
  			list_for_each_entry_rcu(rdev, &mddev->disks, same_set)
5fd6c1dce   NeilBrown   [PATCH] md: allow...
7228
  				if (rdev->raid_disk >= 0 &&
70fffd0bf   NeilBrown   md: Don't update ...
7229
  				    mddev->delta_disks >= 0 &&
5fd6c1dce   NeilBrown   [PATCH] md: allow...
7230
7231
7232
7233
  				    !test_bit(Faulty, &rdev->flags) &&
  				    !test_bit(In_sync, &rdev->flags) &&
  				    rdev->recovery_offset < mddev->curr_resync)
  					rdev->recovery_offset = mddev->curr_resync;
4e59ca7da   Dan Williams   md: rcu_read_lock...
7234
  			rcu_read_unlock();
5fd6c1dce   NeilBrown   [PATCH] md: allow...
7235
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7236
  	}
175712843   NeilBrown   [PATCH] md: assor...
7237
  	set_bit(MD_CHANGE_DEVS, &mddev->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7238

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7239
   skip:
c07b70ad3   NeilBrown   md: adjust resync...
7240
7241
7242
7243
7244
7245
7246
  	if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
  		/* We completed so min/max setting can be forgotten if used. */
  		if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
  			mddev->resync_min = 0;
  		mddev->resync_max = MaxSector;
  	} else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
  		mddev->resync_min = mddev->curr_resync_completed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7247
7248
7249
7250
  	mddev->curr_resync = 0;
  	wake_up(&resync_wait);
  	set_bit(MD_RECOVERY_DONE, &mddev->recovery);
  	md_wakeup_thread(mddev->thread);
c62072777   NeilBrown   md: allow a maxim...
7251
7252
7253
7254
7255
7256
7257
7258
7259
7260
7261
  	return;
  
   interrupted:
  	/*
  	 * got a signal, exit.
  	 */
  	printk(KERN_INFO
  	       "md: md_do_sync() got signal ... exiting
  ");
  	set_bit(MD_RECOVERY_INTR, &mddev->recovery);
  	goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7262
  }
292695531   NeilBrown   [PATCH] md: Final...
7263
  EXPORT_SYMBOL_GPL(md_do_sync);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7264

fd01b88c7   NeilBrown   md: remove typede...
7265
  static int remove_and_add_spares(struct mddev *mddev)
b4c4c7b80   NeilBrown   [PATCH] md: resta...
7266
  {
3cb030020   NeilBrown   md: removing type...
7267
  	struct md_rdev *rdev;
b4c4c7b80   NeilBrown   [PATCH] md: resta...
7268
  	int spares = 0;
97e4f42d6   NeilBrown   md: occasionally ...
7269
  	mddev->curr_resync_completed = 0;
159ec1fc0   Cheng Renquan   md: use list_for_...
7270
  	list_for_each_entry(rdev, &mddev->disks, same_set)
b4c4c7b80   NeilBrown   [PATCH] md: resta...
7271
  		if (rdev->raid_disk >= 0 &&
6bfe0b499   Dan Williams   md: support block...
7272
  		    !test_bit(Blocked, &rdev->flags) &&
b4c4c7b80   NeilBrown   [PATCH] md: resta...
7273
7274
7275
7276
7277
  		    (test_bit(Faulty, &rdev->flags) ||
  		     ! test_bit(In_sync, &rdev->flags)) &&
  		    atomic_read(&rdev->nr_pending)==0) {
  			if (mddev->pers->hot_remove_disk(
  				    mddev, rdev->raid_disk)==0) {
36fad858a   Namhyung Kim   md: introduce lin...
7278
  				sysfs_unlink_rdev(mddev, rdev);
b4c4c7b80   NeilBrown   [PATCH] md: resta...
7279
7280
7281
  				rdev->raid_disk = -1;
  			}
  		}
5389042ff   NeilBrown   md: change manage...
7282
  	if (mddev->degraded) {
159ec1fc0   Cheng Renquan   md: use list_for_...
7283
  		list_for_each_entry(rdev, &mddev->disks, same_set) {
dfc706450   NeilBrown   md: restart recov...
7284
  			if (rdev->raid_disk >= 0 &&
e54271352   Dan Williams   md: do not count ...
7285
  			    !test_bit(In_sync, &rdev->flags) &&
de393cdea   NeilBrown   md: make it easie...
7286
  			    !test_bit(Faulty, &rdev->flags))
dfc706450   NeilBrown   md: restart recov...
7287
  				spares++;
b4c4c7b80   NeilBrown   [PATCH] md: resta...
7288
7289
7290
  			if (rdev->raid_disk < 0
  			    && !test_bit(Faulty, &rdev->flags)) {
  				rdev->recovery_offset = 0;
199050ea1   Neil Brown   rationalise retur...
7291
7292
  				if (mddev->pers->
  				    hot_add_disk(mddev, rdev) == 0) {
36fad858a   Namhyung Kim   md: introduce lin...
7293
  					if (sysfs_link_rdev(mddev, rdev))
00bcb4ac7   NeilBrown   md: reduce depend...
7294
  						/* failure here is OK */;
b4c4c7b80   NeilBrown   [PATCH] md: resta...
7295
7296
  					spares++;
  					md_new_event(mddev);
93be75ffd   NeilBrown   md: integrate spa...
7297
  					set_bit(MD_CHANGE_DEVS, &mddev->flags);
b4c4c7b80   NeilBrown   [PATCH] md: resta...
7298
7299
7300
  				} else
  					break;
  			}
dfc706450   NeilBrown   md: restart recov...
7301
  		}
b4c4c7b80   NeilBrown   [PATCH] md: resta...
7302
7303
7304
  	}
  	return spares;
  }
7ebc0be7f   NeilBrown   md: Be more caref...
7305

fd01b88c7   NeilBrown   md: remove typede...
7306
  static void reap_sync_thread(struct mddev *mddev)
7ebc0be7f   NeilBrown   md: Be more caref...
7307
  {
3cb030020   NeilBrown   md: removing type...
7308
  	struct md_rdev *rdev;
7ebc0be7f   NeilBrown   md: Be more caref...
7309
7310
  
  	/* resync has finished, collect result */
01f96c0a9   NeilBrown   md: Avoid waking ...
7311
  	md_unregister_thread(&mddev->sync_thread);
7ebc0be7f   NeilBrown   md: Be more caref...
7312
7313
7314
7315
7316
7317
7318
7319
7320
7321
7322
  	if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
  	    !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
  		/* success...*/
  		/* activate any spares */
  		if (mddev->pers->spare_active(mddev))
  			sysfs_notify(&mddev->kobj, NULL,
  				     "degraded");
  	}
  	if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
  	    mddev->pers->finish_reshape)
  		mddev->pers->finish_reshape(mddev);
7ebc0be7f   NeilBrown   md: Be more caref...
7323

d70ed2e4f   Andrei Warkentin   MD: Allow restart...
7324
7325
7326
7327
7328
  	/* If array is no-longer degraded, then any saved_raid_disk
  	 * information must be scrapped.  Also if any device is now
  	 * In_sync we must scrape the saved_raid_disk for that device
  	 * do the superblock for an incrementally recovered device
  	 * written out.
7ebc0be7f   NeilBrown   md: Be more caref...
7329
  	 */
d70ed2e4f   Andrei Warkentin   MD: Allow restart...
7330
7331
7332
  	list_for_each_entry(rdev, &mddev->disks, same_set)
  		if (!mddev->degraded ||
  		    test_bit(In_sync, &rdev->flags))
7ebc0be7f   NeilBrown   md: Be more caref...
7333
  			rdev->saved_raid_disk = -1;
d70ed2e4f   Andrei Warkentin   MD: Allow restart...
7334
  	md_update_sb(mddev, 1);
7ebc0be7f   NeilBrown   md: Be more caref...
7335
7336
7337
7338
7339
7340
7341
7342
7343
  	clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
  	clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
  	clear_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
  	clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
  	clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
  	/* flag recovery needed just to double check */
  	set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
  	sysfs_notify_dirent_safe(mddev->sysfs_action);
  	md_new_event(mddev);
768e587e1   Jonathan Brassow   MD: generate an e...
7344
7345
  	if (mddev->event_work.func)
  		queue_work(md_misc_wq, &mddev->event_work);
7ebc0be7f   NeilBrown   md: Be more caref...
7346
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7347
7348
7349
7350
7351
7352
7353
7354
7355
7356
  /*
   * This routine is regularly called by all per-raid-array threads to
   * deal with generic issues like resync and super-block update.
   * Raid personalities that don't have a thread (linear/raid0) do not
   * need this as they never do any recovery or update the superblock.
   *
   * It does not do any resync itself, but rather "forks" off other threads
   * to do that as needed.
   * When it is determined that resync is needed, we set MD_RECOVERY_RUNNING in
   * "->recovery" and create a thread at ->sync_thread.
dfc706450   NeilBrown   md: restart recov...
7357
   * When the thread finishes it sets MD_RECOVERY_DONE
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7358
7359
7360
7361
7362
7363
7364
7365
7366
7367
7368
   * and wakeups up this thread which will reap the thread and finish up.
   * This thread also removes any faulty devices (with nr_pending == 0).
   *
   * The overall approach is:
   *  1/ if the superblock needs updating, update it.
   *  2/ If a recovery thread is running, don't do anything else.
   *  3/ If recovery has finished, clean up, possibly marking spares active.
   *  4/ If there are any faulty devices, remove them.
   *  5/ If array is degraded, try to add spares devices
   *  6/ If array has spares or is not in-sync, start a resync thread.
   */
fd01b88c7   NeilBrown   md: remove typede...
7369
  void md_check_recovery(struct mddev *mddev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7370
  {
68866e425   Jonathan Brassow   MD: no sync IO wh...
7371
7372
  	if (mddev->suspended)
  		return;
5f40402d9   NeilBrown   [PATCH] md: call ...
7373
  	if (mddev->bitmap)
aa5cbd103   NeilBrown   md/bitmap: protec...
7374
  		bitmap_daemon_work(mddev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7375

fca4d848f   NeilBrown   [PATCH] md: merge...
7376
  	if (signal_pending(current)) {
31a59e342   NeilBrown   md: fix 'safemode...
7377
  		if (mddev->pers->sync_request && !mddev->external) {
fca4d848f   NeilBrown   [PATCH] md: merge...
7378
7379
7380
7381
7382
7383
7384
  			printk(KERN_INFO "md: %s in immediate safe mode
  ",
  			       mdname(mddev));
  			mddev->safemode = 2;
  		}
  		flush_signals(current);
  	}
c89a8eee6   NeilBrown   Allow faulty devi...
7385
7386
  	if (mddev->ro && !test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7387
  	if ( ! (
126925c09   NeilBrown   md: call md_updat...
7388
  		(mddev->flags & ~ (1<<MD_CHANGE_PENDING)) ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7389
  		test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
fca4d848f   NeilBrown   [PATCH] md: merge...
7390
  		test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
31a59e342   NeilBrown   md: fix 'safemode...
7391
  		(mddev->external == 0 && mddev->safemode == 1) ||
fca4d848f   NeilBrown   [PATCH] md: merge...
7392
7393
  		(mddev->safemode == 2 && ! atomic_read(&mddev->writes_pending)
  		 && !mddev->in_sync && mddev->recovery_cp == MaxSector)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7394
7395
  		))
  		return;
fca4d848f   NeilBrown   [PATCH] md: merge...
7396

df5b89b32   NeilBrown   [PATCH] md: Conve...
7397
  	if (mddev_trylock(mddev)) {
b4c4c7b80   NeilBrown   [PATCH] md: resta...
7398
  		int spares = 0;
fca4d848f   NeilBrown   [PATCH] md: merge...
7399

c89a8eee6   NeilBrown   Allow faulty devi...
7400
7401
7402
7403
  		if (mddev->ro) {
  			/* Only thing we do on a ro array is remove
  			 * failed devices.
  			 */
3cb030020   NeilBrown   md: removing type...
7404
  			struct md_rdev *rdev;
a8c42c7f4   NeilBrown   md: Don't use rem...
7405
7406
7407
7408
7409
7410
7411
  			list_for_each_entry(rdev, &mddev->disks, same_set)
  				if (rdev->raid_disk >= 0 &&
  				    !test_bit(Blocked, &rdev->flags) &&
  				    test_bit(Faulty, &rdev->flags) &&
  				    atomic_read(&rdev->nr_pending)==0) {
  					if (mddev->pers->hot_remove_disk(
  						    mddev, rdev->raid_disk)==0) {
36fad858a   Namhyung Kim   md: introduce lin...
7412
  						sysfs_unlink_rdev(mddev, rdev);
a8c42c7f4   NeilBrown   md: Don't use rem...
7413
7414
7415
  						rdev->raid_disk = -1;
  					}
  				}
c89a8eee6   NeilBrown   Allow faulty devi...
7416
7417
7418
  			clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
  			goto unlock;
  		}
31a59e342   NeilBrown   md: fix 'safemode...
7419
  		if (!mddev->external) {
0fd62b861   Neil Brown   Make sure all cha...
7420
  			int did_change = 0;
31a59e342   NeilBrown   md: fix 'safemode...
7421
7422
7423
7424
7425
7426
  			spin_lock_irq(&mddev->write_lock);
  			if (mddev->safemode &&
  			    !atomic_read(&mddev->writes_pending) &&
  			    !mddev->in_sync &&
  			    mddev->recovery_cp == MaxSector) {
  				mddev->in_sync = 1;
0fd62b861   Neil Brown   Make sure all cha...
7427
  				did_change = 1;
070dc6dd7   NeilBrown   md: resolve confu...
7428
  				set_bit(MD_CHANGE_CLEAN, &mddev->flags);
31a59e342   NeilBrown   md: fix 'safemode...
7429
7430
7431
7432
  			}
  			if (mddev->safemode == 1)
  				mddev->safemode = 0;
  			spin_unlock_irq(&mddev->write_lock);
0fd62b861   Neil Brown   Make sure all cha...
7433
  			if (did_change)
00bcb4ac7   NeilBrown   md: reduce depend...
7434
  				sysfs_notify_dirent_safe(mddev->sysfs_state);
fca4d848f   NeilBrown   [PATCH] md: merge...
7435
  		}
fca4d848f   NeilBrown   [PATCH] md: merge...
7436

850b2b420   NeilBrown   [PATCH] md: repla...
7437
7438
  		if (mddev->flags)
  			md_update_sb(mddev, 0);
06d91a5fe   NeilBrown   [PATCH] md: impro...
7439

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7440
7441
7442
7443
7444
7445
7446
  		if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) &&
  		    !test_bit(MD_RECOVERY_DONE, &mddev->recovery)) {
  			/* resync/recovery still happening */
  			clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
  			goto unlock;
  		}
  		if (mddev->sync_thread) {
7ebc0be7f   NeilBrown   md: Be more caref...
7447
  			reap_sync_thread(mddev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7448
7449
  			goto unlock;
  		}
72a23c211   Neil Brown   Make sure all cha...
7450
7451
7452
7453
7454
  		/* Set RUNNING before clearing NEEDED to avoid
  		 * any transients in the value of "sync_action".
  		 */
  		set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
  		clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
24dd469d7   NeilBrown   [PATCH] md: allow...
7455
7456
7457
  		/* Clear some bits that don't mean anything, but
  		 * might be left set
  		 */
24dd469d7   NeilBrown   [PATCH] md: allow...
7458
7459
  		clear_bit(MD_RECOVERY_INTR, &mddev->recovery);
  		clear_bit(MD_RECOVERY_DONE, &mddev->recovery);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7460

5fd6c1dce   NeilBrown   [PATCH] md: allow...
7461
7462
  		if (test_bit(MD_RECOVERY_FROZEN, &mddev->recovery))
  			goto unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7463
7464
7465
7466
7467
7468
  		/* no recovery is running.
  		 * remove any failed drives, then
  		 * add spares if possible.
  		 * Spare are also removed and re-added, to allow
  		 * the personality to fail the re-add.
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7469

b4c4c7b80   NeilBrown   [PATCH] md: resta...
7470
  		if (mddev->reshape_position != MaxSector) {
50ac168a6   NeilBrown   md: merge reconfi...
7471
7472
  			if (mddev->pers->check_reshape == NULL ||
  			    mddev->pers->check_reshape(mddev) != 0)
b4c4c7b80   NeilBrown   [PATCH] md: resta...
7473
7474
7475
  				/* Cannot proceed */
  				goto unlock;
  			set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
72a23c211   Neil Brown   Make sure all cha...
7476
  			clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
b4c4c7b80   NeilBrown   [PATCH] md: resta...
7477
  		} else if ((spares = remove_and_add_spares(mddev))) {
24dd469d7   NeilBrown   [PATCH] md: allow...
7478
7479
  			clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
  			clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
56ac36d72   Dan Williams   md: cancel check/...
7480
  			clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
72a23c211   Neil Brown   Make sure all cha...
7481
  			set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
24dd469d7   NeilBrown   [PATCH] md: allow...
7482
7483
  		} else if (mddev->recovery_cp < MaxSector) {
  			set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
72a23c211   Neil Brown   Make sure all cha...
7484
  			clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
24dd469d7   NeilBrown   [PATCH] md: allow...
7485
7486
  		} else if (!test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
  			/* nothing to be done ... */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7487
  			goto unlock;
24dd469d7   NeilBrown   [PATCH] md: allow...
7488

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7489
  		if (mddev->pers->sync_request) {
a654b9d8f   NeilBrown   [PATCH] md: allow...
7490
7491
7492
7493
7494
7495
7496
  			if (spares && mddev->bitmap && ! mddev->bitmap->file) {
  				/* We are adding a device or devices to an array
  				 * which has the bitmap stored on all devices.
  				 * So make sure all bitmap pages get written
  				 */
  				bitmap_write_all(mddev->bitmap);
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7497
7498
  			mddev->sync_thread = md_register_thread(md_do_sync,
  								mddev,
0da3c6194   NeilBrown   md: Improve name ...
7499
  								"resync");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7500
7501
7502
7503
7504
7505
  			if (!mddev->sync_thread) {
  				printk(KERN_ERR "%s: could not start resync"
  					" thread...
  ", 
  					mdname(mddev));
  				/* leave the spares where they are, it shouldn't hurt */
7ebc0be7f   NeilBrown   md: Be more caref...
7506
7507
7508
7509
7510
  				clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
  				clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
  				clear_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
  				clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
  				clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
d7603b7e3   NeilBrown   [PATCH] md: make ...
7511
  			} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7512
  				md_wakeup_thread(mddev->sync_thread);
00bcb4ac7   NeilBrown   md: reduce depend...
7513
  			sysfs_notify_dirent_safe(mddev->sysfs_action);
d7603b7e3   NeilBrown   [PATCH] md: make ...
7514
  			md_new_event(mddev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7515
7516
  		}
  	unlock:
72a23c211   Neil Brown   Make sure all cha...
7517
7518
7519
7520
  		if (!mddev->sync_thread) {
  			clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
  			if (test_and_clear_bit(MD_RECOVERY_RECOVER,
  					       &mddev->recovery))
0c3573f19   NeilBrown   md: use sysfs_not...
7521
  				if (mddev->sysfs_action)
00bcb4ac7   NeilBrown   md: reduce depend...
7522
  					sysfs_notify_dirent_safe(mddev->sysfs_action);
72a23c211   Neil Brown   Make sure all cha...
7523
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7524
7525
7526
  		mddev_unlock(mddev);
  	}
  }
fd01b88c7   NeilBrown   md: remove typede...
7527
  void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev)
6bfe0b499   Dan Williams   md: support block...
7528
  {
00bcb4ac7   NeilBrown   md: reduce depend...
7529
  	sysfs_notify_dirent_safe(rdev->sysfs_state);
6bfe0b499   Dan Williams   md: support block...
7530
  	wait_event_timeout(rdev->blocked_wait,
de393cdea   NeilBrown   md: make it easie...
7531
7532
  			   !test_bit(Blocked, &rdev->flags) &&
  			   !test_bit(BlockedBadBlocks, &rdev->flags),
6bfe0b499   Dan Williams   md: support block...
7533
7534
7535
7536
  			   msecs_to_jiffies(5000));
  	rdev_dec_pending(rdev, mddev);
  }
  EXPORT_SYMBOL(md_wait_for_blocked_rdev);
2230dfe4c   NeilBrown   md: beginnings of...
7537
7538
7539
7540
7541
7542
7543
7544
7545
7546
7547
7548
7549
7550
7551
7552
7553
7554
7555
7556
7557
7558
7559
7560
7561
7562
7563
7564
7565
7566
7567
7568
7569
7570
7571
7572
7573
7574
7575
7576
7577
7578
7579
7580
7581
7582
7583
7584
7585
7586
7587
7588
7589
7590
7591
7592
7593
7594
7595
7596
7597
7598
7599
7600
7601
7602
7603
7604
7605
7606
7607
7608
7609
7610
7611
7612
7613
7614
7615
7616
7617
7618
7619
7620
7621
7622
7623
7624
7625
7626
7627
7628
7629
7630
7631
7632
7633
7634
7635
7636
7637
7638
7639
7640
7641
7642
7643
7644
7645
7646
7647
7648
7649
7650
7651
7652
7653
7654
7655
7656
7657
7658
7659
7660
7661
7662
7663
7664
7665
7666
7667
7668
7669
7670
7671
7672
7673
7674
7675
7676
7677
7678
7679
7680
7681
7682
7683
7684
7685
7686
7687
7688
7689
7690
7691
7692
7693
7694
7695
7696
7697
7698
7699
7700
7701
7702
7703
7704
7705
7706
7707
7708
7709
7710
7711
7712
7713
7714
7715
7716
7717
7718
7719
7720
7721
7722
7723
7724
7725
7726
7727
7728
7729
7730
7731
7732
7733
7734
7735
7736
7737
7738
7739
7740
7741
7742
7743
7744
7745
7746
7747
7748
7749
7750
7751
7752
7753
7754
7755
7756
7757
7758
7759
7760
7761
7762
7763
7764
7765
7766
7767
7768
7769
7770
7771
7772
7773
7774
7775
7776
  
  /* Bad block management.
   * We can record which blocks on each device are 'bad' and so just
   * fail those blocks, or that stripe, rather than the whole device.
   * Entries in the bad-block table are 64bits wide.  This comprises:
   * Length of bad-range, in sectors: 0-511 for lengths 1-512
   * Start of bad-range, sector offset, 54 bits (allows 8 exbibytes)
   *  A 'shift' can be set so that larger blocks are tracked and
   *  consequently larger devices can be covered.
   * 'Acknowledged' flag - 1 bit. - the most significant bit.
   *
   * Locking of the bad-block table uses a seqlock so md_is_badblock
   * might need to retry if it is very unlucky.
   * We will sometimes want to check for bad blocks in a bi_end_io function,
   * so we use the write_seqlock_irq variant.
   *
   * When looking for a bad block we specify a range and want to
   * know if any block in the range is bad.  So we binary-search
   * to the last range that starts at-or-before the given endpoint,
   * (or "before the sector after the target range")
   * then see if it ends after the given start.
   * We return
   *  0 if there are no known bad blocks in the range
   *  1 if there are known bad block which are all acknowledged
   * -1 if there are bad blocks which have not yet been acknowledged in metadata.
   * plus the start/length of the first bad section we overlap.
   */
  int md_is_badblock(struct badblocks *bb, sector_t s, int sectors,
  		   sector_t *first_bad, int *bad_sectors)
  {
  	int hi;
  	int lo = 0;
  	u64 *p = bb->page;
  	int rv = 0;
  	sector_t target = s + sectors;
  	unsigned seq;
  
  	if (bb->shift > 0) {
  		/* round the start down, and the end up */
  		s >>= bb->shift;
  		target += (1<<bb->shift) - 1;
  		target >>= bb->shift;
  		sectors = target - s;
  	}
  	/* 'target' is now the first block after the bad range */
  
  retry:
  	seq = read_seqbegin(&bb->lock);
  
  	hi = bb->count;
  
  	/* Binary search between lo and hi for 'target'
  	 * i.e. for the last range that starts before 'target'
  	 */
  	/* INVARIANT: ranges before 'lo' and at-or-after 'hi'
  	 * are known not to be the last range before target.
  	 * VARIANT: hi-lo is the number of possible
  	 * ranges, and decreases until it reaches 1
  	 */
  	while (hi - lo > 1) {
  		int mid = (lo + hi) / 2;
  		sector_t a = BB_OFFSET(p[mid]);
  		if (a < target)
  			/* This could still be the one, earlier ranges
  			 * could not. */
  			lo = mid;
  		else
  			/* This and later ranges are definitely out. */
  			hi = mid;
  	}
  	/* 'lo' might be the last that started before target, but 'hi' isn't */
  	if (hi > lo) {
  		/* need to check all range that end after 's' to see if
  		 * any are unacknowledged.
  		 */
  		while (lo >= 0 &&
  		       BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) {
  			if (BB_OFFSET(p[lo]) < target) {
  				/* starts before the end, and finishes after
  				 * the start, so they must overlap
  				 */
  				if (rv != -1 && BB_ACK(p[lo]))
  					rv = 1;
  				else
  					rv = -1;
  				*first_bad = BB_OFFSET(p[lo]);
  				*bad_sectors = BB_LEN(p[lo]);
  			}
  			lo--;
  		}
  	}
  
  	if (read_seqretry(&bb->lock, seq))
  		goto retry;
  
  	return rv;
  }
  EXPORT_SYMBOL_GPL(md_is_badblock);
  
  /*
   * Add a range of bad blocks to the table.
   * This might extend the table, or might contract it
   * if two adjacent ranges can be merged.
   * We binary-search to find the 'insertion' point, then
   * decide how best to handle it.
   */
  static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors,
  			    int acknowledged)
  {
  	u64 *p;
  	int lo, hi;
  	int rv = 1;
  
  	if (bb->shift < 0)
  		/* badblocks are disabled */
  		return 0;
  
  	if (bb->shift) {
  		/* round the start down, and the end up */
  		sector_t next = s + sectors;
  		s >>= bb->shift;
  		next += (1<<bb->shift) - 1;
  		next >>= bb->shift;
  		sectors = next - s;
  	}
  
  	write_seqlock_irq(&bb->lock);
  
  	p = bb->page;
  	lo = 0;
  	hi = bb->count;
  	/* Find the last range that starts at-or-before 's' */
  	while (hi - lo > 1) {
  		int mid = (lo + hi) / 2;
  		sector_t a = BB_OFFSET(p[mid]);
  		if (a <= s)
  			lo = mid;
  		else
  			hi = mid;
  	}
  	if (hi > lo && BB_OFFSET(p[lo]) > s)
  		hi = lo;
  
  	if (hi > lo) {
  		/* we found a range that might merge with the start
  		 * of our new range
  		 */
  		sector_t a = BB_OFFSET(p[lo]);
  		sector_t e = a + BB_LEN(p[lo]);
  		int ack = BB_ACK(p[lo]);
  		if (e >= s) {
  			/* Yes, we can merge with a previous range */
  			if (s == a && s + sectors >= e)
  				/* new range covers old */
  				ack = acknowledged;
  			else
  				ack = ack && acknowledged;
  
  			if (e < s + sectors)
  				e = s + sectors;
  			if (e - a <= BB_MAX_LEN) {
  				p[lo] = BB_MAKE(a, e-a, ack);
  				s = e;
  			} else {
  				/* does not all fit in one range,
  				 * make p[lo] maximal
  				 */
  				if (BB_LEN(p[lo]) != BB_MAX_LEN)
  					p[lo] = BB_MAKE(a, BB_MAX_LEN, ack);
  				s = a + BB_MAX_LEN;
  			}
  			sectors = e - s;
  		}
  	}
  	if (sectors && hi < bb->count) {
  		/* 'hi' points to the first range that starts after 's'.
  		 * Maybe we can merge with the start of that range */
  		sector_t a = BB_OFFSET(p[hi]);
  		sector_t e = a + BB_LEN(p[hi]);
  		int ack = BB_ACK(p[hi]);
  		if (a <= s + sectors) {
  			/* merging is possible */
  			if (e <= s + sectors) {
  				/* full overlap */
  				e = s + sectors;
  				ack = acknowledged;
  			} else
  				ack = ack && acknowledged;
  
  			a = s;
  			if (e - a <= BB_MAX_LEN) {
  				p[hi] = BB_MAKE(a, e-a, ack);
  				s = e;
  			} else {
  				p[hi] = BB_MAKE(a, BB_MAX_LEN, ack);
  				s = a + BB_MAX_LEN;
  			}
  			sectors = e - s;
  			lo = hi;
  			hi++;
  		}
  	}
  	if (sectors == 0 && hi < bb->count) {
  		/* we might be able to combine lo and hi */
  		/* Note: 's' is at the end of 'lo' */
  		sector_t a = BB_OFFSET(p[hi]);
  		int lolen = BB_LEN(p[lo]);
  		int hilen = BB_LEN(p[hi]);
  		int newlen = lolen + hilen - (s - a);
  		if (s >= a && newlen < BB_MAX_LEN) {
  			/* yes, we can combine them */
  			int ack = BB_ACK(p[lo]) && BB_ACK(p[hi]);
  			p[lo] = BB_MAKE(BB_OFFSET(p[lo]), newlen, ack);
  			memmove(p + hi, p + hi + 1,
  				(bb->count - hi - 1) * 8);
  			bb->count--;
  		}
  	}
  	while (sectors) {
  		/* didn't merge (it all).
  		 * Need to add a range just before 'hi' */
  		if (bb->count >= MD_MAX_BADBLOCKS) {
  			/* No room for more */
  			rv = 0;
  			break;
  		} else {
  			int this_sectors = sectors;
  			memmove(p + hi + 1, p + hi,
  				(bb->count - hi) * 8);
  			bb->count++;
  
  			if (this_sectors > BB_MAX_LEN)
  				this_sectors = BB_MAX_LEN;
  			p[hi] = BB_MAKE(s, this_sectors, acknowledged);
  			sectors -= this_sectors;
  			s += this_sectors;
  		}
  	}
  
  	bb->changed = 1;
de393cdea   NeilBrown   md: make it easie...
7777
7778
  	if (!acknowledged)
  		bb->unacked_exist = 1;
2230dfe4c   NeilBrown   md: beginnings of...
7779
7780
7781
7782
  	write_sequnlock_irq(&bb->lock);
  
  	return rv;
  }
3cb030020   NeilBrown   md: removing type...
7783
  int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
2230dfe4c   NeilBrown   md: beginnings of...
7784
7785
7786
7787
7788
7789
  		       int acknowledged)
  {
  	int rv = md_set_badblocks(&rdev->badblocks,
  				  s + rdev->data_offset, sectors, acknowledged);
  	if (rv) {
  		/* Make sure they get written out promptly */
8bd2f0a05   NeilBrown   md: ensure new ba...
7790
  		sysfs_notify_dirent_safe(rdev->sysfs_state);
2230dfe4c   NeilBrown   md: beginnings of...
7791
7792
7793
7794
7795
7796
7797
7798
7799
7800
7801
7802
7803
7804
7805
7806
7807
7808
7809
7810
7811
7812
7813
7814
7815
7816
7817
7818
7819
7820
7821
7822
7823
7824
7825
7826
7827
7828
7829
7830
7831
7832
7833
7834
7835
7836
7837
7838
7839
7840
7841
7842
7843
7844
7845
7846
7847
7848
7849
7850
7851
7852
7853
7854
7855
7856
7857
7858
7859
7860
7861
7862
7863
7864
7865
7866
7867
7868
7869
7870
7871
7872
7873
7874
7875
7876
7877
7878
7879
7880
7881
7882
7883
7884
7885
7886
7887
7888
7889
7890
7891
  		set_bit(MD_CHANGE_CLEAN, &rdev->mddev->flags);
  		md_wakeup_thread(rdev->mddev->thread);
  	}
  	return rv;
  }
  EXPORT_SYMBOL_GPL(rdev_set_badblocks);
  
  /*
   * Remove a range of bad blocks from the table.
   * This may involve extending the table if we spilt a region,
   * but it must not fail.  So if the table becomes full, we just
   * drop the remove request.
   */
  static int md_clear_badblocks(struct badblocks *bb, sector_t s, int sectors)
  {
  	u64 *p;
  	int lo, hi;
  	sector_t target = s + sectors;
  	int rv = 0;
  
  	if (bb->shift > 0) {
  		/* When clearing we round the start up and the end down.
  		 * This should not matter as the shift should align with
  		 * the block size and no rounding should ever be needed.
  		 * However it is better the think a block is bad when it
  		 * isn't than to think a block is not bad when it is.
  		 */
  		s += (1<<bb->shift) - 1;
  		s >>= bb->shift;
  		target >>= bb->shift;
  		sectors = target - s;
  	}
  
  	write_seqlock_irq(&bb->lock);
  
  	p = bb->page;
  	lo = 0;
  	hi = bb->count;
  	/* Find the last range that starts before 'target' */
  	while (hi - lo > 1) {
  		int mid = (lo + hi) / 2;
  		sector_t a = BB_OFFSET(p[mid]);
  		if (a < target)
  			lo = mid;
  		else
  			hi = mid;
  	}
  	if (hi > lo) {
  		/* p[lo] is the last range that could overlap the
  		 * current range.  Earlier ranges could also overlap,
  		 * but only this one can overlap the end of the range.
  		 */
  		if (BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > target) {
  			/* Partial overlap, leave the tail of this range */
  			int ack = BB_ACK(p[lo]);
  			sector_t a = BB_OFFSET(p[lo]);
  			sector_t end = a + BB_LEN(p[lo]);
  
  			if (a < s) {
  				/* we need to split this range */
  				if (bb->count >= MD_MAX_BADBLOCKS) {
  					rv = 0;
  					goto out;
  				}
  				memmove(p+lo+1, p+lo, (bb->count - lo) * 8);
  				bb->count++;
  				p[lo] = BB_MAKE(a, s-a, ack);
  				lo++;
  			}
  			p[lo] = BB_MAKE(target, end - target, ack);
  			/* there is no longer an overlap */
  			hi = lo;
  			lo--;
  		}
  		while (lo >= 0 &&
  		       BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) {
  			/* This range does overlap */
  			if (BB_OFFSET(p[lo]) < s) {
  				/* Keep the early parts of this range. */
  				int ack = BB_ACK(p[lo]);
  				sector_t start = BB_OFFSET(p[lo]);
  				p[lo] = BB_MAKE(start, s - start, ack);
  				/* now low doesn't overlap, so.. */
  				break;
  			}
  			lo--;
  		}
  		/* 'lo' is strictly before, 'hi' is strictly after,
  		 * anything between needs to be discarded
  		 */
  		if (hi - lo > 1) {
  			memmove(p+lo+1, p+hi, (bb->count - hi) * 8);
  			bb->count -= (hi - lo - 1);
  		}
  	}
  
  	bb->changed = 1;
  out:
  	write_sequnlock_irq(&bb->lock);
  	return rv;
  }
3cb030020   NeilBrown   md: removing type...
7892
  int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors)
2230dfe4c   NeilBrown   md: beginnings of...
7893
7894
7895
7896
7897
7898
7899
7900
7901
7902
7903
7904
7905
7906
7907
7908
7909
7910
7911
7912
7913
7914
7915
7916
7917
7918
7919
7920
7921
  {
  	return md_clear_badblocks(&rdev->badblocks,
  				  s + rdev->data_offset,
  				  sectors);
  }
  EXPORT_SYMBOL_GPL(rdev_clear_badblocks);
  
  /*
   * Acknowledge all bad blocks in a list.
   * This only succeeds if ->changed is clear.  It is used by
   * in-kernel metadata updates
   */
  void md_ack_all_badblocks(struct badblocks *bb)
  {
  	if (bb->page == NULL || bb->changed)
  		/* no point even trying */
  		return;
  	write_seqlock_irq(&bb->lock);
  
  	if (bb->changed == 0) {
  		u64 *p = bb->page;
  		int i;
  		for (i = 0; i < bb->count ; i++) {
  			if (!BB_ACK(p[i])) {
  				sector_t start = BB_OFFSET(p[i]);
  				int len = BB_LEN(p[i]);
  				p[i] = BB_MAKE(start, len, 1);
  			}
  		}
de393cdea   NeilBrown   md: make it easie...
7922
  		bb->unacked_exist = 0;
2230dfe4c   NeilBrown   md: beginnings of...
7923
7924
7925
7926
  	}
  	write_sequnlock_irq(&bb->lock);
  }
  EXPORT_SYMBOL_GPL(md_ack_all_badblocks);
16c791a5a   NeilBrown   md/bad-block-log:...
7927
7928
7929
7930
7931
7932
7933
7934
7935
7936
7937
7938
7939
7940
7941
7942
7943
7944
7945
7946
7947
7948
7949
7950
7951
7952
7953
7954
7955
7956
7957
7958
7959
7960
7961
7962
7963
7964
7965
7966
7967
7968
7969
  /* sysfs access to bad-blocks list.
   * We present two files.
   * 'bad-blocks' lists sector numbers and lengths of ranges that
   *    are recorded as bad.  The list is truncated to fit within
   *    the one-page limit of sysfs.
   *    Writing "sector length" to this file adds an acknowledged
   *    bad block list.
   * 'unacknowledged-bad-blocks' lists bad blocks that have not yet
   *    been acknowledged.  Writing to this file adds bad blocks
   *    without acknowledging them.  This is largely for testing.
   */
  
  static ssize_t
  badblocks_show(struct badblocks *bb, char *page, int unack)
  {
  	size_t len;
  	int i;
  	u64 *p = bb->page;
  	unsigned seq;
  
  	if (bb->shift < 0)
  		return 0;
  
  retry:
  	seq = read_seqbegin(&bb->lock);
  
  	len = 0;
  	i = 0;
  
  	while (len < PAGE_SIZE && i < bb->count) {
  		sector_t s = BB_OFFSET(p[i]);
  		unsigned int length = BB_LEN(p[i]);
  		int ack = BB_ACK(p[i]);
  		i++;
  
  		if (unack && ack)
  			continue;
  
  		len += snprintf(page+len, PAGE_SIZE-len, "%llu %u
  ",
  				(unsigned long long)s << bb->shift,
  				length << bb->shift);
  	}
de393cdea   NeilBrown   md: make it easie...
7970
7971
  	if (unack && len == 0)
  		bb->unacked_exist = 0;
16c791a5a   NeilBrown   md/bad-block-log:...
7972
7973
7974
7975
7976
7977
7978
7979
7980
7981
7982
7983
7984
7985
7986
7987
7988
7989
7990
7991
7992
7993
7994
7995
7996
7997
7998
7999
8000
8001
8002
8003
8004
8005
8006
8007
8008
8009
8010
8011
8012
8013
8014
8015
8016
8017
8018
8019
8020
8021
  
  	if (read_seqretry(&bb->lock, seq))
  		goto retry;
  
  	return len;
  }
  
  #define DO_DEBUG 1
  
  static ssize_t
  badblocks_store(struct badblocks *bb, const char *page, size_t len, int unack)
  {
  	unsigned long long sector;
  	int length;
  	char newline;
  #ifdef DO_DEBUG
  	/* Allow clearing via sysfs *only* for testing/debugging.
  	 * Normally only a successful write may clear a badblock
  	 */
  	int clear = 0;
  	if (page[0] == '-') {
  		clear = 1;
  		page++;
  	}
  #endif /* DO_DEBUG */
  
  	switch (sscanf(page, "%llu %d%c", &sector, &length, &newline)) {
  	case 3:
  		if (newline != '
  ')
  			return -EINVAL;
  	case 2:
  		if (length <= 0)
  			return -EINVAL;
  		break;
  	default:
  		return -EINVAL;
  	}
  
  #ifdef DO_DEBUG
  	if (clear) {
  		md_clear_badblocks(bb, sector, length);
  		return len;
  	}
  #endif /* DO_DEBUG */
  	if (md_set_badblocks(bb, sector, length, !unack))
  		return len;
  	else
  		return -ENOSPC;
  }
75c96f858   Adrian Bunk   [PATCH] make some...
8022
8023
  static int md_notify_reboot(struct notifier_block *this,
  			    unsigned long code, void *x)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8024
8025
  {
  	struct list_head *tmp;
fd01b88c7   NeilBrown   md: remove typede...
8026
  	struct mddev *mddev;
2dba6a911   Daniel P. Berrange   md: don't delay r...
8027
  	int need_delay = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8028
8029
8030
8031
8032
  
  	if ((code == SYS_DOWN) || (code == SYS_HALT) || (code == SYS_POWER_OFF)) {
  
  		printk(KERN_INFO "md: stopping all md devices.
  ");
2dba6a911   Daniel P. Berrange   md: don't delay r...
8033
  		for_each_mddev(mddev, tmp) {
c71d48877   Neil Brown   [PATCH] Unlock md...
8034
  			if (mddev_trylock(mddev)) {
2b25000bf   NeilBrown   Restore force swi...
8035
8036
8037
8038
  				/* Force a switch to readonly even array
  				 * appears to still be in use.  Hence
  				 * the '100'.
  				 */
a4bd82d0d   NeilBrown   md: split md_set_...
8039
  				md_set_readonly(mddev, 100);
c71d48877   Neil Brown   [PATCH] Unlock md...
8040
8041
  				mddev_unlock(mddev);
  			}
2dba6a911   Daniel P. Berrange   md: don't delay r...
8042
8043
  			need_delay = 1;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8044
8045
8046
8047
8048
8049
  		/*
  		 * certain more exotic SCSI devices are known to be
  		 * volatile wrt too early system reboots. While the
  		 * right place to handle this issue is the given
  		 * driver, we do want to have a safe RAID driver ...
  		 */
2dba6a911   Daniel P. Berrange   md: don't delay r...
8050
8051
  		if (need_delay)
  			mdelay(1000*1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8052
8053
8054
  	}
  	return NOTIFY_DONE;
  }
75c96f858   Adrian Bunk   [PATCH] make some...
8055
  static struct notifier_block md_notifier = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8056
8057
8058
8059
8060
8061
8062
  	.notifier_call	= md_notify_reboot,
  	.next		= NULL,
  	.priority	= INT_MAX, /* before any real devices */
  };
  
  static void md_geninit(void)
  {
36a4e1fe0   NeilBrown   md: remove PRINTK...
8063
8064
  	pr_debug("md: sizeof(mdp_super_t) = %d
  ", (int)sizeof(mdp_super_t));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8065

c7705f344   Denis V. Lunev   drivers: use non-...
8066
  	proc_create("mdstat", S_IRUGO, NULL, &md_seq_fops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8067
  }
75c96f858   Adrian Bunk   [PATCH] make some...
8068
  static int __init md_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8069
  {
e804ac780   Tejun Heo   md: fix and updat...
8070
  	int ret = -ENOMEM;
ada609ee2   Tejun Heo   workqueue: use WQ...
8071
  	md_wq = alloc_workqueue("md", WQ_MEM_RECLAIM, 0);
e804ac780   Tejun Heo   md: fix and updat...
8072
8073
8074
8075
8076
8077
8078
8079
8080
8081
8082
8083
8084
  	if (!md_wq)
  		goto err_wq;
  
  	md_misc_wq = alloc_workqueue("md_misc", 0, 0);
  	if (!md_misc_wq)
  		goto err_misc_wq;
  
  	if ((ret = register_blkdev(MD_MAJOR, "md")) < 0)
  		goto err_md;
  
  	if ((ret = register_blkdev(0, "mdp")) < 0)
  		goto err_mdp;
  	mdp_major = ret;
3dbd8c2e3   Christoph Hellwig   md: stop defining...
8085
  	blk_register_region(MKDEV(MD_MAJOR, 0), 1UL<<MINORBITS, THIS_MODULE,
e8703fe1f   NeilBrown   [PATCH] md: remov...
8086
8087
  			    md_probe, NULL, NULL);
  	blk_register_region(MKDEV(mdp_major, 0), 1UL<<MINORBITS, THIS_MODULE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8088
  			    md_probe, NULL, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8089
  	register_reboot_notifier(&md_notifier);
0b4d41471   Eric W. Biederman   [PATCH] sysctl: r...
8090
  	raid_table_header = register_sysctl_table(raid_root_table);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8091
8092
  
  	md_geninit();
d710e1381   NeilBrown   md: remove space ...
8093
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8094

e804ac780   Tejun Heo   md: fix and updat...
8095
8096
8097
8098
8099
8100
8101
8102
8103
  err_mdp:
  	unregister_blkdev(MD_MAJOR, "md");
  err_md:
  	destroy_workqueue(md_misc_wq);
  err_misc_wq:
  	destroy_workqueue(md_wq);
  err_wq:
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8104
8105
8106
8107
8108
8109
8110
  
  #ifndef MODULE
  
  /*
   * Searches all registered partitions for autorun RAID arrays
   * at boot time.
   */
4d936ec1f   Michael J. Evans   md: software Raid...
8111
8112
8113
8114
8115
8116
  
  static LIST_HEAD(all_detected_devices);
  struct detected_devices_node {
  	struct list_head list;
  	dev_t dev;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8117
8118
8119
  
  void md_autodetect_dev(dev_t dev)
  {
4d936ec1f   Michael J. Evans   md: software Raid...
8120
8121
8122
8123
8124
8125
8126
8127
8128
8129
8130
  	struct detected_devices_node *node_detected_dev;
  
  	node_detected_dev = kzalloc(sizeof(*node_detected_dev), GFP_KERNEL);
  	if (node_detected_dev) {
  		node_detected_dev->dev = dev;
  		list_add_tail(&node_detected_dev->list, &all_detected_devices);
  	} else {
  		printk(KERN_CRIT "md: md_autodetect_dev: kzalloc failed"
  			", skipping dev(%d,%d)
  ", MAJOR(dev), MINOR(dev));
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8131
8132
8133
8134
8135
  }
  
  
  static void autostart_arrays(int part)
  {
3cb030020   NeilBrown   md: removing type...
8136
  	struct md_rdev *rdev;
4d936ec1f   Michael J. Evans   md: software Raid...
8137
8138
8139
  	struct detected_devices_node *node_detected_dev;
  	dev_t dev;
  	int i_scanned, i_passed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8140

4d936ec1f   Michael J. Evans   md: software Raid...
8141
8142
  	i_scanned = 0;
  	i_passed = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8143

4d936ec1f   Michael J. Evans   md: software Raid...
8144
8145
  	printk(KERN_INFO "md: Autodetecting RAID arrays.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8146

4d936ec1f   Michael J. Evans   md: software Raid...
8147
8148
8149
8150
8151
8152
8153
  	while (!list_empty(&all_detected_devices) && i_scanned < INT_MAX) {
  		i_scanned++;
  		node_detected_dev = list_entry(all_detected_devices.next,
  					struct detected_devices_node, list);
  		list_del(&node_detected_dev->list);
  		dev = node_detected_dev->dev;
  		kfree(node_detected_dev);
df968c4e8   NeilBrown   md: improve messa...
8154
  		rdev = md_import_device(dev,0, 90);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8155
8156
  		if (IS_ERR(rdev))
  			continue;
b2d444d7a   NeilBrown   [PATCH] md: conve...
8157
  		if (test_bit(Faulty, &rdev->flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8158
8159
8160
  			MD_BUG();
  			continue;
  		}
d0fae18f1   NeilBrown   md: clean up irre...
8161
  		set_bit(AutoDetected, &rdev->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8162
  		list_add(&rdev->same_set, &pending_raid_disks);
4d936ec1f   Michael J. Evans   md: software Raid...
8163
  		i_passed++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8164
  	}
4d936ec1f   Michael J. Evans   md: software Raid...
8165
8166
8167
8168
  
  	printk(KERN_INFO "md: Scanned %d and added %d devices.
  ",
  						i_scanned, i_passed);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8169
8170
8171
  
  	autorun_devices(part);
  }
fdee8ae44   Jeff Garzik   [PATCH] MD: condi...
8172
  #endif /* !MODULE */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8173
8174
8175
  
  static __exit void md_exit(void)
  {
fd01b88c7   NeilBrown   md: remove typede...
8176
  	struct mddev *mddev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8177
  	struct list_head *tmp;
8ab5e4c15   Greg Kroah-Hartman   [PATCH] devfs: Re...
8178

3dbd8c2e3   Christoph Hellwig   md: stop defining...
8179
  	blk_unregister_region(MKDEV(MD_MAJOR,0), 1U << MINORBITS);
e8703fe1f   NeilBrown   [PATCH] md: remov...
8180
  	blk_unregister_region(MKDEV(mdp_major,0), 1U << MINORBITS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8181

3dbd8c2e3   Christoph Hellwig   md: stop defining...
8182
  	unregister_blkdev(MD_MAJOR,"md");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8183
8184
8185
8186
  	unregister_blkdev(mdp_major, "mdp");
  	unregister_reboot_notifier(&md_notifier);
  	unregister_sysctl_table(raid_table_header);
  	remove_proc_entry("mdstat", NULL);
29ac4aa3f   NeilBrown   md: change INTERA...
8187
  	for_each_mddev(mddev, tmp) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8188
  		export_array(mddev);
d3374825c   NeilBrown   md: make devices ...
8189
  		mddev->hold_active = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8190
  	}
e804ac780   Tejun Heo   md: fix and updat...
8191
8192
  	destroy_workqueue(md_misc_wq);
  	destroy_workqueue(md_wq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8193
  }
685784aaf   Dan Williams   xor: make 'xor_bl...
8194
  subsys_initcall(md_init);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8195
  module_exit(md_exit)
f91de92ed   NeilBrown   [PATCH] md: allow...
8196
8197
8198
8199
8200
8201
8202
8203
8204
8205
8206
  static int get_ro(char *buffer, struct kernel_param *kp)
  {
  	return sprintf(buffer, "%d", start_readonly);
  }
  static int set_ro(const char *val, struct kernel_param *kp)
  {
  	char *e;
  	int num = simple_strtoul(val, &e, 10);
  	if (*val && (*e == '\0' || *e == '
  ')) {
  		start_readonly = num;
4dbcdc751   NeilBrown   [PATCH] md: count...
8207
  		return 0;
f91de92ed   NeilBrown   [PATCH] md: allow...
8208
8209
8210
  	}
  	return -EINVAL;
  }
80ca3a44f   NeilBrown   [PATCH] md: unify...
8211
8212
  module_param_call(start_ro, set_ro, get_ro, NULL, S_IRUSR|S_IWUSR);
  module_param(start_dirty_degraded, int, S_IRUGO|S_IWUSR);
6ff8d8ec0   NeilBrown   [PATCH] md: allow...
8213

efeb53c0e   NeilBrown   md: Allow md devi...
8214
  module_param_call(new_array, add_named_array, NULL, NULL, S_IWUSR);
f91de92ed   NeilBrown   [PATCH] md: allow...
8215

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8216
8217
8218
8219
8220
8221
  EXPORT_SYMBOL(register_md_personality);
  EXPORT_SYMBOL(unregister_md_personality);
  EXPORT_SYMBOL(md_error);
  EXPORT_SYMBOL(md_done_sync);
  EXPORT_SYMBOL(md_write_start);
  EXPORT_SYMBOL(md_write_end);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8222
8223
8224
  EXPORT_SYMBOL(md_register_thread);
  EXPORT_SYMBOL(md_unregister_thread);
  EXPORT_SYMBOL(md_wakeup_thread);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8225
8226
  EXPORT_SYMBOL(md_check_recovery);
  MODULE_LICENSE("GPL");
0efb9e619   NeilBrown   md: add MODULE_DE...
8227
  MODULE_DESCRIPTION("MD RAID framework");
aa1595e9f   NeilBrown   [PATCH] md: make ...
8228
  MODULE_ALIAS("md");
72008652d   NeilBrown   [PATCH] md: creat...
8229
  MODULE_ALIAS_BLOCKDEV_MAJOR(MD_MAJOR);