]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
Fix management of backed-up region for hi-to-low reshapes.
authorNeilBrown <neilb@suse.de>
Thu, 20 Jan 2011 20:59:53 +0000 (07:59 +1100)
committerNeilBrown <neilb@suse.de>
Thu, 20 Jan 2011 20:59:53 +0000 (07:59 +1100)
When reshaping from the end of the array to the start, for times
when the number of data devices is decreasing, the handling of the
backup area isn't a simple mirror of the handling on low-to-hi
reshapes as the backup areas is always low in the array.

So re-write that to make it work.

Signed-off-by: NeilBrown <neilb@suse.de>
Grow.c

diff --git a/Grow.c b/Grow.c
index 23ef88ee67e1e3f26f998d1874898a979cb274b7..9d3e482fe0c7ae6dda3c1bac4d9476e5cc5753bf 100644 (file)
--- a/Grow.c
+++ b/Grow.c
@@ -2223,8 +2223,9 @@ int progress_reshape(struct mdinfo *info, struct reshape *reshape,
 
        int advancing = (reshape->after.data_disks
                         >= reshape->before.data_disks);
-       unsigned long long need_backup; /* need to eventually backup all the way
-                                        * to here
+       unsigned long long need_backup; /* All data between start of array and
+                                        * here will at some point need to
+                                        * be backed up.
                                         */
        unsigned long long read_offset, write_offset;
        unsigned long long write_range;
@@ -2266,37 +2267,38 @@ int progress_reshape(struct mdinfo *info, struct reshape *reshape,
        read_offset = info->reshape_progress / reshape->before.data_disks;
        write_offset = info->reshape_progress / reshape->after.data_disks;
        write_range = info->new_chunk/512;
+       if (reshape->before.data_disks == reshape->after.data_disks)
+               need_backup = array_size;
+       else
+               need_backup = reshape->backup_blocks;
        if (advancing) {
-               need_backup = 0;
-               if (read_offset < write_offset + write_range) {
+               if (read_offset < write_offset + write_range)
                        max_progress = backup_point;
-                       if (reshape->before.data_disks == reshape->after.data_disks)
-                               need_backup = array_size;
-                       else
-                               need_backup = reshape->backup_blocks;
-               } else {
+               else {
                        max_progress =
                                read_offset *
                                reshape->after.data_disks;
                }
        } else {
-               need_backup = array_size;
-               if (read_offset > write_offset - write_range) {
+               if (read_offset > write_offset - write_range)
+                       /* Can only progress as far as has been backed up,
+                        * which must be suspended */
                        max_progress = backup_point;
-                       if (max_progress >= info->reshape_progress)
-                               need_backup = 0;
-               } else {
-                       max_progress =
-                               read_offset *
-                               reshape->after.data_disks;
-                       /* If we are using internal metadata, then we can
-                        * progress all the way to the suspend_point without
-                        * worrying about backing-up/suspending along the
-                        * way.
-                        */
-                       if (max_progress < *suspend_point &&
-                               info->array.major_version >= 0)
-                               max_progress = *suspend_point;
+               else if (info->reshape_progress <= need_backup)
+                       max_progress = backup_point;
+               else {
+                       if (info->array.major_version >= 0)
+                               /* Can progress until backup is needed */
+                               max_progress = need_backup;
+                       else {
+                               /* Can progress until metadata update is required */
+                               max_progress =
+                                       read_offset *
+                                       reshape->after.data_disks;
+                               /* but data must be suspended */
+                               if (max_progress < *suspend_point)
+                                       max_progress = *suspend_point;
+                       }
                }
        }
 
@@ -2335,16 +2337,28 @@ int progress_reshape(struct mdinfo *info, struct reshape *reshape,
                                max_progress = *suspend_point;
                }
        } else {
-               if ((need_backup < info->reshape_progress
-                    || info->array.major_version < 0) &&
-                   *suspend_point > info->reshape_progress - target) {
-                       if (need_backup > *suspend_point - 2 * target)
-                               *suspend_point = need_backup;
-                       else if (*suspend_point >= 2 * target)
-                               *suspend_point -= 2 * target;
-                       else
+               if (info->array.major_version >= 0) {
+                       /* Only need to suspend when about to backup */
+                       if (info->reshape_progress < need_backup * 2 &&
+                           *suspend_point > 0) {
                                *suspend_point = 0;
-                       sysfs_set_num(info, NULL, "suspend_lo", *suspend_point);
+                               sysfs_set_num(info, NULL, "suspend_lo", 0);
+                               sysfs_set_num(info, NULL, "suspend_hi", need_backup);
+                       }
+               } else {
+                       /* Need to suspend continually */
+                       if (info->reshape_progress < *suspend_point)
+                               *suspend_point = info->reshape_progress;
+                       if (*suspend_point + target < info->reshape_progress)
+                               /* No need to move suspend region yet */;
+                       else {
+                               if (*suspend_point >= 2 * target)
+                                       *suspend_point -= 2 * target;
+                               else
+                                       *suspend_point = 0;
+                               sysfs_set_num(info, NULL, "suspend_lo",
+                                             *suspend_point);
+                       }
                        if (max_progress < *suspend_point)
                                max_progress = *suspend_point;
                }
@@ -2423,9 +2437,10 @@ int progress_reshape(struct mdinfo *info, struct reshape *reshape,
        /* We return the need_backup flag.  Caller will decide
         * how much - a multiple of ->backup_blocks up to *suspend_point
         */
-       return advancing
-               ? (need_backup > info->reshape_progress)
-               : (need_backup < info->reshape_progress);
+       if (advancing)
+               return need_backup > info->reshape_progress;
+       else
+               return need_backup >= info->reshape_progress;
 
 check_progress:
        /* if we couldn't read a number from sync_completed, then