mtd: davinci nand: update clock naming
[safe/jmp/linux-2.6] / drivers / md / raid5.c
index 7638cc3..5d400ae 100644 (file)
@@ -395,7 +395,8 @@ get_active_stripe(raid5_conf_t *conf, sector_t sector,
                                init_stripe(sh, sector, previous);
                } else {
                        if (atomic_read(&sh->count)) {
-                         BUG_ON(!list_empty(&sh->lru));
+                               BUG_ON(!list_empty(&sh->lru)
+                                   && !test_bit(STRIPE_EXPANDING, &sh->state));
                        } else {
                                if (!test_bit(STRIPE_HANDLE, &sh->state))
                                        atomic_inc(&conf->active_stripes);
@@ -947,7 +948,6 @@ static int grow_stripes(raid5_conf_t *conf, int num)
        return 0;
 }
 
-#ifdef CONFIG_MD_RAID5_RESHAPE
 static int resize_stripes(raid5_conf_t *conf, int newsize)
 {
        /* Make all the stripes able to hold 'newsize' devices.
@@ -1072,7 +1072,6 @@ static int resize_stripes(raid5_conf_t *conf, int newsize)
        conf->pool_size = newsize;
        return err;
 }
-#endif
 
 static int drop_one_stripe(raid5_conf_t *conf)
 {
@@ -1273,6 +1272,8 @@ static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector,
        int pd_idx, qd_idx;
        int ddf_layout = 0;
        sector_t new_sector;
+       int algorithm = previous ? conf->prev_algo
+                                : conf->algorithm;
        int sectors_per_chunk = previous ? (conf->prev_chunk >> 9)
                                         : (conf->chunk_size >> 9);
        int raid_disks = previous ? conf->previous_raid_disks
@@ -1307,7 +1308,7 @@ static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector,
                pd_idx = data_disks;
                break;
        case 5:
-               switch (conf->algorithm) {
+               switch (algorithm) {
                case ALGORITHM_LEFT_ASYMMETRIC:
                        pd_idx = data_disks - stripe % raid_disks;
                        if (*dd_idx >= pd_idx)
@@ -1335,13 +1336,13 @@ static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector,
                        break;
                default:
                        printk(KERN_ERR "raid5: unsupported algorithm %d\n",
-                               conf->algorithm);
+                               algorithm);
                        BUG();
                }
                break;
        case 6:
 
-               switch (conf->algorithm) {
+               switch (algorithm) {
                case ALGORITHM_LEFT_ASYMMETRIC:
                        pd_idx = raid_disks - 1 - (stripe % raid_disks);
                        qd_idx = pd_idx + 1;
@@ -1454,7 +1455,7 @@ static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector,
 
                default:
                        printk(KERN_CRIT "raid6: unsupported algorithm %d\n",
-                              conf->algorithm);
+                              algorithm);
                        BUG();
                }
                break;
@@ -1481,6 +1482,8 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i, int previous)
        sector_t new_sector = sh->sector, check;
        int sectors_per_chunk = previous ? (conf->prev_chunk >> 9)
                                         : (conf->chunk_size >> 9);
+       int algorithm = previous ? conf->prev_algo
+                                : conf->algorithm;
        sector_t stripe;
        int chunk_offset;
        int chunk_number, dummy1, dd_idx = i;
@@ -1497,7 +1500,7 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i, int previous)
        switch(conf->level) {
        case 4: break;
        case 5:
-               switch (conf->algorithm) {
+               switch (algorithm) {
                case ALGORITHM_LEFT_ASYMMETRIC:
                case ALGORITHM_RIGHT_ASYMMETRIC:
                        if (i > sh->pd_idx)
@@ -1516,14 +1519,14 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i, int previous)
                        break;
                default:
                        printk(KERN_ERR "raid5: unsupported algorithm %d\n",
-                              conf->algorithm);
+                              algorithm);
                        BUG();
                }
                break;
        case 6:
                if (i == sh->qd_idx)
                        return 0; /* It is the Q disk */
-               switch (conf->algorithm) {
+               switch (algorithm) {
                case ALGORITHM_LEFT_ASYMMETRIC:
                case ALGORITHM_RIGHT_ASYMMETRIC:
                case ALGORITHM_ROTATING_ZERO_RESTART:
@@ -1571,7 +1574,7 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i, int previous)
                        break;
                default:
                        printk(KERN_CRIT "raid6: unsupported algorithm %d\n",
-                              conf->algorithm);
+                              algorithm);
                        BUG();
                }
                break;
@@ -2940,6 +2943,23 @@ static bool handle_stripe5(struct stripe_head *sh)
 
        /* Finish reconstruct operations initiated by the expansion process */
        if (sh->reconstruct_state == reconstruct_state_result) {
+               struct stripe_head *sh2
+                       = get_active_stripe(conf, sh->sector, 1, 1);
+               if (sh2 && test_bit(STRIPE_EXPAND_SOURCE, &sh2->state)) {
+                       /* sh cannot be written until sh2 has been read.
+                        * so arrange for sh to be delayed a little
+                        */
+                       set_bit(STRIPE_DELAYED, &sh->state);
+                       set_bit(STRIPE_HANDLE, &sh->state);
+                       if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE,
+                                             &sh2->state))
+                               atomic_inc(&conf->preread_active_stripes);
+                       release_stripe(sh2);
+                       goto unlock;
+               }
+               if (sh2)
+                       release_stripe(sh2);
+
                sh->reconstruct_state = reconstruct_state_idle;
                clear_bit(STRIPE_EXPANDING, &sh->state);
                for (i = conf->raid_disks; i--; ) {
@@ -3168,6 +3188,23 @@ static bool handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
                }
 
        if (s.expanded && test_bit(STRIPE_EXPANDING, &sh->state)) {
+               struct stripe_head *sh2
+                       = get_active_stripe(conf, sh->sector, 1, 1);
+               if (sh2 && test_bit(STRIPE_EXPAND_SOURCE, &sh2->state)) {
+                       /* sh cannot be written until sh2 has been read.
+                        * so arrange for sh to be delayed a little
+                        */
+                       set_bit(STRIPE_DELAYED, &sh->state);
+                       set_bit(STRIPE_HANDLE, &sh->state);
+                       if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE,
+                                             &sh2->state))
+                               atomic_inc(&conf->preread_active_stripes);
+                       release_stripe(sh2);
+                       goto unlock;
+               }
+               if (sh2)
+                       release_stripe(sh2);
+
                /* Need to write out all blocks after computing P&Q */
                sh->disks = conf->raid_disks;
                stripe_set_idx(sh->sector, conf, 0, sh);
@@ -3600,10 +3637,9 @@ static int make_request(struct request_queue *q, struct bio * bi)
 
        retry:
                previous = 0;
+               disks = conf->raid_disks;
                prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
-               if (likely(conf->reshape_progress == MaxSector))
-                       disks = conf->raid_disks;
-               else {
+               if (unlikely(conf->reshape_progress != MaxSector)) {
                        /* spinlock is needed as reshape_progress may be
                         * 64bit on a 32bit platform, and so it might be
                         * possible to see a half-updated value
@@ -3613,7 +3649,6 @@ static int make_request(struct request_queue *q, struct bio * bi)
                         * to check again.
                         */
                        spin_lock_irq(&conf->device_lock);
-                       disks = conf->raid_disks;
                        if (mddev->delta_disks < 0
                            ? logical_sector < conf->reshape_progress
                            : logical_sector >= conf->reshape_progress) {
@@ -3642,7 +3677,7 @@ static int make_request(struct request_queue *q, struct bio * bi)
                sh = get_active_stripe(conf, new_sector, previous,
                                       (bi->bi_rw&RWA_MASK));
                if (sh) {
-                       if (unlikely(conf->reshape_progress != MaxSector)) {
+                       if (unlikely(previous)) {
                                /* expansion might have moved on while waiting for a
                                 * stripe, so we must do the range check again.
                                 * Expansion could still move past after this
@@ -3653,10 +3688,9 @@ static int make_request(struct request_queue *q, struct bio * bi)
                                 */
                                int must_retry = 0;
                                spin_lock_irq(&conf->device_lock);
-                               if ((mddev->delta_disks < 0
-                                    ? logical_sector >= conf->reshape_progress
-                                    : logical_sector < conf->reshape_progress)
-                                   && previous)
+                               if (mddev->delta_disks < 0
+                                   ? logical_sector >= conf->reshape_progress
+                                   : logical_sector < conf->reshape_progress)
                                        /* mismatch, need to try again */
                                        must_retry = 1;
                                spin_unlock_irq(&conf->device_lock);
@@ -3732,8 +3766,10 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
        int new_data_disks = conf->raid_disks - conf->max_degraded;
        int i;
        int dd_idx;
-       sector_t writepos, safepos, gap;
+       sector_t writepos, readpos, safepos;
        sector_t stripe_addr;
+       int reshape_sectors;
+       struct list_head stripes;
 
        if (sector_nr == 0) {
                /* If restarting in the middle, skip the initial sectors */
@@ -3751,6 +3787,15 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
                }
        }
 
+       /* We need to process a full chunk at a time.
+        * If old and new chunk sizes differ, we need to process the
+        * largest of these
+        */
+       if (mddev->new_chunk > mddev->chunk_size)
+               reshape_sectors = mddev->new_chunk / 512;
+       else
+               reshape_sectors = mddev->chunk_size / 512;
+
        /* we update the metadata when there is more than 3Meg
         * in the block range (that is rather arbitrary, should
         * probably be time based) or when the data about to be
@@ -3761,26 +3806,47 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
         */
        writepos = conf->reshape_progress;
        sector_div(writepos, new_data_disks);
+       readpos = conf->reshape_progress;
+       sector_div(readpos, data_disks);
        safepos = conf->reshape_safe;
        sector_div(safepos, data_disks);
        if (mddev->delta_disks < 0) {
-               writepos -= conf->chunk_size/512;
-               safepos += conf->chunk_size/512;
-               gap = conf->reshape_safe - conf->reshape_progress;
+               writepos -= min_t(sector_t, reshape_sectors, writepos);
+               readpos += reshape_sectors;
+               safepos += reshape_sectors;
        } else {
-               writepos += conf->chunk_size/512;
-               safepos -= conf->chunk_size/512;
-               gap = conf->reshape_progress - conf->reshape_safe;
+               writepos += reshape_sectors;
+               readpos -= min_t(sector_t, reshape_sectors, readpos);
+               safepos -= min_t(sector_t, reshape_sectors, safepos);
        }
 
+       /* 'writepos' is the most advanced device address we might write.
+        * 'readpos' is the least advanced device address we might read.
+        * 'safepos' is the least address recorded in the metadata as having
+        *     been reshaped.
+        * If 'readpos' is behind 'writepos', then there is no way that we can
+        * ensure safety in the face of a crash - that must be done by userspace
+        * making a backup of the data.  So in that case there is no particular
+        * rush to update metadata.
+        * Otherwise if 'safepos' is behind 'writepos', then we really need to
+        * update the metadata to advance 'safepos' to match 'readpos' so that
+        * we can be safe in the event of a crash.
+        * So we insist on updating metadata if safepos is behind writepos and
+        * readpos is beyond writepos.
+        * In any case, update the metadata every 10 seconds.
+        * Maybe that number should be configurable, but I'm not sure it is
+        * worth it.... maybe it could be a multiple of safemode_delay???
+        */
        if ((mddev->delta_disks < 0
-            ? writepos < safepos
-            : writepos > safepos) ||
-           gap > (new_data_disks)*3000*2 /*3Meg*/) {
+            ? (safepos > writepos && readpos < writepos)
+            : (safepos < writepos && readpos > writepos)) ||
+           time_after(jiffies, conf->reshape_checkpoint + 10*HZ)) {
                /* Cannot proceed until we've updated the superblock... */
                wait_event(conf->wait_for_overlap,
                           atomic_read(&conf->reshape_stripes)==0);
                mddev->reshape_position = conf->reshape_progress;
+               mddev->curr_resync_completed = mddev->curr_resync;
+               conf->reshape_checkpoint = jiffies;
                set_bit(MD_CHANGE_DEVS, &mddev->flags);
                md_wakeup_thread(mddev->thread);
                wait_event(mddev->sb_wait, mddev->flags == 0 ||
@@ -3789,20 +3855,22 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
                conf->reshape_safe = mddev->reshape_position;
                spin_unlock_irq(&conf->device_lock);
                wake_up(&conf->wait_for_overlap);
+               sysfs_notify(&mddev->kobj, NULL, "sync_completed");
        }
 
        if (mddev->delta_disks < 0) {
                BUG_ON(conf->reshape_progress == 0);
                stripe_addr = writepos;
                BUG_ON((mddev->dev_sectors &
-                       ~((sector_t)conf->chunk_size / 512 - 1))
-                      - (conf->chunk_size / 512) - stripe_addr
+                       ~((sector_t)reshape_sectors - 1))
+                      - reshape_sectors - stripe_addr
                       != sector_nr);
        } else {
-               BUG_ON(writepos != sector_nr + conf->chunk_size / 512);
+               BUG_ON(writepos != sector_nr + reshape_sectors);
                stripe_addr = sector_nr;
        }
-       for (i=0; i < conf->chunk_size/512; i+= STRIPE_SECTORS) {
+       INIT_LIST_HEAD(&stripes);
+       for (i = 0; i < reshape_sectors; i += STRIPE_SECTORS) {
                int j;
                int skipped = 0;
                sh = get_active_stripe(conf, stripe_addr+i, 0, 0);
@@ -3831,13 +3899,13 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
                        set_bit(STRIPE_EXPAND_READY, &sh->state);
                        set_bit(STRIPE_HANDLE, &sh->state);
                }
-               release_stripe(sh);
+               list_add(&sh->lru, &stripes);
        }
        spin_lock_irq(&conf->device_lock);
        if (mddev->delta_disks < 0)
-               conf->reshape_progress -= i * new_data_disks;
+               conf->reshape_progress -= reshape_sectors * new_data_disks;
        else
-               conf->reshape_progress += i * new_data_disks;
+               conf->reshape_progress += reshape_sectors * new_data_disks;
        spin_unlock_irq(&conf->device_lock);
        /* Ok, those stripe are ready. We can start scheduling
         * reads on the source stripes.
@@ -3860,15 +3928,26 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
                release_stripe(sh);
                first_sector += STRIPE_SECTORS;
        }
+       /* Now that the sources are clearly marked, we can release
+        * the destination stripes
+        */
+       while (!list_empty(&stripes)) {
+               sh = list_entry(stripes.next, struct stripe_head, lru);
+               list_del_init(&sh->lru);
+               release_stripe(sh);
+       }
        /* If this takes us to the resync_max point where we have to pause,
         * then we need to write out the superblock.
         */
-       sector_nr += conf->chunk_size>>9;
-       if (sector_nr >= mddev->resync_max) {
+       sector_nr += reshape_sectors;
+       if ((sector_nr - mddev->curr_resync_completed) * 2
+           >= mddev->resync_max - mddev->curr_resync_completed) {
                /* Cannot proceed until we've updated the superblock... */
                wait_event(conf->wait_for_overlap,
                           atomic_read(&conf->reshape_stripes) == 0);
                mddev->reshape_position = conf->reshape_progress;
+               mddev->curr_resync_completed = mddev->curr_resync;
+               conf->reshape_checkpoint = jiffies;
                set_bit(MD_CHANGE_DEVS, &mddev->flags);
                md_wakeup_thread(mddev->thread);
                wait_event(mddev->sb_wait,
@@ -3878,8 +3957,9 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
                conf->reshape_safe = mddev->reshape_position;
                spin_unlock_irq(&conf->device_lock);
                wake_up(&conf->wait_for_overlap);
+               sysfs_notify(&mddev->kobj, NULL, "sync_completed");
        }
-       return conf->chunk_size>>9;
+       return reshape_sectors;
 }
 
 /* FIXME go_faster isn't used */
@@ -4330,8 +4410,10 @@ static raid5_conf_t *setup_conf(mddev_t *mddev)
        conf->algorithm = mddev->new_layout;
        conf->max_nr_stripes = NR_STRIPES;
        conf->reshape_progress = mddev->reshape_position;
-       if (conf->reshape_progress != MaxSector)
+       if (conf->reshape_progress != MaxSector) {
                conf->prev_chunk = mddev->chunk_size;
+               conf->prev_algo = mddev->layout;
+       }
 
        memory = conf->max_nr_stripes * (sizeof(struct stripe_head) +
                 conf->raid_disks * ((sizeof(struct bio) + PAGE_SIZE))) / 1024;
@@ -4381,9 +4463,7 @@ static int run(mddev_t *mddev)
                int old_disks;
                int max_degraded = (mddev->level == 6 ? 2 : 1);
 
-               if (mddev->new_level != mddev->level ||
-                   mddev->new_layout != mddev->layout ||
-                   mddev->new_chunk != mddev->chunk_size) {
+               if (mddev->new_level != mddev->level) {
                        printk(KERN_ERR "raid5: %s: unsupported reshape "
                               "required - aborting.\n",
                               mdname(mddev));
@@ -4472,14 +4552,14 @@ static int run(mddev_t *mddev)
 
        if (mddev->degraded == 0)
                printk("raid5: raid level %d set %s active with %d out of %d"
-                       " devices, algorithm %d\n", conf->level, mdname(mddev), 
-                       mddev->raid_disks-mddev->degraded, mddev->raid_disks,
-                       conf->algorithm);
+                      " devices, algorithm %d\n", conf->level, mdname(mddev),
+                      mddev->raid_disks-mddev->degraded, mddev->raid_disks,
+                      mddev->new_layout);
        else
                printk(KERN_ALERT "raid5: raid level %d set %s active with %d"
                        " out of %d devices, algorithm %d\n", conf->level,
                        mdname(mddev), mddev->raid_disks - mddev->degraded,
-                       mddev->raid_disks, conf->algorithm);
+                       mddev->raid_disks, mddev->new_layout);
 
        print_raid5_conf(conf);
 
@@ -4763,13 +4843,14 @@ static int raid5_resize(mddev_t *mddev, sector_t sectors)
        return 0;
 }
 
-#ifdef CONFIG_MD_RAID5_RESHAPE
 static int raid5_check_reshape(mddev_t *mddev)
 {
        raid5_conf_t *conf = mddev_to_conf(mddev);
 
-       if (mddev->delta_disks == 0)
-               return 0; /* nothing to do */
+       if (mddev->delta_disks == 0 &&
+           mddev->new_layout == mddev->layout &&
+           mddev->new_chunk == mddev->chunk_size)
+               return -EINVAL; /* nothing to do */
        if (mddev->bitmap)
                /* Cannot grow a bitmap yet */
                return -EBUSY;
@@ -4844,6 +4925,10 @@ static int raid5_start_reshape(mddev_t *mddev)
        spin_lock_irq(&conf->device_lock);
        conf->previous_raid_disks = conf->raid_disks;
        conf->raid_disks += mddev->delta_disks;
+       conf->prev_chunk = conf->chunk_size;
+       conf->chunk_size = mddev->new_chunk;
+       conf->prev_algo = conf->algorithm;
+       conf->algorithm = mddev->new_layout;
        if (mddev->delta_disks < 0)
                conf->reshape_progress = raid5_size(mddev, 0, 0);
        else
@@ -4898,11 +4983,11 @@ static int raid5_start_reshape(mddev_t *mddev)
                spin_unlock_irq(&conf->device_lock);
                return -EAGAIN;
        }
+       conf->reshape_checkpoint = jiffies;
        md_wakeup_thread(mddev->sync_thread);
        md_new_event(mddev);
        return 0;
 }
-#endif
 
 /* This is called from the reshape thread and should make any
  * changes needed in 'conf'
@@ -4916,6 +5001,7 @@ static void end_reshape(raid5_conf_t *conf)
                conf->previous_raid_disks = conf->raid_disks;
                conf->reshape_progress = MaxSector;
                spin_unlock_irq(&conf->device_lock);
+               wake_up(&conf->wait_for_overlap);
 
                /* read-ahead size must cover two whole stripes, which is
                 * 2 * (datadisks) * chunksize where 'n' is the number of raid devices
@@ -4936,6 +5022,7 @@ static void end_reshape(raid5_conf_t *conf)
 static void raid5_finish_reshape(mddev_t *mddev)
 {
        struct block_device *bdev;
+       raid5_conf_t *conf = mddev_to_conf(mddev);
 
        if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
 
@@ -4954,7 +5041,6 @@ static void raid5_finish_reshape(mddev_t *mddev)
                        }
                } else {
                        int d;
-                       raid5_conf_t *conf = mddev_to_conf(mddev);
                        mddev->degraded = conf->raid_disks;
                        for (d = 0; d < conf->raid_disks ; d++)
                                if (conf->disks[d].rdev &&
@@ -4966,6 +5052,8 @@ static void raid5_finish_reshape(mddev_t *mddev)
                             d++)
                                raid5_remove_disk(mddev, d);
                }
+               mddev->layout = conf->algorithm;
+               mddev->chunk_size = conf->chunk_size;
                mddev->reshape_position = MaxSector;
                mddev->delta_disks = 0;
        }
@@ -5064,11 +5152,10 @@ static void *raid5_takeover_raid6(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.
+       /* For a 2-drive array, the layout and chunk size can be changed
+        * immediately as not restriping is needed.
+        * For larger arrays we record the new value - after validation
+        * to be used by a reshape pass.
         */
        raid5_conf_t *conf = mddev_to_conf(mddev);
 
@@ -5087,19 +5174,49 @@ static int raid5_reconfig(mddev_t *mddev, int new_layout, int new_chunk)
 
        /* They look valid */
 
-       if (mddev->raid_disks != 2)
-               return -EINVAL;
+       if (mddev->raid_disks == 2) {
 
-       if (new_layout >= 0) {
-               conf->algorithm = new_layout;
-               mddev->layout = mddev->new_layout = new_layout;
+               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);
+       } else {
+               if (new_layout >= 0)
+                       mddev->new_layout = new_layout;
+               if (new_chunk > 0)
+                       mddev->new_chunk = new_chunk;
        }
+       return 0;
+}
+
+static int raid6_reconfig(mddev_t *mddev, int new_layout, int new_chunk)
+{
+       if (new_layout >= 0 && !algorithm_valid_raid6(new_layout))
+               return -EINVAL;
        if (new_chunk > 0) {
-               conf->chunk_size = new_chunk;
-               mddev->chunk_size = mddev->new_chunk = new_chunk;
+               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;
        }
-       set_bit(MD_CHANGE_DEVS, &mddev->flags);
-       md_wakeup_thread(mddev->thread);
+
+       /* They look valid */
+
+       if (new_layout >= 0)
+               mddev->new_layout = new_layout;
+       if (new_chunk > 0)
+               mddev->new_chunk = new_chunk;
+
        return 0;
 }
 
@@ -5193,13 +5310,12 @@ static struct mdk_personality raid6_personality =
        .sync_request   = sync_request,
        .resize         = raid5_resize,
        .size           = raid5_size,
-#ifdef CONFIG_MD_RAID5_RESHAPE
        .check_reshape  = raid5_check_reshape,
        .start_reshape  = raid5_start_reshape,
        .finish_reshape = raid5_finish_reshape,
-#endif
        .quiesce        = raid5_quiesce,
        .takeover       = raid6_takeover,
+       .reconfig       = raid6_reconfig,
 };
 static struct mdk_personality raid5_personality =
 {
@@ -5217,11 +5333,9 @@ static struct mdk_personality raid5_personality =
        .sync_request   = sync_request,
        .resize         = raid5_resize,
        .size           = raid5_size,
-#ifdef CONFIG_MD_RAID5_RESHAPE
        .check_reshape  = raid5_check_reshape,
        .start_reshape  = raid5_start_reshape,
        .finish_reshape = raid5_finish_reshape,
-#endif
        .quiesce        = raid5_quiesce,
        .takeover       = raid5_takeover,
        .reconfig       = raid5_reconfig,
@@ -5243,11 +5357,9 @@ static struct mdk_personality raid4_personality =
        .sync_request   = sync_request,
        .resize         = raid5_resize,
        .size           = raid5_size,
-#ifdef CONFIG_MD_RAID5_RESHAPE
        .check_reshape  = raid5_check_reshape,
        .start_reshape  = raid5_start_reshape,
        .finish_reshape = raid5_finish_reshape,
-#endif
        .quiesce        = raid5_quiesce,
 };