提交 f91de92e 编写于 作者: N NeilBrown 提交者: Linus Torvalds

[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: NNeil Brown <neilb@suse.de>
Signed-off-by: NAndrew Morton <akpm@osdl.org>
Signed-off-by: NLinus Torvalds <torvalds@osdl.org>
上级 19133a42
...@@ -131,6 +131,8 @@ static ctl_table raid_root_table[] = { ...@@ -131,6 +131,8 @@ static ctl_table raid_root_table[] = {
static struct block_device_operations md_fops; static struct block_device_operations md_fops;
static int start_readonly;
/* /*
* Enables to iterate over all existing md arrays * Enables to iterate over all existing md arrays
* all_mddevs_lock protects this list. * all_mddevs_lock protects this list.
...@@ -2029,6 +2031,9 @@ static int do_md_run(mddev_t * mddev) ...@@ -2029,6 +2031,9 @@ static int do_md_run(mddev_t * mddev)
mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */ mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */
mddev->barriers_work = 1; mddev->barriers_work = 1;
if (start_readonly)
mddev->ro = 2; /* read-only, but switch on first write */
/* before we start the array running, initialise the bitmap */ /* before we start the array running, initialise the bitmap */
err = bitmap_create(mddev); err = bitmap_create(mddev);
if (err) if (err)
...@@ -2141,7 +2146,7 @@ static int do_md_stop(mddev_t * mddev, int ro) ...@@ -2141,7 +2146,7 @@ static int do_md_stop(mddev_t * mddev, int ro)
if (ro) { if (ro) {
err = -ENXIO; err = -ENXIO;
if (mddev->ro) if (mddev->ro==1)
goto out; goto out;
mddev->ro = 1; mddev->ro = 1;
} else { } else {
...@@ -3258,12 +3263,22 @@ static int md_ioctl(struct inode *inode, struct file *file, ...@@ -3258,12 +3263,22 @@ static int md_ioctl(struct inode *inode, struct file *file,
/* /*
* The remaining ioctls are changing the state of the * The remaining ioctls are changing the state of the
* superblock, so we do not allow read-only arrays * superblock, so we do not allow them on read-only arrays.
* here: * 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.
*/ */
if (mddev->ro) { if (_IOC_TYPE(cmd) == MD_MAJOR &&
err = -EROFS; mddev->ro && mddev->pers) {
goto abort_unlock; if (mddev->ro == 2) {
mddev->ro = 0;
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
md_wakeup_thread(mddev->thread);
} else {
err = -EROFS;
goto abort_unlock;
}
} }
switch (cmd) switch (cmd)
...@@ -3651,8 +3666,10 @@ static int md_seq_show(struct seq_file *seq, void *v) ...@@ -3651,8 +3666,10 @@ static int md_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "%s : %sactive", mdname(mddev), seq_printf(seq, "%s : %sactive", mdname(mddev),
mddev->pers ? "" : "in"); mddev->pers ? "" : "in");
if (mddev->pers) { if (mddev->pers) {
if (mddev->ro) if (mddev->ro==1)
seq_printf(seq, " (read-only)"); seq_printf(seq, " (read-only)");
if (mddev->ro==2)
seq_printf(seq, "(auto-read-only)");
seq_printf(seq, " %s", mddev->pers->name); seq_printf(seq, " %s", mddev->pers->name);
} }
...@@ -3696,7 +3713,9 @@ static int md_seq_show(struct seq_file *seq, void *v) ...@@ -3696,7 +3713,9 @@ static int md_seq_show(struct seq_file *seq, void *v)
status_resync (seq, mddev); status_resync (seq, mddev);
seq_printf(seq, "\n "); seq_printf(seq, "\n ");
} else if (mddev->curr_resync == 1 || mddev->curr_resync == 2) } else if (mddev->curr_resync == 1 || mddev->curr_resync == 2)
seq_printf(seq, " resync=DELAYED\n "); seq_printf(seq, "\tresync=DELAYED\n ");
else if (mddev->recovery_cp < MaxSector)
seq_printf(seq, "\tresync=PENDING\n ");
} else } else
seq_printf(seq, "\n "); seq_printf(seq, "\n ");
...@@ -3833,6 +3852,13 @@ void md_write_start(mddev_t *mddev, struct bio *bi) ...@@ -3833,6 +3852,13 @@ void md_write_start(mddev_t *mddev, struct bio *bi)
if (bio_data_dir(bi) != WRITE) if (bio_data_dir(bi) != WRITE)
return; return;
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);
}
atomic_inc(&mddev->writes_pending); atomic_inc(&mddev->writes_pending);
if (mddev->in_sync) { if (mddev->in_sync) {
spin_lock_irq(&mddev->write_lock); spin_lock_irq(&mddev->write_lock);
...@@ -4431,6 +4457,23 @@ static __exit void md_exit(void) ...@@ -4431,6 +4457,23 @@ static __exit void md_exit(void)
module_init(md_init) module_init(md_init)
module_exit(md_exit) module_exit(md_exit)
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 == '\n')) {
start_readonly = num;
return 0;;
}
return -EINVAL;
}
module_param_call(start_ro, set_ro, get_ro, NULL, 0600);
EXPORT_SYMBOL(register_md_personality); EXPORT_SYMBOL(register_md_personality);
EXPORT_SYMBOL(unregister_md_personality); EXPORT_SYMBOL(unregister_md_personality);
EXPORT_SYMBOL(md_error); EXPORT_SYMBOL(md_error);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册