diff options
author | NeilBrown <neilb@suse.de> | 2005-11-09 00:39:36 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-09 10:56:38 -0500 |
commit | f91de92ed6bfb70a3ff607558c910c7bf34d45e9 (patch) | |
tree | 7891da2296aba0302b48220bdd291acc0e92e810 /drivers/md/md.c | |
parent | 19133a4298223422742db7b5f940e8c54c6a1846 (diff) |
[PATCH] md: allow md arrays to be started read-only (module parameter).
When an md array is started, the superblock will be written, and resync may
commense. This is not good if you want to be completely read-only as, for
example, when preparing to resume from a suspend-to-disk image.
So introduce a module parameter "start_ro" which can be set
to '1' at boot, at module load, or via
/sys/module/md_mod/parameters/start_ro
When this is set, new arrays get an 'auto-ro' mode, which disables all
internal io (superblock updates, resync, recovery) and is automatically
switched to 'rw' when the first write request arrives.
The array can be set to true 'ro' mode using 'mdadm -r' before the first
write request, or resync can be started without a write using 'mdadm -w'.
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/md/md.c')
-rw-r--r-- | drivers/md/md.c | 59 |
1 files changed, 51 insertions, 8 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index 8238c1c0ec09..d002b8301fc2 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -131,6 +131,8 @@ static ctl_table raid_root_table[] = { | |||
131 | 131 | ||
132 | static struct block_device_operations md_fops; | 132 | static struct block_device_operations md_fops; |
133 | 133 | ||
134 | static int start_readonly; | ||
135 | |||
134 | /* | 136 | /* |
135 | * Enables to iterate over all existing md arrays | 137 | * Enables to iterate over all existing md arrays |
136 | * all_mddevs_lock protects this list. | 138 | * all_mddevs_lock protects this list. |
@@ -2029,6 +2031,9 @@ static int do_md_run(mddev_t * mddev) | |||
2029 | mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */ | 2031 | mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */ |
2030 | mddev->barriers_work = 1; | 2032 | mddev->barriers_work = 1; |
2031 | 2033 | ||
2034 | if (start_readonly) | ||
2035 | mddev->ro = 2; /* read-only, but switch on first write */ | ||
2036 | |||
2032 | /* before we start the array running, initialise the bitmap */ | 2037 | /* before we start the array running, initialise the bitmap */ |
2033 | err = bitmap_create(mddev); | 2038 | err = bitmap_create(mddev); |
2034 | if (err) | 2039 | if (err) |
@@ -2141,7 +2146,7 @@ static int do_md_stop(mddev_t * mddev, int ro) | |||
2141 | 2146 | ||
2142 | if (ro) { | 2147 | if (ro) { |
2143 | err = -ENXIO; | 2148 | err = -ENXIO; |
2144 | if (mddev->ro) | 2149 | if (mddev->ro==1) |
2145 | goto out; | 2150 | goto out; |
2146 | mddev->ro = 1; | 2151 | mddev->ro = 1; |
2147 | } else { | 2152 | } else { |
@@ -3258,12 +3263,22 @@ static int md_ioctl(struct inode *inode, struct file *file, | |||
3258 | 3263 | ||
3259 | /* | 3264 | /* |
3260 | * The remaining ioctls are changing the state of the | 3265 | * The remaining ioctls are changing the state of the |
3261 | * superblock, so we do not allow read-only arrays | 3266 | * superblock, so we do not allow them on read-only arrays. |
3262 | * here: | 3267 | * However non-MD ioctls (e.g. get-size) will still come through |
3268 | * here and hit the 'default' below, so only disallow | ||
3269 | * 'md' ioctls, and switch to rw mode if started auto-readonly. | ||
3263 | */ | 3270 | */ |
3264 | if (mddev->ro) { | 3271 | if (_IOC_TYPE(cmd) == MD_MAJOR && |
3265 | err = -EROFS; | 3272 | mddev->ro && mddev->pers) { |
3266 | goto abort_unlock; | 3273 | if (mddev->ro == 2) { |
3274 | mddev->ro = 0; | ||
3275 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); | ||
3276 | md_wakeup_thread(mddev->thread); | ||
3277 | |||
3278 | } else { | ||
3279 | err = -EROFS; | ||
3280 | goto abort_unlock; | ||
3281 | } | ||
3267 | } | 3282 | } |
3268 | 3283 | ||
3269 | switch (cmd) | 3284 | switch (cmd) |
@@ -3651,8 +3666,10 @@ static int md_seq_show(struct seq_file *seq, void *v) | |||
3651 | seq_printf(seq, "%s : %sactive", mdname(mddev), | 3666 | seq_printf(seq, "%s : %sactive", mdname(mddev), |
3652 | mddev->pers ? "" : "in"); | 3667 | mddev->pers ? "" : "in"); |
3653 | if (mddev->pers) { | 3668 | if (mddev->pers) { |
3654 | if (mddev->ro) | 3669 | if (mddev->ro==1) |
3655 | seq_printf(seq, " (read-only)"); | 3670 | seq_printf(seq, " (read-only)"); |
3671 | if (mddev->ro==2) | ||
3672 | seq_printf(seq, "(auto-read-only)"); | ||
3656 | seq_printf(seq, " %s", mddev->pers->name); | 3673 | seq_printf(seq, " %s", mddev->pers->name); |
3657 | } | 3674 | } |
3658 | 3675 | ||
@@ -3696,7 +3713,9 @@ static int md_seq_show(struct seq_file *seq, void *v) | |||
3696 | status_resync (seq, mddev); | 3713 | status_resync (seq, mddev); |
3697 | seq_printf(seq, "\n "); | 3714 | seq_printf(seq, "\n "); |
3698 | } else if (mddev->curr_resync == 1 || mddev->curr_resync == 2) | 3715 | } else if (mddev->curr_resync == 1 || mddev->curr_resync == 2) |
3699 | seq_printf(seq, " resync=DELAYED\n "); | 3716 | seq_printf(seq, "\tresync=DELAYED\n "); |
3717 | else if (mddev->recovery_cp < MaxSector) | ||
3718 | seq_printf(seq, "\tresync=PENDING\n "); | ||
3700 | } else | 3719 | } else |
3701 | seq_printf(seq, "\n "); | 3720 | seq_printf(seq, "\n "); |
3702 | 3721 | ||
@@ -3833,6 +3852,13 @@ void md_write_start(mddev_t *mddev, struct bio *bi) | |||
3833 | if (bio_data_dir(bi) != WRITE) | 3852 | if (bio_data_dir(bi) != WRITE) |
3834 | return; | 3853 | return; |
3835 | 3854 | ||
3855 | BUG_ON(mddev->ro == 1); | ||
3856 | if (mddev->ro == 2) { | ||
3857 | /* need to switch to read/write */ | ||
3858 | mddev->ro = 0; | ||
3859 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); | ||
3860 | md_wakeup_thread(mddev->thread); | ||
3861 | } | ||
3836 | atomic_inc(&mddev->writes_pending); | 3862 | atomic_inc(&mddev->writes_pending); |
3837 | if (mddev->in_sync) { | 3863 | if (mddev->in_sync) { |
3838 | spin_lock_irq(&mddev->write_lock); | 3864 | spin_lock_irq(&mddev->write_lock); |
@@ -4431,6 +4457,23 @@ static __exit void md_exit(void) | |||
4431 | module_init(md_init) | 4457 | module_init(md_init) |
4432 | module_exit(md_exit) | 4458 | module_exit(md_exit) |
4433 | 4459 | ||
4460 | static int get_ro(char *buffer, struct kernel_param *kp) | ||
4461 | { | ||
4462 | return sprintf(buffer, "%d", start_readonly); | ||
4463 | } | ||
4464 | static int set_ro(const char *val, struct kernel_param *kp) | ||
4465 | { | ||
4466 | char *e; | ||
4467 | int num = simple_strtoul(val, &e, 10); | ||
4468 | if (*val && (*e == '\0' || *e == '\n')) { | ||
4469 | start_readonly = num; | ||
4470 | return 0;; | ||
4471 | } | ||
4472 | return -EINVAL; | ||
4473 | } | ||
4474 | |||
4475 | module_param_call(start_ro, set_ro, get_ro, NULL, 0600); | ||
4476 | |||
4434 | EXPORT_SYMBOL(register_md_personality); | 4477 | EXPORT_SYMBOL(register_md_personality); |
4435 | EXPORT_SYMBOL(unregister_md_personality); | 4478 | EXPORT_SYMBOL(unregister_md_personality); |
4436 | EXPORT_SYMBOL(md_error); | 4479 | EXPORT_SYMBOL(md_error); |