aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/raid10.c67
1 files changed, 49 insertions, 18 deletions
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 1c90005ab343..f102e88fc785 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -3253,26 +3253,64 @@ static void calc_sectors(struct r10conf *conf, sector_t size)
3253 } 3253 }
3254} 3254}
3255 3255
3256enum geo_type {geo_new, geo_old, geo_start};
3257static int setup_geo(struct geom *geo, struct mddev *mddev, enum geo_type new)
3258{
3259 int nc, fc, fo;
3260 int layout, chunk, disks;
3261 switch (new) {
3262 case geo_old:
3263 layout = mddev->layout;
3264 chunk = mddev->chunk_sectors;
3265 disks = mddev->raid_disks - mddev->delta_disks;
3266 break;
3267 case geo_new:
3268 layout = mddev->new_layout;
3269 chunk = mddev->new_chunk_sectors;
3270 disks = mddev->raid_disks;
3271 break;
3272 default: /* avoid 'may be unused' warnings */
3273 case geo_start: /* new when starting reshape - raid_disks not
3274 * updated yet. */
3275 layout = mddev->new_layout;
3276 chunk = mddev->new_chunk_sectors;
3277 disks = mddev->raid_disks + mddev->delta_disks;
3278 break;
3279 }
3280 if (layout >> 17)
3281 return -1;
3282 if (chunk < (PAGE_SIZE >> 9) ||
3283 !is_power_of_2(chunk))
3284 return -2;
3285 nc = layout & 255;
3286 fc = (layout >> 8) & 255;
3287 fo = layout & (1<<16);
3288 geo->raid_disks = disks;
3289 geo->near_copies = nc;
3290 geo->far_copies = fc;
3291 geo->far_offset = fo;
3292 geo->chunk_mask = chunk - 1;
3293 geo->chunk_shift = ffz(~chunk);
3294 return nc*fc;
3295}
3296
3256static struct r10conf *setup_conf(struct mddev *mddev) 3297static struct r10conf *setup_conf(struct mddev *mddev)
3257{ 3298{
3258 struct r10conf *conf = NULL; 3299 struct r10conf *conf = NULL;
3259 int nc, fc, fo;
3260 int err = -EINVAL; 3300 int err = -EINVAL;
3301 struct geom geo;
3302 int copies;
3303
3304 copies = setup_geo(&geo, mddev, geo_new);
3261 3305
3262 if (mddev->new_chunk_sectors < (PAGE_SIZE >> 9) || 3306 if (copies == -2) {
3263 !is_power_of_2(mddev->new_chunk_sectors)) {
3264 printk(KERN_ERR "md/raid10:%s: chunk size must be " 3307 printk(KERN_ERR "md/raid10:%s: chunk size must be "
3265 "at least PAGE_SIZE(%ld) and be a power of 2.\n", 3308 "at least PAGE_SIZE(%ld) and be a power of 2.\n",
3266 mdname(mddev), PAGE_SIZE); 3309 mdname(mddev), PAGE_SIZE);
3267 goto out; 3310 goto out;
3268 } 3311 }
3269 3312
3270 nc = mddev->new_layout & 255; 3313 if (copies < 2 || copies > mddev->raid_disks) {
3271 fc = (mddev->new_layout >> 8) & 255;
3272 fo = mddev->new_layout & (1<<16);
3273
3274 if ((nc*fc) <2 || (nc*fc) > mddev->raid_disks ||
3275 (mddev->new_layout >> 17)) {
3276 printk(KERN_ERR "md/raid10:%s: unsupported raid10 layout: 0x%8x\n", 3314 printk(KERN_ERR "md/raid10:%s: unsupported raid10 layout: 0x%8x\n",
3277 mdname(mddev), mddev->new_layout); 3315 mdname(mddev), mddev->new_layout);
3278 goto out; 3316 goto out;
@@ -3292,15 +3330,8 @@ static struct r10conf *setup_conf(struct mddev *mddev)
3292 if (!conf->tmppage) 3330 if (!conf->tmppage)
3293 goto out; 3331 goto out;
3294 3332
3295 3333 conf->geo = geo;
3296 conf->geo.raid_disks = mddev->raid_disks; 3334 conf->copies = copies;
3297 conf->geo.near_copies = nc;
3298 conf->geo.far_copies = fc;
3299 conf->copies = nc*fc;
3300 conf->geo.far_offset = fo;
3301 conf->geo.chunk_mask = mddev->new_chunk_sectors - 1;
3302 conf->geo.chunk_shift = ffz(~mddev->new_chunk_sectors);
3303
3304 conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc, 3335 conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc,
3305 r10bio_pool_free, conf); 3336 r10bio_pool_free, conf);
3306 if (!conf->r10bio_pool) 3337 if (!conf->r10bio_pool)