/*
* mdadm - manage Linux "md" devices aka RAID arrays.
*
- * Copyright (C) 2001-2012 Neil Brown <neilb@suse.de>
+ * Copyright (C) 2001-2013 Neil Brown <neilb@suse.de>
*
*
* This program is free software; you can redistribute it and/or modify
#include "mdadm.h"
#include "dlink.h"
#include <sys/mman.h>
+#include <stddef.h>
#include <stdint.h>
+#include <signal.h>
+#include <sys/wait.h>
#if ! defined(__BIG_ENDIAN) && ! defined(__LITTLE_ENDIAN)
#error no endian defined
#include "md_u.h"
#include "md_p.h"
-#ifndef offsetof
-#define offsetof(t,f) ((size_t)&(((t*)0)->f))
-#endif
-
int restore_backup(struct supertype *st,
struct mdinfo *content,
int working_disks,
int next_spare,
- char *backup_file,
+ char **backup_filep,
int verbose)
{
int i;
struct mdinfo *dev;
int err;
int disk_count = next_spare + working_disks;
+ char *backup_file = *backup_filep;
dprintf("Called restore_backup()\n");
fdlist = xmalloc(sizeof(int) * disk_count);
fdlist[next_spare++] = fd;
}
+ if (!backup_file) {
+ backup_file = locate_backup(content->sys_name);
+ *backup_filep = backup_file;
+ }
+
if (st->ss->external && st->ss->recover_backup)
err = st->ss->recover_backup(st, content);
else
return unfreeze_container(st);
else {
struct mdinfo *sra = sysfs_read(-1, st->devnm, GET_VERSION);
+ char buf[20];
- if (sra)
+ if (sra &&
+ sysfs_get_str(sra, NULL, "sync_action", buf, 20) > 0
+ && strcmp(buf, "frozen\n") == 0) {
+ printf("unfreeze\n");
sysfs_set_str(sra, NULL, "sync_action", "idle");
+ }
sysfs_free(sra);
}
}
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);
}
sysfs_set_num(sra, NULL, "suspend_hi", 0);
sysfs_set_num(sra, NULL, "suspend_lo", 0);
sysfs_set_num(sra, NULL, "sync_min", 0);
- sysfs_set_str(sra, NULL, "sync_max", "max");
+ // It isn't safe to reset sync_max as we aren't monitoring.
+ // Array really should be stopped at this point.
}
int remove_disks_for_takeover(struct supertype *st,
long blocks,
int *fdlist,
unsigned long long *offsets,
+ char *sys_name,
int restart)
{
/* Return 1 on success, 0 on any form of failure */
return 0;
}
- return 1;
-}
-
-unsigned long GCD(unsigned long a, unsigned long b)
-{
- while (a != b) {
- if (a < b)
- b -= a;
- if (b < a)
- a -= b;
+ if (!restart && strncmp(backup_file, MAP_DIR, strlen(MAP_DIR)) != 0) {
+ char *bu = make_backup(sys_name);
+ if (symlink(backup_file, bu))
+ pr_err("Recording backup file in " MAP_DIR "failed: %s\n",
+ strerror(errno));
+ free(bu);
}
- return a;
+
+ return 1;
}
unsigned long compute_backup_blocks(int nchunk, int ochunk,
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";
switch (info->array.level) {
default:
- return "Cannot understand this RAID level";
+ return "No reshape is possibly for this RAID level";
+ case LEVEL_LINEAR:
+ if (info->delta_disks != UnSet)
+ return "Only --add is supported for LINEAR, setting --raid-disks is not needed";
+ else
+ return "Only --add is supported for LINEAR, other --grow options are not meaningful";
case 1:
/* RAID1 can convert to RAID1 with different disks, or
* raid5 with 2 disks, or
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";
switch (re->level) {
case 4:
- re->before.layout = 0;
re->after.layout = 0;
break;
case 5:
struct supertype *st,
struct mdinfo *info,
int force,
- char *backup_file,
- int verbose, int restart, int freeze_reshape);
+ char *backup_file, int verbose,
+ int forked, int restart, int freeze_reshape);
int Grow_reshape(char *devname, int fd,
struct mddev_dev *devlist,
if (s->size == MAX_SIZE)
s->size = 0;
array.size = s->size;
- if ((unsigned)array.size != s->size) {
+ if (s->size & ~INT32_MAX) {
/* got truncated to 32bit, write to
* component_size instead
*/
* performed at the level of the container
*/
rv = reshape_container(container, devname, -1, st, &info,
- c->force, c->backup_file, c->verbose, 0, 0);
+ c->force, c->backup_file, c->verbose, 0, 0, 0);
frozen = 0;
} else {
/* get spare devices from external metadata
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;
if (info2.space_before == 0 &&
info2.space_after == 0) {
/* Metadata doesn't support data_offset changes */
- return 1;
+ pr_err("%s: Metadata version doesn't support"
+ " data_offset changes\n", devname);
+ goto release;
}
if (before > info2.space_before)
before = info2.space_before;
} 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");
return -1;
}
+static int impose_level(int fd, int level, char *devname, int verbose)
+{
+ char *c;
+ struct mdu_array_info_s array;
+ struct mdinfo info;
+ sysfs_init(&info, fd, NULL);
+
+ ioctl(fd, GET_ARRAY_INFO, &array);
+ if (level == 0 &&
+ (array.level >= 4 && array.level <= 6)) {
+ /* To convert to RAID0 we need to fail and
+ * remove any non-data devices. */
+ int found = 0;
+ int d;
+ int data_disks = array.raid_disks - 1;
+ if (array.level == 6)
+ data_disks -= 1;
+ if (array.level == 5 &&
+ array.layout != ALGORITHM_PARITY_N)
+ return -1;
+ if (array.level == 6 &&
+ array.layout != ALGORITHM_PARITY_N_6)
+ return -1;
+ sysfs_set_str(&info, NULL,"sync_action", "idle");
+ /* First remove any spares so no recovery starts */
+ for (d = 0, found = 0;
+ d < MAX_DISKS && found < array.nr_disks;
+ d++) {
+ mdu_disk_info_t disk;
+ disk.number = d;
+ if (ioctl(fd, GET_DISK_INFO, &disk) < 0)
+ continue;
+ if (disk.major == 0 && disk.minor == 0)
+ continue;
+ found++;
+ if ((disk.state & (1 << MD_DISK_ACTIVE))
+ && disk.raid_disk < data_disks)
+ /* keep this */
+ continue;
+ ioctl(fd, HOT_REMOVE_DISK,
+ makedev(disk.major, disk.minor));
+ }
+ /* Now fail anything left */
+ ioctl(fd, GET_ARRAY_INFO, &array);
+ for (d = 0, found = 0;
+ d < MAX_DISKS && found < array.nr_disks;
+ d++) {
+ int cnt;
+ mdu_disk_info_t disk;
+ disk.number = d;
+ if (ioctl(fd, GET_DISK_INFO, &disk) < 0)
+ continue;
+ if (disk.major == 0 && disk.minor == 0)
+ continue;
+ found++;
+ if ((disk.state & (1 << MD_DISK_ACTIVE))
+ && disk.raid_disk < data_disks)
+ /* keep this */
+ continue;
+ ioctl(fd, SET_DISK_FAULTY,
+ makedev(disk.major, disk.minor));
+ cnt = 5;
+ while (ioctl(fd, HOT_REMOVE_DISK,
+ makedev(disk.major, disk.minor)) < 0
+ && errno == EBUSY
+ && cnt--) {
+ usleep(10000);
+ }
+ }
+ }
+ c = map_num(pers, level);
+ if (c) {
+ int err = sysfs_set_str(&info, NULL, "level", c);
+ if (err) {
+ err = errno;
+ pr_err("%s: could not set level to %s\n",
+ devname, c);
+ if (err == EBUSY &&
+ (array.state & (1<<MD_SB_BITMAP_PRESENT)))
+ cont_err("Bitmap must be removed"
+ " before level can be changed\n");
+ return err;
+ }
+ if (verbose >= 0)
+ pr_err("level of %s changed to %s\n",
+ devname, c);
+ }
+ return 0;
+}
+
+int sigterm = 0;
+static void catch_term(int sig)
+{
+ sigterm = 1;
+}
+
+static int continue_via_systemd(char *devnm)
+{
+ int skipped, i, pid, status;
+ char pathbuf[1024];
+ /* In a systemd/udev world, it is best to get systemd to
+ * run "mdadm --grow --continue" rather than running in the
+ * background.
+ */
+ switch(fork()) {
+ case 0:
+ /* FIXME yuk. CLOSE_EXEC?? */
+ skipped = 0;
+ for (i = 3; skipped < 20; i++)
+ if (close(i) < 0)
+ skipped++;
+ else
+ skipped = 0;
+
+ /* Don't want to see error messages from
+ * systemctl. If the service doesn't exist,
+ * we fork ourselves.
+ */
+ close(2);
+ open("/dev/null", O_WRONLY);
+ snprintf(pathbuf, sizeof(pathbuf), "mdadm-grow-continue@%s.service",
+ devnm);
+ status = execl("/usr/bin/systemctl", "systemctl",
+ "start",
+ pathbuf, NULL);
+ status = execl("/bin/systemctl", "systemctl", "start",
+ pathbuf, NULL);
+ exit(1);
+ case -1: /* Just do it ourselves. */
+ break;
+ default: /* parent - good */
+ pid = wait(&status);
+ if (pid >= 0 && status == 0)
+ return 1;
+ }
+ return 0;
+}
+
static int reshape_array(char *container, int fd, char *devname,
struct supertype *st, struct mdinfo *info,
int force, struct mddev_dev *devlist,
unsigned long long array_size;
int done;
struct mdinfo *sra = NULL;
+ char buf[20];
/* when reshaping a RAID0, the component_size might be zero.
* So try to fix that up.
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 &&
goto release;
}
- if (st->ss->external && restart && (info->reshape_progress == 0)) {
+ if (st->ss->external && restart && (info->reshape_progress == 0) &&
+ !((sysfs_get_str(info, NULL, "sync_action", buf, sizeof(buf)) > 0) &&
+ (strncmp(buf, "reshape", 7) == 0))) {
/* When reshape is restarted from '0', very begin of array
* it is possible that for external metadata reshape and array
* configuration doesn't happen.
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;
+ }
+
+ if (!backup_file)
+ backup_file = locate_backup(sra->sys_name);
+
goto started;
}
/* The container is frozen but the array may not be.
}
if (reshape.level != array.level) {
- char *c = map_num(pers, reshape.level);
- int err;
- if (c == NULL)
+ int err = impose_level(fd, reshape.level, devname, verbose);
+ if (err)
goto release;
-
- if (reshape.level == 0 &&
- (array.level >= 4 && array.level <= 6)) {
- /* To convert to RAID0 we need to fail and
- * remove any non-data devices. */
- int found = 0;
- if (array.level == 5 &&
- array.layout != ALGORITHM_PARITY_N)
- goto release;
- if (array.level == 6 &&
- array.layout != ALGORITHM_PARITY_N_6)
- goto release;
- sysfs_set_str(info, NULL,"sync_action", "idle");
- for (d = 0;
- d < MAX_DISKS && found < array.nr_disks;
- d++) {
- int cnt;
- mdu_disk_info_t disk;
- disk.number = d;
- if (ioctl(fd, GET_DISK_INFO, &disk) < 0)
- continue;
- if (disk.major == 0 && disk.minor == 0)
- continue;
- found++;
- if ((disk.state & (1 << MD_DISK_ACTIVE))
- && disk.raid_disk < reshape.after.data_disks)
- /* keep this */
- continue;
- ioctl(fd, SET_DISK_FAULTY,
- makedev(disk.major, disk.minor));
- cnt = 5;
- while (ioctl(fd, HOT_REMOVE_DISK,
- makedev(disk.major, disk.minor)) < 0
- && errno == EBUSY
- && cnt--) {
- usleep(10000);
- }
- }
- }
-
- err = sysfs_set_str(info, NULL, "level", c);
- if (err) {
- err = errno;
- pr_err("%s: could not set level to %s\n",
- devname, c);
- if (err == EBUSY &&
- (info->array.state & (1<<MD_SB_BITMAP_PRESENT)))
- cont_err("Bitmap must be removed"
- " before level can be changed\n");
- goto release;
- }
- if (verbose >= 0)
- pr_err("level of %s changed to %s\n",
- devname, c);
- info->new_layout = UnSet; // after level change, layout is meaningless
+ info->new_layout = UnSet; /* after level change,
+ * layout is meaningless */
orig_level = array.level;
sysfs_freeze_array(info);
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:
pr_err("Failed to initiate reshape!\n");
goto release;
}
-
+ if (info->new_level == reshape.level)
+ return 0;
+ /* need to adjust level when reshape completes */
+ switch(fork()) {
+ case -1: /* ignore error, but don't wait */
+ return 0;
+ default: /* parent */
+ return 0;
+ case 0:
+ map_fork();
+ break;
+ }
+ close(fd);
+ wait_reshape(sra);
+ 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 - "
if (!reshape_open_backup_file(backup_file, fd, devname,
(signed)blocks,
fdlist+d, offsets+d,
+ sra->sys_name,
restart)) {
goto release;
}
return 1;
}
+ if (!forked && !check_env("MDADM_NO_SYSTEMCTL"))
+ if (continue_via_systemd(container ?: sra->sys_name)) {
+ free(fdlist);
+ free(offsets);
+ sysfs_free(sra);
+ return 0;
+ }
+
/* Now we just need to kick off the reshape and watch, while
* handling backups of the data...
* This is all done by a forked background process.
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);
fd = -1;
mlockall(MCL_FUTURE);
+ signal(SIGTERM, catch_term);
+
if (st->ss->external) {
/* metadata handler takes it from here */
done = st->ss->manage_reshape(
free(fdlist);
free(offsets);
- if (backup_file && done)
+ if (backup_file && done) {
+ char *bul;
+ bul = make_backup(sra->sys_name);
+ if (bul) {
+ char buf[1024];
+ int l = readlink(bul, buf, sizeof(buf));
+ if (l > 0) {
+ buf[l]=0;
+ unlink(buf);
+ }
+ unlink(bul);
+ free(bul);
+ }
unlink(backup_file);
+ }
if (!done) {
abort_reshape(sra);
goto out;
set_array_size(st, info, info->text_version);
if (info->new_level != reshape.level) {
-
- c = map_num(pers, info->new_level);
- if (c) {
- err = sysfs_set_str(sra, NULL, "level", c);
- if (err)
- pr_err("%s: could not set level "
- "to %s\n", devname, c);
- }
+ if (fd < 0)
+ fd = open(devname, O_RDONLY);
+ impose_level(fd, info->new_level, devname, verbose);
+ close(fd);
if (info->new_level == 0)
st->update_tail = NULL;
}
struct supertype *st,
struct mdinfo *info,
int force,
- char *backup_file,
- int verbose, int restart, int freeze_reshape)
+ char *backup_file, int verbose,
+ int forked, int restart, int freeze_reshape)
{
struct mdinfo *cc = NULL;
int rv = restart;
*/
ping_monitor(container);
- switch (fork()) {
+ if (!forked && !freeze_reshape && !check_env("MDADM_NO_SYSTEMCTL"))
+ if (continue_via_systemd(container))
+ return 0;
+
+ switch (forked ? 0 : fork()) {
case -1: /* error */
perror("Cannot fork to complete reshape\n");
unfreeze(st);
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;
forget_backup(dests, destfd,
destoffsets, 1);
}
-
+ if (sigterm)
+ rv = -2;
if (rv < 0) {
if (rv == -1)
done = 1;
}
if (rv == 0 && increasing && !st->ss->external) {
/* No longer need to monitor this reshape */
+ sysfs_set_str(sra, NULL, "sync_max", "max");
done = 1;
break;
}
}
/* FIXME maybe call progress_reshape one more time instead */
- abort_reshape(sra); /* remove any remaining suspension */
+ /* remove any remaining suspension */
+ sysfs_set_num(sra, NULL, "suspend_lo", 0x7FFFFFFFFFFFFFFFULL);
+ sysfs_set_num(sra, NULL, "suspend_hi", 0);
+ sysfs_set_num(sra, NULL, "suspend_lo", 0);
+ sysfs_set_num(sra, NULL, "sync_min", 0);
+
if (reshape->before.data_disks == reshape->after.data_disks)
sysfs_set_num(sra, NULL, "sync_speed_min", speed);
free(buf);
continue;
err = st->ss->load_super(st, fd2, NULL);
close(fd2);
+ /* invalidate fd2 to avoid possible double close() */
+ fd2 = -1;
if (err)
continue;
break;
/* continue reshape
*/
- ret_val = Grow_continue(fd, st, content, backup_file, 0);
+ ret_val = Grow_continue(fd, st, content, backup_file, 1, 0);
Grow_continue_command_exit:
if (fd2 > -1)
}
int Grow_continue(int mdfd, struct supertype *st, struct mdinfo *info,
- char *backup_file, int freeze_reshape)
+ char *backup_file, int forked, int freeze_reshape)
{
int ret_val = 2;
close(cfd);
ret_val = reshape_container(st->container_devnm, NULL, mdfd,
st, info, 0, backup_file,
- 0,
+ 0, forked,
1 | info->reshape_active,
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, forked,
1 | info->reshape_active,
freeze_reshape);
return ret_val;
}
+
+char *make_backup(char *name)
+{
+ char *base = "backup_file-";
+ int len;
+ char *fname;
+
+ len = strlen(MAP_DIR) + 1 + strlen(base) + strlen(name)+1;
+ fname = xmalloc(len);
+ sprintf(fname, "%s/%s%s", MAP_DIR, base, name);
+ return fname;
+}
+
+char *locate_backup(char *name)
+{
+ char *fl = make_backup(name);
+ struct stat stb;
+
+ if (stat(fl, &stb) == 0 &&
+ S_ISREG(stb.st_mode))
+ return fl;
+
+ free(fl);
+ return NULL;
+}