Improve determination of when a backup is needed.

The current code is right.
Instead compute where we might eventually need to back up to, and
then compare that to how far we have progressed.

Also move suspend_point up towards where we might need to backup to,
rather than just as far as max_progress - as max_progress can never
exceed where we are currently suspended to.

Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
NeilBrown 2011-01-11 15:20:40 +11:00
parent 2f3dd5e4bc
commit d0ab945ee1
1 changed files with 34 additions and 18 deletions

52
Grow.c
View File

@ -2277,11 +2277,14 @@ int progress_reshape(struct mdinfo *info, struct reshape *reshape,
int advancing = (reshape->after.data_disks int advancing = (reshape->after.data_disks
>= reshape->before.data_disks); >= reshape->before.data_disks);
int need_backup = (reshape->after.data_disks unsigned long long need_backup; /* need to eventually backup all the way
== reshape->before.data_disks); * to here
*/
unsigned long long read_offset, write_offset; unsigned long long read_offset, write_offset;
unsigned long long write_range; unsigned long long write_range;
unsigned long long max_progress, target, completed; unsigned long long max_progress, target, completed;
unsigned long long array_size = (info->component_size
* reshape->before.data_disks);
int fd; int fd;
/* First, we unsuspend any region that is now known to be safe. /* First, we unsuspend any region that is now known to be safe.
@ -2317,20 +2320,24 @@ int progress_reshape(struct mdinfo *info, struct reshape *reshape,
write_offset = info->reshape_progress / reshape->after.data_disks; write_offset = info->reshape_progress / reshape->after.data_disks;
write_range = info->new_chunk/512; write_range = info->new_chunk/512;
if (advancing) { if (advancing) {
need_backup = 0;
if (read_offset < write_offset + write_range) { if (read_offset < write_offset + write_range) {
max_progress = backup_point; max_progress = backup_point;
if (max_progress <= info->reshape_progress) if (reshape->before.data_disks == reshape->after.data_disks)
need_backup = 1; need_backup = array_size;
else
need_backup = reshape->backup_blocks;
} else { } else {
max_progress = max_progress =
read_offset * read_offset *
reshape->after.data_disks; reshape->after.data_disks;
} }
} else { } else {
need_backup = array_size;
if (read_offset > write_offset - write_range) { if (read_offset > write_offset - write_range) {
max_progress = backup_point; max_progress = backup_point;
if (max_progress >= info->reshape_progress) if (max_progress >= info->reshape_progress)
need_backup = 1; need_backup = 0;
} else { } else {
max_progress = max_progress =
read_offset * read_offset *
@ -2365,24 +2372,32 @@ int progress_reshape(struct mdinfo *info, struct reshape *reshape,
* a backup. * a backup.
*/ */
if (advancing) { if (advancing) {
if ((need_backup || info->array.major_version < 0) && if ((need_backup > info->reshape_progress
|| info->array.major_version < 0) &&
*suspend_point < info->reshape_progress + target) { *suspend_point < info->reshape_progress + target) {
if (max_progress < *suspend_point + 2 * target) if (need_backup < *suspend_point + 2 * target)
*suspend_point = max_progress; *suspend_point = need_backup;
else else if (*suspend_point + 2 * target < array_size)
*suspend_point += 2 * target; *suspend_point += 2 * target;
else
*suspend_point = array_size;
sysfs_set_num(info, NULL, "suspend_hi", *suspend_point); sysfs_set_num(info, NULL, "suspend_hi", *suspend_point);
max_progress = *suspend_point; if (max_progress > *suspend_point)
max_progress = *suspend_point;
} }
} else { } else {
if ((need_backup || info->array.major_version < 0) && if ((need_backup < info->reshape_progress
|| info->array.major_version < 0) &&
*suspend_point > info->reshape_progress - target) { *suspend_point > info->reshape_progress - target) {
if (max_progress > *suspend_point - 2 * target) if (need_backup > *suspend_point - 2 * target)
*suspend_point = max_progress; *suspend_point = need_backup;
else else if (*suspend_point >= 2 * target)
*suspend_point -= 2 * target; *suspend_point -= 2 * target;
else
*suspend_point = 0;
sysfs_set_num(info, NULL, "suspend_lo", *suspend_point); sysfs_set_num(info, NULL, "suspend_lo", *suspend_point);
max_progress = *suspend_point; if (max_progress < *suspend_point)
max_progress = *suspend_point;
} }
} }
@ -2448,10 +2463,11 @@ int progress_reshape(struct mdinfo *info, struct reshape *reshape,
close(fd); close(fd);
/* We return the need_backup flag. Caller will decide /* We return the need_backup flag. Caller will decide
* how much (a multiple of ->backup_blocks) and will adjust * how much - a multiple of ->backup_blocks up to *suspend_point
* suspend_{lo,hi} and suspend_point.
*/ */
return need_backup; return advancing
? (need_backup > info->reshape_progress)
: (need_backup < info->reshape_progress);
} }