diff --git a/drivers/md/md.c b/drivers/md/md.c index b9dfdfccdb78..1a637676a930 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2594,7 +2594,7 @@ static int do_md_run(mddev_t * mddev) strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel)); if (mddev->reshape_position != MaxSector && - pers->reshape == NULL) { + pers->start_reshape == NULL) { /* This personality cannot handle reshaping... */ mddev->pers = NULL; module_put(pers->owner); @@ -3556,14 +3556,16 @@ static int update_raid_disks(mddev_t *mddev, int raid_disks) { int rv; /* change the number of raid disks */ - if (mddev->pers->reshape == NULL) + if (mddev->pers->check_reshape == NULL) return -EINVAL; if (raid_disks <= 0 || raid_disks >= mddev->max_disks) return -EINVAL; - if (mddev->sync_thread) + if (mddev->sync_thread || mddev->reshape_position != MaxSector) return -EBUSY; - rv = mddev->pers->reshape(mddev, raid_disks); + mddev->delta_disks = raid_disks - mddev->raid_disks; + + rv = mddev->pers->check_reshape(mddev); return rv; } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index b65b8cfbdf30..04418e10d1dc 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1976,7 +1976,7 @@ static int raid1_resize(mddev_t *mddev, sector_t sectors) return 0; } -static int raid1_reshape(mddev_t *mddev, int raid_disks) +static int raid1_reshape(mddev_t *mddev) { /* We need to: * 1/ resize the r1bio_pool @@ -1993,10 +1993,22 @@ static int raid1_reshape(mddev_t *mddev, int raid_disks) struct pool_info *newpoolinfo; mirror_info_t *newmirrors; conf_t *conf = mddev_to_conf(mddev); - int cnt; + int cnt, raid_disks; int d, d2; + /* Cannot change chunk_size, layout, or level */ + if (mddev->chunk_size != mddev->new_chunk || + mddev->layout != mddev->new_layout || + mddev->level != mddev->new_level) { + mddev->new_chunk = mddev->chunk_size; + mddev->new_layout = mddev->layout; + mddev->new_level = mddev->level; + return -EINVAL; + } + + raid_disks = mddev->raid_disks + mddev->delta_disks; + if (raid_disks < conf->raid_disks) { cnt=0; for (d= 0; d < conf->raid_disks; d++) @@ -2043,6 +2055,7 @@ static int raid1_reshape(mddev_t *mddev, int raid_disks) mddev->degraded += (raid_disks - conf->raid_disks); conf->raid_disks = mddev->raid_disks = raid_disks; + mddev->delta_disks = 0; conf->last_used = 0; /* just make sure it is in-range */ lower_barrier(conf); @@ -2084,7 +2097,7 @@ static struct mdk_personality raid1_personality = .spare_active = raid1_spare_active, .sync_request = sync_request, .resize = raid1_resize, - .reshape = raid1_reshape, + .check_reshape = raid1_reshape, .quiesce = raid1_quiesce, }; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 089a32604305..355dafb98aac 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2590,21 +2590,15 @@ static int raid5_resize(mddev_t *mddev, sector_t sectors) } #ifdef CONFIG_MD_RAID5_RESHAPE -static int raid5_reshape(mddev_t *mddev, int raid_disks) +static int raid5_check_reshape(mddev_t *mddev) { raid5_conf_t *conf = mddev_to_conf(mddev); int err; - mdk_rdev_t *rdev; - struct list_head *rtmp; - int spares = 0; - int added_devices = 0; - if (mddev->degraded || - test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) - return -EBUSY; - if (conf->raid_disks > raid_disks) - return -EINVAL; /* Cannot shrink array yet */ - if (conf->raid_disks == raid_disks) + if (mddev->delta_disks < 0 || + mddev->new_level != mddev->level) + return -EINVAL; /* Cannot shrink array or change level yet */ + if (mddev->delta_disks == 0) return 0; /* nothing to do */ /* Can only proceed if there are plenty of stripe_heads. @@ -2615,30 +2609,48 @@ static int raid5_reshape(mddev_t *mddev, int raid_disks) * If the chunk size is greater, user-space should request more * stripe_heads first. */ - if ((mddev->chunk_size / STRIPE_SIZE) * 4 > conf->max_nr_stripes) { + if ((mddev->chunk_size / STRIPE_SIZE) * 4 > conf->max_nr_stripes || + (mddev->new_chunk / STRIPE_SIZE) * 4 > conf->max_nr_stripes) { printk(KERN_WARNING "raid5: reshape: not enough stripes. Needed %lu\n", (mddev->chunk_size / STRIPE_SIZE)*4); return -ENOSPC; } + err = resize_stripes(conf, conf->raid_disks + mddev->delta_disks); + if (err) + return err; + + /* looks like we might be able to manage this */ + return 0; +} + +static int raid5_start_reshape(mddev_t *mddev) +{ + raid5_conf_t *conf = mddev_to_conf(mddev); + mdk_rdev_t *rdev; + struct list_head *rtmp; + int spares = 0; + int added_devices = 0; + + if (mddev->degraded || + test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) + return -EBUSY; + ITERATE_RDEV(mddev, rdev, rtmp) if (rdev->raid_disk < 0 && !test_bit(Faulty, &rdev->flags)) spares++; - if (conf->raid_disks + spares < raid_disks-1) + + if (spares < mddev->delta_disks-1) /* Not enough devices even to make a degraded array * of that size */ return -EINVAL; - err = resize_stripes(conf, raid_disks); - if (err) - return err; - atomic_set(&conf->reshape_stripes, 0); spin_lock_irq(&conf->device_lock); conf->previous_raid_disks = conf->raid_disks; - conf->raid_disks = raid_disks; + conf->raid_disks += mddev->delta_disks; conf->expand_progress = 0; conf->expand_lo = 0; spin_unlock_irq(&conf->device_lock); @@ -2660,12 +2672,8 @@ static int raid5_reshape(mddev_t *mddev, int raid_disks) break; } - mddev->degraded = (raid_disks - conf->previous_raid_disks) - added_devices; - mddev->new_chunk = mddev->chunk_size; - mddev->new_layout = mddev->layout; - mddev->new_level = mddev->level; - mddev->raid_disks = raid_disks; - mddev->delta_disks = raid_disks - conf->previous_raid_disks; + mddev->degraded = (conf->raid_disks - conf->previous_raid_disks) - added_devices; + mddev->raid_disks = conf->raid_disks; mddev->reshape_position = 0; mddev->sb_dirty = 1; @@ -2679,7 +2687,6 @@ static int raid5_reshape(mddev_t *mddev, int raid_disks) mddev->recovery = 0; spin_lock_irq(&conf->device_lock); mddev->raid_disks = conf->raid_disks = conf->previous_raid_disks; - mddev->delta_disks = 0; conf->expand_progress = MaxSector; spin_unlock_irq(&conf->device_lock); return -EAGAIN; @@ -2752,7 +2759,8 @@ static struct mdk_personality raid5_personality = .sync_request = sync_request, .resize = raid5_resize, #ifdef CONFIG_MD_RAID5_RESHAPE - .reshape = raid5_reshape, + .check_reshape = raid5_check_reshape, + .start_reshape = raid5_start_reshape, #endif .quiesce = raid5_quiesce, }; diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 1a6f9f2f6282..002ee631fabb 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -261,7 +261,8 @@ struct mdk_personality int (*spare_active) (mddev_t *mddev); sector_t (*sync_request)(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster); int (*resize) (mddev_t *mddev, sector_t sectors); - int (*reshape) (mddev_t *mddev, int raid_disks); + int (*check_reshape) (mddev_t *mddev); + int (*start_reshape) (mddev_t *mddev); int (*reconfig) (mddev_t *mddev, int layout, int chunk_size); /* quiesce moves between quiescence states * 0 - fully active