diff options
author | NeilBrown <neilb@suse.de> | 2009-03-30 23:56:41 -0400 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2009-03-30 23:56:41 -0400 |
commit | b3546035277847028df650b147469fc943cf5c71 (patch) | |
tree | 87966abc5456a62845326eb8d5a5cf0f88879b2d /drivers/md | |
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>
Diffstat (limited to 'drivers/md')
-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 05b613b5e4b2..0689d89d263c 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) | |||
2771 | if (!*buf || (*e && *e != '\n')) | 2771 | if (!*buf || (*e && *e != '\n')) |
2772 | return -EINVAL; | 2772 | return -EINVAL; |
2773 | 2773 | ||
2774 | if (mddev->pers) | 2774 | if (mddev->pers) { |
2775 | return -EBUSY; | 2775 | int err; |
2776 | 2776 | if (mddev->pers->reconfig == NULL) | |
2777 | mddev->new_layout = n; | 2777 | return -EBUSY; |
2778 | if (mddev->reshape_position == MaxSector) | 2778 | err = mddev->pers->reconfig(mddev, n, -1); |
2779 | mddev->layout = n; | 2779 | if (err) |
2780 | return err; | ||
2781 | } else { | ||
2782 | mddev->new_layout = n; | ||
2783 | if (mddev->reshape_position == MaxSector) | ||
2784 | mddev->layout = n; | ||
2785 | } | ||
2780 | return len; | 2786 | return len; |
2781 | } | 2787 | } |
2782 | static struct md_sysfs_entry md_layout = | 2788 | static struct md_sysfs_entry md_layout = |
@@ -2833,19 +2839,24 @@ chunk_size_show(mddev_t *mddev, char *page) | |||
2833 | static ssize_t | 2839 | static ssize_t |
2834 | chunk_size_store(mddev_t *mddev, const char *buf, size_t len) | 2840 | chunk_size_store(mddev_t *mddev, const char *buf, size_t len) |
2835 | { | 2841 | { |
2836 | /* can only set chunk_size if array is not yet active */ | ||
2837 | char *e; | 2842 | char *e; |
2838 | unsigned long n = simple_strtoul(buf, &e, 10); | 2843 | unsigned long n = simple_strtoul(buf, &e, 10); |
2839 | 2844 | ||
2840 | if (!*buf || (*e && *e != '\n')) | 2845 | if (!*buf || (*e && *e != '\n')) |
2841 | return -EINVAL; | 2846 | return -EINVAL; |
2842 | 2847 | ||
2843 | if (mddev->pers) | 2848 | if (mddev->pers) { |
2844 | return -EBUSY; | 2849 | int err; |
2845 | 2850 | if (mddev->pers->reconfig == NULL) | |
2846 | mddev->new_chunk = n; | 2851 | return -EBUSY; |
2847 | if (mddev->reshape_position == MaxSector) | 2852 | err = mddev->pers->reconfig(mddev, -1, n); |
2848 | mddev->chunk_size = n; | 2853 | if (err) |
2854 | return err; | ||
2855 | } else { | ||
2856 | mddev->new_chunk = n; | ||
2857 | if (mddev->reshape_position == MaxSector) | ||
2858 | mddev->chunk_size = n; | ||
2859 | } | ||
2849 | return len; | 2860 | return len; |
2850 | } | 2861 | } |
2851 | static struct md_sysfs_entry md_chunk_size = | 2862 | static struct md_sysfs_entry md_chunk_size = |
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 611ea7bbf474..8a5e14e4a851 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
@@ -4913,6 +4913,47 @@ static void *raid5_takeover_raid1(mddev_t *mddev) | |||
4913 | } | 4913 | } |
4914 | 4914 | ||
4915 | 4915 | ||
4916 | static int raid5_reconfig(mddev_t *mddev, int new_layout, int new_chunk) | ||
4917 | { | ||
4918 | /* Currently the layout and chunk size can only be changed | ||
4919 | * for a 2-drive raid array, as in that case no data shuffling | ||
4920 | * is required. | ||
4921 | * Later we might validate these and set new_* so a reshape | ||
4922 | * can complete the change. | ||
4923 | */ | ||
4924 | raid5_conf_t *conf = mddev_to_conf(mddev); | ||
4925 | |||
4926 | if (new_layout >= 0 && !algorithm_valid_raid5(new_layout)) | ||
4927 | return -EINVAL; | ||
4928 | if (new_chunk > 0) { | ||
4929 | if (new_chunk & (new_chunk-1)) | ||
4930 | /* not a power of 2 */ | ||
4931 | return -EINVAL; | ||
4932 | if (new_chunk < PAGE_SIZE) | ||
4933 | return -EINVAL; | ||
4934 | if (mddev->array_sectors & ((new_chunk>>9)-1)) | ||
4935 | /* not factor of array size */ | ||
4936 | return -EINVAL; | ||
4937 | } | ||
4938 | |||
4939 | /* They look valid */ | ||
4940 | |||
4941 | if (mddev->raid_disks != 2) | ||
4942 | return -EINVAL; | ||
4943 | |||
4944 | if (new_layout >= 0) { | ||
4945 | conf->algorithm = new_layout; | ||
4946 | mddev->layout = mddev->new_layout = new_layout; | ||
4947 | } | ||
4948 | if (new_chunk > 0) { | ||
4949 | conf->chunk_size = new_chunk; | ||
4950 | mddev->chunk_size = mddev->new_chunk = new_chunk; | ||
4951 | } | ||
4952 | set_bit(MD_CHANGE_DEVS, &mddev->flags); | ||
4953 | md_wakeup_thread(mddev->thread); | ||
4954 | return 0; | ||
4955 | } | ||
4956 | |||
4916 | static void *raid5_takeover(mddev_t *mddev) | 4957 | static void *raid5_takeover(mddev_t *mddev) |
4917 | { | 4958 | { |
4918 | /* raid5 can take over: | 4959 | /* raid5 can take over: |
@@ -5023,6 +5064,7 @@ static struct mdk_personality raid5_personality = | |||
5023 | #endif | 5064 | #endif |
5024 | .quiesce = raid5_quiesce, | 5065 | .quiesce = raid5_quiesce, |
5025 | .takeover = raid5_takeover, | 5066 | .takeover = raid5_takeover, |
5067 | .reconfig = raid5_reconfig, | ||
5026 | }; | 5068 | }; |
5027 | 5069 | ||
5028 | static struct mdk_personality raid4_personality = | 5070 | static struct mdk_personality raid4_personality = |