if (fd < 0)
return;
- while (sysfs_fd_get_str(fd, action, 20) > 0 &&
- strncmp(action, "reshape", 7) == 0) {
- fd_set rfds;
- FD_ZERO(&rfds);
- FD_SET(fd, &rfds);
- select(fd+1, NULL, NULL, &rfds, NULL);
- }
+ while (sysfs_fd_get_str(fd, action, 20) > 0 &&
+ strncmp(action, "reshape", 7) == 0)
+ sysfs_wait(fd, NULL);
close(fd);
}
return 1;
}
-unsigned long GCD(unsigned long a, unsigned long b)
-{
- while (a != b) {
- if (a < b)
- b -= a;
- if (b < a)
- a -= b;
- }
- return a;
-}
-
unsigned long compute_backup_blocks(int nchunk, int ochunk,
unsigned int ndata, unsigned int odata)
{
return blocks;
}
-char *analyse_change(struct mdinfo *info, struct reshape *re)
+char *analyse_change(char *devname, struct mdinfo *info, struct reshape *re)
{
/* Based on the current array state in info->array and
* the changes in info->new_* etc, determine:
/* chunk size is meaningful, must divide component_size
* evenly
*/
- if (info->component_size % (info->new_chunk/512))
- return "New chunk size does not"
- " divide component size";
+ if (info->component_size % (info->new_chunk/512)) {
+ unsigned long long shrink = info->component_size;
+ shrink &= ~(unsigned long long)(info->new_chunk/512-1);
+ pr_err("New chunk size (%dK) does not evenly divide device size (%lluk)\n",
+ info->new_chunk/1024, info->component_size/2);
+ pr_err("After shrinking any filesystem, \"mdadm --grow %s --size %llu\"\n",
+ devname, shrink/2);
+ pr_err("will shrink the array so the given chunk size would work.\n");
+ return "";
+ }
break;
default:
return "chunk size not meaningful for this level";
delta_parity = 1;
re->level = 5;
re->before.layout = ALGORITHM_PARITY_N;
+ if (info->new_layout == UnSet)
+ info->new_layout = map_name(r5layout, "default");
break;
case 6:
delta_parity = 2;
re->level = 6;
re->before.layout = ALGORITHM_PARITY_N;
+ if (info->new_layout == UnSet)
+ info->new_layout = map_name(r6layout, "default");
break;
default:
return "Impossible level change requested";
static int set_new_data_offset(struct mdinfo *sra, struct supertype *st,
char *devname, int delta_disks,
unsigned long long data_offset,
- unsigned long long min)
+ unsigned long long min,
+ int can_fallback)
{
struct mdinfo *sd;
int dir = 0;
} else if (delta_disks > 0) {
/* need space before */
if (before < min) {
+ if (can_fallback)
+ goto fallback;
pr_err("Insufficient head-space for reshape on %s\n",
dn);
goto release;
if (dir > 0) {
/* Increase data offset */
if (after < min) {
+ if (can_fallback)
+ goto fallback;
pr_err("Insufficient tail-space for reshape on %s\n",
dn);
goto release;
} else {
/* Decrease data offset */
if (before < min) {
+ if (can_fallback)
+ goto fallback;
pr_err("insufficient head-room on %s\n",
dn);
goto release;
return err;
release:
return -1;
+fallback:
+ /* Just use a backup file */
+ return 1;
}
static int raid10_reshape(char *container, int fd, char *devname,
}
}
err = set_new_data_offset(sra, st, devname, info->delta_disks, data_offset,
- min);
+ min, 0);
if (err == 1) {
pr_err("Cannot set new_data_offset: RAID10 reshape not\n");
cont_err("supported on this kernel\n");
info->new_level = UnSet;
if (info->delta_disks > 0)
info->array.raid_disks -= info->delta_disks;
- msg = analyse_change(info, &reshape);
+ msg = analyse_change(devname, info, &reshape);
info->new_level = new_level;
if (info->delta_disks > 0)
info->array.raid_disks += info->delta_disks;
/* Make sure the array isn't read-only */
ioctl(fd, RESTART_ARRAY_RW, 0);
} else
- msg = analyse_change(info, &reshape);
+ msg = analyse_change(devname, info, &reshape);
if (msg) {
- pr_err("%s\n", msg);
+ /* if msg == "", error has already been printed */
+ if (msg[0])
+ pr_err("%s\n", msg);
goto release;
}
if (restart &&
return 0;
if (restart & RESHAPE_NO_BACKUP)
return 0;
+
+ /* Need 'sra' down at 'started:' */
+ sra = sysfs_read(fd, NULL,
+ GET_COMPONENT|GET_DEVS|GET_OFFSET|GET_STATE|GET_CHUNK|
+ GET_CACHE);
+ if (!sra) {
+ pr_err("%s: Cannot get array details from sysfs\n",
+ devname);
+ goto release;
+ }
goto started;
}
/* The container is frozen but the array may not be.
switch(set_new_data_offset(sra, st, devname,
reshape.after.data_disks - reshape.before.data_disks,
data_offset,
- reshape.min_offset_change)) {
+ reshape.min_offset_change, 1)) {
case -1:
goto release;
case 0:
map_fork();
break;
}
+ close(fd);
wait_reshape(sra);
- impose_level(fd, info->new_level, devname, verbose);
-
+ fd = open_dev(sra->sys_name);
+ if (fd >= 0)
+ impose_level(fd, info->new_level, devname, verbose);
return 0;
case 1: /* Couldn't set data_offset, try the old way */
if (data_offset != INVALID_SECTORS) {
if (backup_file == NULL) {
if (reshape.after.data_disks <=
reshape.before.data_disks) {
- pr_err("%s: Cannot grow - "
- "need backup-file\n", devname);
+ pr_err("%s: Cannot grow - need backup-file\n",
+ devname);
+ pr_err(" Please provide one with \"--backup=...\"\n");
goto release;
} else if (sra->array.spare_disks == 0) {
pr_err("%s: Cannot grow - "
do {
struct mdstat_ent *mds, *m;
delayed = 0;
- mds = mdstat_read(0, 0);
+ mds = mdstat_read(1, 0);
for (m = mds; m; m = m->next)
if (strcmp(m->devnm, sra->sys_name) == 0) {
if (m->resync &&
delayed = 0;
}
if (delayed)
- sleep(30 - (delayed-1) * 25);
+ mdstat_wait(30 - (delayed-1) * 25);
} while (delayed);
-
+ mdstat_close();
close(fd);
if (check_env("MDADM_GROW_VERIFY"))
fd = open(devname, O_RDONLY | O_DIRECT);
flush_mdmon(container);
rv = reshape_array(container, fd, adev, st,
- content, force, NULL, 0ULL,
+ content, force, NULL, INVALID_SECTORS,
backup_file, verbose, 1, restart,
freeze_reshape);
close(fd);
unsigned long long backup_point,
unsigned long long wait_point,
unsigned long long *suspend_point,
- unsigned long long *reshape_completed)
+ unsigned long long *reshape_completed, int *frozen)
{
/* This function is called repeatedly by the reshape manager.
* It determines how much progress can safely be made and allows
wait_point = info->component_size - wait_point;
}
- sysfs_set_num(info, NULL, "sync_max", max_progress);
+ if (!*frozen)
+ sysfs_set_num(info, NULL, "sync_max", max_progress);
/* Now wait. If we have already reached the point that we were
* asked to wait to, don't wait at all, else wait for any change.
* waiting forever on a dead array
*/
char action[20];
- fd_set rfds;
if (sysfs_get_str(info, NULL, "sync_action",
action, 20) <= 0 ||
strncmp(action, "reshape", 7) != 0)
&& info->reshape_progress < (info->component_size
* reshape->after.data_disks))
break;
- FD_ZERO(&rfds);
- FD_SET(fd, &rfds);
- select(fd+1, NULL, NULL, &rfds, NULL);
+ sysfs_wait(fd, NULL);
if (sysfs_fd_get_ll(fd, &completed) < 0)
goto check_progress;
}
/* The abort might only be temporary. Wait up to 10
* seconds for fd to contain a valid number again.
*/
- struct timeval tv;
+ int wait = 10000;
int rv = -2;
- tv.tv_sec = 10;
- tv.tv_usec = 0;
- while (fd >= 0 && rv < 0 && tv.tv_sec > 0) {
- fd_set rfds;
- FD_ZERO(&rfds);
- FD_SET(fd, &rfds);
- if (select(fd+1, NULL, NULL, &rfds, &tv) != 1)
+ unsigned long long new_sync_max;
+ while (fd >= 0 && rv < 0 && wait > 0) {
+ if (sysfs_wait(fd, &wait) != 1)
break;
switch (sysfs_fd_get_ll(fd, &completed)) {
case 0:
/* all good again */
rv = 1;
+ /* If "sync_max" is no longer max_progress
+ * we need to freeze things
+ */
+ sysfs_get_ll(info, NULL, "sync_max", &new_sync_max);
+ *frozen = (new_sync_max != max_progress);
break;
case -2: /* read error - abort */
- tv.tv_sec = 0;
+ wait = 0;
break;
}
}
struct mdinfo *sd;
unsigned long stripes;
int uuid[4];
+ int frozen = 0;
/* set up the backup-super-block. This requires the
* uuid from the array.
wait_point = __le64_to_cpu(bsb.arraystart2);
}
+ reshape_completed = sra->reshape_progress;
rv = progress_reshape(sra, reshape,
backup_point, wait_point,
- &suspend_point, &reshape_completed);
+ &suspend_point, &reshape_completed,
+ &frozen);
/* external metadata would need to ping_monitor here */
sra->reshape_progress = reshape_completed;
freeze_reshape);
} else
ret_val = reshape_array(NULL, mdfd, "array", st, info, 1,
- NULL, 0ULL, backup_file, 0, 0,
+ NULL, INVALID_SECTORS,
+ backup_file, 0, 0,
1 | info->reshape_active,
freeze_reshape);