diff options
-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); |