diff options
author | NeilBrown <neilb@suse.de> | 2009-03-31 14:56:41 +1100 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2009-03-31 14:56:41 +1100 |
commit | b3546035277847028df650b147469fc943cf5c71 (patch) | |
tree | 87966abc5456a62845326eb8d5a5cf0f88879b2d | |
parent | d562b0c4313e3ddea402a400371afa47ddf679f9 (diff) |
md/raid5: allow layout/chunksize to be changed on an active 2-drive raid5.
2-drive raid5's aren't very interesting. But if you are converting
a raid1 into a raid5, you will at least temporarily have one. And
that it a good time to set the layout/chunksize for the new RAID5
if you aren't happy with the defaults.
layout and chunksize don't actually affect the placement of data
on a 2-drive raid5, so we just do some internal book-keeping.
Signed-off-by: NeilBrown <neilb@suse.de>
-rw-r--r-- | drivers/md/md.c | 37 | ||||
-rw-r--r-- | drivers/md/raid5.c | 42 |
2 files changed, 66 insertions, 13 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index 05b613b5e4b..0689d89d263 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2771,12 +2771,18 @@ layout_store(mddev_t *mddev, const char *buf, size_t len) if (!*buf || (*e && *e != '\n')) return -EINVAL; - if (mddev->pers) - return -EBUSY; - - mddev->new_layout = n; - if (mddev->reshape_position == MaxSector) - mddev->layout = n; + if (mddev->pers) { + int err; + if (mddev->pers->reconfig == NULL) + return -EBUSY; + err = mddev->pers->reconfig(mddev, n, -1); + if (err) + return err; + } else { + mddev->new_layout = n; + if (mddev->reshape_position == MaxSector) + mddev->layout = n; + } return len; } static struct md_sysfs_entry md_layout = @@ -2833,19 +2839,24 @@ chunk_size_show(mddev_t *mddev, char *page) static ssize_t chunk_size_store(mddev_t *mddev, const char *buf, size_t len) { - /* can only set chunk_size if array is not yet active */ char *e; unsigned long n = simple_strtoul(buf, &e, 10); if (!*buf || (*e && *e != '\n')) return -EINVAL; - if (mddev->pers) - return -EBUSY; - - mddev->new_chunk = n; - if (mddev->reshape_position == MaxSector) - mddev->chunk_size = n; + if (mddev->pers) { + int err; + if (mddev->pers->reconfig == NULL) + return -EBUSY; + err = mddev->pers->reconfig(mddev, -1, n); + if (err) + return err; + } else { + mddev->new_chunk = n; + if (mddev->reshape_position == MaxSector) + mddev->chunk_size = n; + } return len; } static struct md_sysfs_entry md_chunk_size = diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 611ea7bbf47..8a5e14e4a85 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -4913,6 +4913,47 @@ static void *raid5_takeover_raid1(mddev_t *mddev) } +static int raid5_reconfig(mddev_t *mddev, int new_layout, int new_chunk) +{ + /* Currently the layout and chunk size can only be changed + * for a 2-drive raid array, as in that case no data shuffling + * is required. + * Later we might validate these and set new_* so a reshape + * can complete the change. + */ + raid5_conf_t *conf = mddev_to_conf(mddev); + + if (new_layout >= 0 && !algorithm_valid_raid5(new_layout)) + return -EINVAL; + if (new_chunk > 0) { + if (new_chunk & (new_chunk-1)) + /* not a power of 2 */ + return -EINVAL; + if (new_chunk < PAGE_SIZE) + return -EINVAL; + if (mddev->array_sectors & ((new_chunk>>9)-1)) + /* not factor of array size */ + return -EINVAL; + } + + /* They look valid */ + + if (mddev->raid_disks != 2) + return -EINVAL; + + if (new_layout >= 0) { + conf->algorithm = new_layout; + mddev->layout = mddev->new_layout = new_layout; + } + if (new_chunk > 0) { + conf->chunk_size = new_chunk; + mddev->chunk_size = mddev->new_chunk = new_chunk; + } + set_bit(MD_CHANGE_DEVS, &mddev->flags); + md_wakeup_thread(mddev->thread); + return 0; +} + static void *raid5_takeover(mddev_t *mddev) { /* raid5 can take over: @@ -5023,6 +5064,7 @@ static struct mdk_personality raid5_personality = #endif .quiesce = raid5_quiesce, .takeover = raid5_takeover, + .reconfig = raid5_reconfig, }; static struct mdk_personality raid4_personality = |