init_waitqueue_head(&mddev->sb_wait);
        init_waitqueue_head(&mddev->recovery_wait);
        mddev->reshape_position = MaxSector;
+       mddev->reshape_backwards = 0;
        mddev->resync_min = 0;
        mddev->resync_max = MaxSector;
        mddev->level = LEVEL_NONE;
                mddev->events = ev1;
                mddev->bitmap_info.offset = 0;
                mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
+               mddev->reshape_backwards = 0;
 
                if (mddev->minor_version >= 91) {
                        mddev->reshape_position = sb->reshape_position;
                        mddev->new_level = sb->new_level;
                        mddev->new_layout = sb->new_layout;
                        mddev->new_chunk_sectors = sb->new_chunk >> 9;
+                       if (mddev->delta_disks < 0)
+                               mddev->reshape_backwards = 1;
                } else {
                        mddev->reshape_position = MaxSector;
                        mddev->delta_disks = 0;
                mddev->events = ev1;
                mddev->bitmap_info.offset = 0;
                mddev->bitmap_info.default_offset = 1024 >> 9;
-               
+               mddev->reshape_backwards = 0;
+
                mddev->recovery_cp = le64_to_cpu(sb->resync_offset);
                memcpy(mddev->uuid, sb->set_uuid, 16);
 
                        mddev->new_level = le32_to_cpu(sb->new_level);
                        mddev->new_layout = le32_to_cpu(sb->new_layout);
                        mddev->new_chunk_sectors = le32_to_cpu(sb->new_chunk);
+                       if (mddev->delta_disks < 0 ||
+                           (mddev->delta_disks == 0 &&
+                            (le32_to_cpu(sb->feature_map)
+                             & MD_FEATURE_RESHAPE_BACKWARDS)))
+                               mddev->reshape_backwards = 1;
                } else {
                        mddev->reshape_position = MaxSector;
                        mddev->delta_disks = 0;
                sb->delta_disks = cpu_to_le32(mddev->delta_disks);
                sb->new_level = cpu_to_le32(mddev->new_level);
                sb->new_chunk = cpu_to_le32(mddev->new_chunk_sectors);
+               if (mddev->delta_disks == 0 &&
+                   mddev->reshape_backwards)
+                       sb->feature_map
+                               |= cpu_to_le32(MD_FEATURE_RESHAPE_BACKWARDS);
        }
 
        if (rdev->badblocks.count == 0)
                mddev->new_chunk_sectors = mddev->chunk_sectors;
                mddev->raid_disks -= mddev->delta_disks;
                mddev->delta_disks = 0;
+               mddev->reshape_backwards = 0;
                module_put(pers->owner);
                printk(KERN_WARNING "md: %s: %s would not accept array\n",
                       mdname(mddev), clevel);
        mddev->layout = mddev->new_layout;
        mddev->chunk_sectors = mddev->new_chunk_sectors;
        mddev->delta_disks = 0;
+       mddev->reshape_backwards = 0;
        mddev->degraded = 0;
        if (mddev->pers->sync_request == NULL) {
                /* this is now an array without redundancy, so
                int olddisks = mddev->raid_disks - mddev->delta_disks;
                mddev->delta_disks = n - olddisks;
                mddev->raid_disks = n;
+               mddev->reshape_backwards = (mddev->delta_disks < 0);
        } else
                mddev->raid_disks = n;
        return rv ? rv : len;
                return -EINVAL;
        mddev->reshape_position = new;
        mddev->delta_disks = 0;
+       mddev->reshape_backwards = 0;
        mddev->new_level = mddev->level;
        mddev->new_layout = mddev->layout;
        mddev->new_chunk_sectors = mddev->chunk_sectors;
 __ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show,
        reshape_position_store);
 
+static ssize_t
+reshape_direction_show(struct mddev *mddev, char *page)
+{
+       return sprintf(page, "%s\n",
+                      mddev->reshape_backwards ? "backwards" : "forwards");
+}
+
+static ssize_t
+reshape_direction_store(struct mddev *mddev, const char *buf, size_t len)
+{
+       int backwards = 0;
+       if (cmd_match(buf, "forwards"))
+               backwards = 0;
+       else if (cmd_match(buf, "backwards"))
+               backwards = 1;
+       else
+               return -EINVAL;
+       if (mddev->reshape_backwards == backwards)
+               return len;
+
+       /* check if we are allowed to change */
+       if (mddev->delta_disks)
+               return -EBUSY;
+
+       if (mddev->persistent &&
+           mddev->major_version == 0)
+               return -EINVAL;
+
+       mddev->reshape_backwards = backwards;
+       return len;
+}
+
+static struct md_sysfs_entry md_reshape_direction =
+__ATTR(reshape_direction, S_IRUGO|S_IWUSR, reshape_direction_show,
+       reshape_direction_store);
+
 static ssize_t
 array_size_show(struct mddev *mddev, char *page)
 {
        &md_safe_delay.attr,
        &md_array_state.attr,
        &md_reshape_position.attr,
+       &md_reshape_direction.attr,
        &md_array_size.attr,
        &max_corr_read_errors.attr,
        NULL,
        mddev->events = 0;
        mddev->can_decrease_events = 0;
        mddev->delta_disks = 0;
+       mddev->reshape_backwards = 0;
        mddev->new_level = LEVEL_NONE;
        mddev->new_layout = 0;
        mddev->new_chunk_sectors = 0;
        mddev->new_chunk_sectors = mddev->chunk_sectors;
        mddev->new_layout = mddev->layout;
        mddev->delta_disks = 0;
+       mddev->reshape_backwards = 0;
 
        return 0;
 }
        if (mddev->sync_thread || mddev->reshape_position != MaxSector)
                return -EBUSY;
        mddev->delta_disks = raid_disks - mddev->raid_disks;
+       if (mddev->delta_disks < 0)
+               mddev->reshape_backwards = 1;
+       else if (mddev->delta_disks > 0)
+               mddev->reshape_backwards = 0;
 
        rv = mddev->pers->check_reshape(mddev);
-       if (rv < 0)
+       if (rv < 0) {
                mddev->delta_disks = 0;
+               mddev->reshape_backwards = 0;
+       }
        return rv;
 }
 
 
                         * to check again.
                         */
                        spin_lock_irq(&conf->device_lock);
-                       if (mddev->delta_disks < 0
+                       if (mddev->reshape_backwards
                            ? logical_sector < conf->reshape_progress
                            : logical_sector >= conf->reshape_progress) {
                                disks = conf->previous_raid_disks;
                                previous = 1;
                        } else {
-                               if (mddev->delta_disks < 0
+                               if (mddev->reshape_backwards
                                    ? logical_sector < conf->reshape_safe
                                    : logical_sector >= conf->reshape_safe) {
                                        spin_unlock_irq(&conf->device_lock);
                                 */
                                int must_retry = 0;
                                spin_lock_irq(&conf->device_lock);
-                               if (mddev->delta_disks < 0
+                               if (mddev->reshape_backwards
                                    ? logical_sector >= conf->reshape_progress
                                    : logical_sector < conf->reshape_progress)
                                        /* mismatch, need to try again */
 
        if (sector_nr == 0) {
                /* If restarting in the middle, skip the initial sectors */
-               if (mddev->delta_disks < 0 &&
+               if (mddev->reshape_backwards &&
                    conf->reshape_progress < raid5_size(mddev, 0, 0)) {
                        sector_nr = raid5_size(mddev, 0, 0)
                                - conf->reshape_progress;
-               } else if (mddev->delta_disks >= 0 &&
+               } else if (!mddev->reshape_backwards &&
                           conf->reshape_progress > 0)
                        sector_nr = conf->reshape_progress;
                sector_div(sector_nr, new_data_disks);
        sector_div(readpos, data_disks);
        safepos = conf->reshape_safe;
        sector_div(safepos, data_disks);
-       if (mddev->delta_disks < 0) {
+       if (mddev->reshape_backwards) {
                writepos -= min_t(sector_t, reshape_sectors, writepos);
                readpos += reshape_sectors;
                safepos += reshape_sectors;
         * 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
+       if ((mddev->reshape_backwards
             ? (safepos > writepos && readpos < writepos)
             : (safepos < writepos && readpos > writepos)) ||
            time_after(jiffies, conf->reshape_checkpoint + 10*HZ)) {
                sysfs_notify(&mddev->kobj, NULL, "sync_completed");
        }
 
-       if (mddev->delta_disks < 0) {
+       if (mddev->reshape_backwards) {
                BUG_ON(conf->reshape_progress == 0);
                stripe_addr = writepos;
                BUG_ON((mddev->dev_sectors &
                list_add(&sh->lru, &stripes);
        }
        spin_lock_irq(&conf->device_lock);
-       if (mddev->delta_disks < 0)
+       if (mddev->reshape_backwards)
                conf->reshape_progress -= reshape_sectors * new_data_disks;
        else
                conf->reshape_progress += reshape_sectors * new_data_disks;
                                       mdname(mddev));
                                return -EINVAL;
                        }
-               } else if (mddev->delta_disks < 0
+               } else if (mddev->reshape_backwards
                    ? (here_new * mddev->new_chunk_sectors <=
                       here_old * mddev->chunk_sectors)
                    : (here_new * mddev->new_chunk_sectors >=
        conf->chunk_sectors = mddev->new_chunk_sectors;
        conf->prev_algo = conf->algorithm;
        conf->algorithm = mddev->new_layout;
-       if (mddev->delta_disks < 0)
+       if (mddev->reshape_backwards)
                conf->reshape_progress = raid5_size(mddev, 0, 0);
        else
                conf->reshape_progress = 0;
                mddev->chunk_sectors = conf->chunk_sectors;
                mddev->reshape_position = MaxSector;
                mddev->delta_disks = 0;
+               mddev->reshape_backwards = 0;
        }
 }