summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJes Sorensen <Jes.Sorensen@redhat.com>2012-04-01 23:48:38 +1000
committerNeilBrown <neilb@suse.de>2012-04-03 15:37:26 +1000
commit24b961f811a3e790a9b93604d2594bfb6cce4fa4 (patch)
tree8cde643f6d3d142538d8e2499e65b368f5320bcc
parent18b9837ea0dc3cf844c6c4196871ce91d047bddb (diff)
downloadlinux-24b961f811a3e790a9b93604d2594bfb6cce4fa4.tar.bz2
md: Avoid OOPS when reshaping raid1 to raid0
raid1 arrays do not have the notion of chunk size. Calculate the largest chunk sector size we can use to avoid a divide by zero OOPS when aligning the size of the new array to the chunk size. Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com> Signed-off-by: NeilBrown <neilb@suse.de>
-rw-r--r--drivers/md/raid0.c18
1 files changed, 17 insertions, 1 deletions
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index c9809453a346..de63a1fc3737 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -632,6 +632,7 @@ static void *raid0_takeover_raid10(struct mddev *mddev)
static void *raid0_takeover_raid1(struct mddev *mddev)
{
struct r0conf *priv_conf;
+ int chunksect;
/* Check layout:
* - (N - 1) mirror drives must be already faulty
@@ -642,10 +643,25 @@ static void *raid0_takeover_raid1(struct mddev *mddev)
return ERR_PTR(-EINVAL);
}
+ /*
+ * a raid1 doesn't have the notion of chunk size, so
+ * figure out the largest suitable size we can use.
+ */
+ chunksect = 64 * 2; /* 64K by default */
+
+ /* The array must be an exact multiple of chunksize */
+ while (chunksect && (mddev->array_sectors & (chunksect - 1)))
+ chunksect >>= 1;
+
+ if ((chunksect << 9) < PAGE_SIZE)
+ /* array size does not allow a suitable chunk size */
+ return ERR_PTR(-EINVAL);
+
/* Set new parameters */
mddev->new_level = 0;
mddev->new_layout = 0;
- mddev->new_chunk_sectors = 128; /* by default set chunk size to 64k */
+ mddev->new_chunk_sectors = chunksect;
+ mddev->chunk_sectors = chunksect;
mddev->delta_disks = 1 - mddev->raid_disks;
mddev->raid_disks = 1;
/* make sure it will be not marked as dirty */