md/raid5: allow new reshape modes to be restarted in the middle.

md/raid5 doesn't allow a reshape to restart if it involves writing
over the same part of disk that it would be reading from.
This happens at the beginning of a reshape that increases the number
of devices, at the end of a reshape that decreases the number of
devices, and continuously for a reshape that does not change the
number of devices.

The current code is correct for the "increase number of devices"
case as the critical section at the start is handled by userspace
performing a backup.

It does not work for reducing the number of devices, or the
no-change case.
For 'reducing', we need to invert the test. For no-change we cannot
really be sure things will be safe, so simply require the array
to be read-only, which is how the user-space code which carefully
starts such arrays works.

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

NeilBrown 67ac6011 51d5668c

+20 -1
+20 -1
drivers/md/raid5.c
··· 4509 (old_disks-max_degraded)); 4510 /* here_old is the first stripe that we might need to read 4511 * from */ 4512 - if (here_new >= here_old) { 4513 /* Reading from the same stripe as writing to - bad */ 4514 printk(KERN_ERR "raid5: reshape_position too early for " 4515 "auto-recovery - aborting.\n");
··· 4509 (old_disks-max_degraded)); 4510 /* here_old is the first stripe that we might need to read 4511 * from */ 4512 + if (mddev->delta_disks == 0) { 4513 + /* We cannot be sure it is safe to start an in-place 4514 + * reshape. It is only safe if user-space if monitoring 4515 + * and taking constant backups. 4516 + * mdadm always starts a situation like this in 4517 + * readonly mode so it can take control before 4518 + * allowing any writes. So just check for that. 4519 + */ 4520 + if ((here_new * mddev->new_chunk_sectors != 4521 + here_old * mddev->chunk_sectors) || 4522 + mddev->ro == 0) { 4523 + printk(KERN_ERR "raid5: in-place reshape must be started" 4524 + " in read-only mode - aborting\n"); 4525 + return -EINVAL; 4526 + } 4527 + } else if (mddev->delta_disks < 0 4528 + ? (here_new * mddev->new_chunk_sectors <= 4529 + here_old * mddev->chunk_sectors) 4530 + : (here_new * mddev->new_chunk_sectors >= 4531 + here_old * mddev->chunk_sectors)) { 4532 /* Reading from the same stripe as writing to - bad */ 4533 printk(KERN_ERR "raid5: reshape_position too early for " 4534 "auto-recovery - aborting.\n");