Grow.c (mdadm-4.1) | : | Grow.c (mdadm-4.2) | ||
---|---|---|---|---|
skipping to change at line 200 | skipping to change at line 200 | |||
} | } | |||
/* Ok, looks good. Lets update the superblock and write it out to | /* Ok, looks good. Lets update the superblock and write it out to | |||
* newdev. | * newdev. | |||
*/ | */ | |||
info.disk.number = d; | info.disk.number = d; | |||
info.disk.major = major(rdev); | info.disk.major = major(rdev); | |||
info.disk.minor = minor(rdev); | info.disk.minor = minor(rdev); | |||
info.disk.raid_disk = d; | info.disk.raid_disk = d; | |||
info.disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE); | info.disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE); | |||
st->ss->update_super(st, &info, "linear-grow-new", newdev, 0, 0, NULL); | if (st->ss->update_super(st, &info, "linear-grow-new", newdev, | |||
0, 0, NULL) != 0) { | ||||
pr_err("Preparing new metadata failed on %s\n", newdev); | ||||
close(nfd); | ||||
return 1; | ||||
} | ||||
if (st->ss->store_super(st, nfd)) { | if (st->ss->store_super(st, nfd)) { | |||
pr_err("Cannot store new superblock on %s\n", newdev); | pr_err("Cannot store new superblock on %s\n", newdev); | |||
close(nfd); | close(nfd); | |||
return 1; | return 1; | |||
} | } | |||
close(nfd); | close(nfd); | |||
if (ioctl(fd, ADD_NEW_DISK, &info.disk) != 0) { | if (ioctl(fd, ADD_NEW_DISK, &info.disk) != 0) { | |||
pr_err("Cannot add new disk to this array\n"); | pr_err("Cannot add new disk to this array\n"); | |||
skipping to change at line 253 | skipping to change at line 258 | |||
pr_err("cannot find super block on %s\n", dv); | pr_err("cannot find super block on %s\n", dv); | |||
close(fd); | close(fd); | |||
close(fd2); | close(fd2); | |||
return 1; | return 1; | |||
} | } | |||
info.array.raid_disks = nd+1; | info.array.raid_disks = nd+1; | |||
info.array.nr_disks = nd+1; | info.array.nr_disks = nd+1; | |||
info.array.active_disks = nd+1; | info.array.active_disks = nd+1; | |||
info.array.working_disks = nd+1; | info.array.working_disks = nd+1; | |||
st->ss->update_super(st, &info, "linear-grow-update", dv, | if (st->ss->update_super(st, &info, "linear-grow-update", dv, | |||
0, 0, NULL); | 0, 0, NULL) != 0) { | |||
pr_err("Updating metadata failed on %s\n", dv); | ||||
close(fd2); | ||||
return 1; | ||||
} | ||||
if (st->ss->store_super(st, fd2)) { | if (st->ss->store_super(st, fd2)) { | |||
pr_err("Cannot store new superblock on %s\n", dv); | pr_err("Cannot store new superblock on %s\n", dv); | |||
close(fd2); | close(fd2); | |||
return 1; | return 1; | |||
} | } | |||
close(fd2); | close(fd2); | |||
} | } | |||
return 0; | return 0; | |||
skipping to change at line 424 | skipping to change at line 433 | |||
disk.number = d; | disk.number = d; | |||
if (md_get_disk_info(fd, &disk) < 0) | if (md_get_disk_info(fd, &disk) < 0) | |||
continue; | continue; | |||
if (disk.major == 0 && disk.minor == 0) | if (disk.major == 0 && disk.minor == 0) | |||
continue; | continue; | |||
if ((disk.state & (1 << MD_DISK_SYNC)) == 0) | if ((disk.state & (1 << MD_DISK_SYNC)) == 0) | |||
continue; | continue; | |||
dv = map_dev(disk.major, disk.minor, 1); | dv = map_dev(disk.major, disk.minor, 1); | |||
if (!dv) | if (!dv) | |||
continue; | continue; | |||
if (((disk.state & (1 << MD_DISK_WRITEMOSTLY)) == 0) && | ||||
(strcmp(s->bitmap_file, "clustered") == 0)) { | ||||
pr_err("%s disks marked write-mostly are not supp | ||||
orted with clustered bitmap\n",devname); | ||||
return 1; | ||||
} | ||||
fd2 = dev_open(dv, O_RDWR); | fd2 = dev_open(dv, O_RDWR); | |||
if (fd2 < 0) | if (fd2 < 0) | |||
continue; | continue; | |||
rv = st->ss->load_super(st, fd2, NULL); | rv = st->ss->load_super(st, fd2, NULL); | |||
if (!rv) { | if (!rv) { | |||
rv = st->ss->add_internal_bitmap( | rv = st->ss->add_internal_bitmap( | |||
st, &s->bitmap_chunk, c->delay, | st, &s->bitmap_chunk, c->delay, | |||
s->write_behind, bitmapsize, | s->write_behind, bitmapsize, | |||
offset_setable, major); | offset_setable, major); | |||
if (!rv) { | if (!rv) { | |||
skipping to change at line 449 | skipping to change at line 463 | |||
} else { | } else { | |||
pr_err("failed to load super-block.\n"); | pr_err("failed to load super-block.\n"); | |||
} | } | |||
close(fd2); | close(fd2); | |||
if (rv) | if (rv) | |||
return 1; | return 1; | |||
} | } | |||
if (offset_setable) { | if (offset_setable) { | |||
st->ss->getinfo_super(st, mdi, NULL); | st->ss->getinfo_super(st, mdi, NULL); | |||
if (sysfs_init(mdi, fd, NULL)) { | if (sysfs_init(mdi, fd, NULL)) { | |||
pr_err("failed to intialize sysfs.\n"); | pr_err("failed to initialize sysfs.\n"); | |||
free(mdi); | free(mdi); | |||
} | } | |||
rv = sysfs_set_num_signed(mdi, NULL, "bitmap/location", | rv = sysfs_set_num_signed(mdi, NULL, "bitmap/location", | |||
mdi->bitmap_offset); | mdi->bitmap_offset); | |||
free(mdi); | free(mdi); | |||
} else { | } else { | |||
if (strcmp(s->bitmap_file, "clustered") == 0) | if (strcmp(s->bitmap_file, "clustered") == 0) | |||
array.state |= (1 << MD_SB_CLUSTERED); | array.state |= (1 << MD_SB_CLUSTERED); | |||
array.state |= (1 << MD_SB_BITMAP_PRESENT); | array.state |= (1 << MD_SB_BITMAP_PRESENT); | |||
rv = md_set_array_info(fd, &array); | rv = md_set_array_info(fd, &array); | |||
skipping to change at line 915 | skipping to change at line 929 | |||
/* if we get EAGAIN here then the monitor is not active | /* if we get EAGAIN here then the monitor is not active | |||
* so stop trying | * so stop trying | |||
*/ | */ | |||
rc = sysfs_set_num(sra, NULL, name, n); | rc = sysfs_set_num(sra, NULL, name, n); | |||
} | } | |||
sysfs_set_str(sra, NULL, "safe_mode_delay", safe); | sysfs_set_str(sra, NULL, "safe_mode_delay", safe); | |||
return rc; | return rc; | |||
} | } | |||
int start_reshape(struct mdinfo *sra, int already_running, | int start_reshape(struct mdinfo *sra, int already_running, | |||
int before_data_disks, int data_disks) | int before_data_disks, int data_disks, struct supertype *st) | |||
{ | { | |||
int err; | int err; | |||
unsigned long long sync_max_to_set; | unsigned long long sync_max_to_set; | |||
sysfs_set_num(sra, NULL, "suspend_lo", 0x7FFFFFFFFFFFFFFFULL); | sysfs_set_num(sra, NULL, "suspend_lo", 0x7FFFFFFFFFFFFFFFULL); | |||
err = sysfs_set_num(sra, NULL, "suspend_hi", sra->reshape_progress); | err = sysfs_set_num(sra, NULL, "suspend_hi", sra->reshape_progress); | |||
err = err ?: sysfs_set_num(sra, NULL, "suspend_lo", | err = err ?: sysfs_set_num(sra, NULL, "suspend_lo", | |||
sra->reshape_progress); | sra->reshape_progress); | |||
if (before_data_disks <= data_disks) | if (before_data_disks <= data_disks) | |||
sync_max_to_set = sra->reshape_progress / data_disks; | sync_max_to_set = sra->reshape_progress / data_disks; | |||
else | else | |||
sync_max_to_set = (sra->component_size * data_disks | sync_max_to_set = (sra->component_size * data_disks | |||
- sra->reshape_progress) / data_disks; | - sra->reshape_progress) / data_disks; | |||
if (!already_running) | if (!already_running) | |||
sysfs_set_num(sra, NULL, "sync_min", sync_max_to_set); | sysfs_set_num(sra, NULL, "sync_min", sync_max_to_set); | |||
err = err ?: sysfs_set_num(sra, NULL, "sync_max", sync_max_to_set); | ||||
if (st->ss->external) | ||||
err = err ?: sysfs_set_num(sra, NULL, "sync_max", sync_max_to_set | ||||
); | ||||
else | ||||
err = err ?: sysfs_set_str(sra, NULL, "sync_max", "max"); | ||||
if (!already_running && err == 0) { | if (!already_running && err == 0) { | |||
int cnt = 5; | int cnt = 5; | |||
do { | do { | |||
err = sysfs_set_str(sra, NULL, "sync_action", | err = sysfs_set_str(sra, NULL, "sync_action", | |||
"reshape"); | "reshape"); | |||
if (err) | if (err) | |||
sleep(1); | sleep(1); | |||
} while (err && errno == EBUSY && cnt-- > 0); | } while (err && errno == EBUSY && cnt-- > 0); | |||
} | } | |||
return err; | return err; | |||
skipping to change at line 1199 | skipping to change at line 1219 | |||
/* So how much do we need to backup. | /* So how much do we need to backup. | |||
* We need an amount of data which is both a whole number of | * We need an amount of data which is both a whole number of | |||
* old stripes and a whole number of new stripes. | * old stripes and a whole number of new stripes. | |||
* So LCM for (chunksize*datadisks). | * So LCM for (chunksize*datadisks). | |||
*/ | */ | |||
a = (ochunk/512) * odata; | a = (ochunk/512) * odata; | |||
b = (nchunk/512) * ndata; | b = (nchunk/512) * ndata; | |||
/* Find GCD */ | /* Find GCD */ | |||
a = GCD(a, b); | a = GCD(a, b); | |||
/* LCM == product / GCD */ | /* LCM == product / GCD */ | |||
blocks = (ochunk/512) * (nchunk/512) * odata * ndata / a; | blocks = (unsigned long)(ochunk/512) * (unsigned long)(nchunk/512) * | |||
odata * ndata / a; | ||||
return blocks; | return blocks; | |||
} | } | |||
char *analyse_change(char *devname, 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 | /* Based on the current array state in info->array and | |||
* the changes in info->new_* etc, determine: | * the changes in info->new_* etc, determine: | |||
* - whether the change is possible | * - whether the change is possible | |||
* - Intermediate level/raid_disks/layout | * - Intermediate level/raid_disks/layout | |||
skipping to change at line 1840 | skipping to change at line 1861 | |||
st = super_by_fd(fd, &subarray); | st = super_by_fd(fd, &subarray); | |||
if (!st) { | if (!st) { | |||
pr_err("Unable to determine metadata format for %s\n", devname); | pr_err("Unable to determine metadata format for %s\n", devname); | |||
return 1; | return 1; | |||
} | } | |||
if (s->raiddisks > st->max_devs) { | if (s->raiddisks > st->max_devs) { | |||
pr_err("Cannot increase raid-disks on this array beyond %d\n", st ->max_devs); | pr_err("Cannot increase raid-disks on this array beyond %d\n", st ->max_devs); | |||
return 1; | return 1; | |||
} | } | |||
if (s->level == 0 && | if (s->level == 0 && (array.state & (1 << MD_SB_BITMAP_PRESENT)) && | |||
(array.state & (1<<MD_SB_BITMAP_PRESENT)) && | !(array.state & (1 << MD_SB_CLUSTERED)) && !st->ss->external) { | |||
!(array.state & (1<<MD_SB_CLUSTERED))) { | array.state &= ~(1 << MD_SB_BITMAP_PRESENT); | |||
array.state &= ~(1<<MD_SB_BITMAP_PRESENT); | if (md_set_array_info(fd, &array) != 0) { | |||
if (md_set_array_info(fd, &array)!= 0) { | pr_err("failed to remove internal bitmap.\n"); | |||
pr_err("failed to remove internal bitmap.\n"); | return 1; | |||
return 1; | } | |||
} | } | |||
} | ||||
/* in the external case we need to check that the requested reshape is | /* in the external case we need to check that the requested reshape is | |||
* supported, and perform an initial check that the container holds the | * supported, and perform an initial check that the container holds the | |||
* pre-requisite spare devices (mdmon owns final validation) | * pre-requisite spare devices (mdmon owns final validation) | |||
*/ | */ | |||
if (st->ss->external) { | if (st->ss->external) { | |||
int retval; | int retval; | |||
if (subarray) { | if (subarray) { | |||
container = st->container_devnm; | container = st->container_devnm; | |||
skipping to change at line 1912 | skipping to change at line 1932 | |||
free(subarray); | free(subarray); | |||
return 1; | return 1; | |||
} | } | |||
if (content->consistency_policy == | if (content->consistency_policy == | |||
CONSISTENCY_POLICY_PPL) { | CONSISTENCY_POLICY_PPL) { | |||
pr_err("Operation not supported when ppl consistency policy is enabled\n"); | pr_err("Operation not supported when ppl consistency policy is enabled\n"); | |||
sysfs_free(cc); | sysfs_free(cc); | |||
free(subarray); | free(subarray); | |||
return 1; | return 1; | |||
} | } | |||
if (content->consistency_policy == | ||||
CONSISTENCY_POLICY_BITMAP) { | ||||
pr_err("Operation not supported when writ | ||||
e-intent bitmap is enabled\n"); | ||||
sysfs_free(cc); | ||||
free(subarray); | ||||
return 1; | ||||
} | ||||
} | } | |||
sysfs_free(cc); | sysfs_free(cc); | |||
} | } | |||
if (mdmon_running(container)) | if (mdmon_running(container)) | |||
st->update_tail = &st->updates; | st->update_tail = &st->updates; | |||
} | } | |||
added_disks = 0; | added_disks = 0; | |||
for (dv = devlist; dv; dv = dv->next) | for (dv = devlist; dv; dv = dv->next) | |||
added_disks++; | added_disks++; | |||
skipping to change at line 2180 | skipping to change at line 2207 | |||
* and updated metadata before we continue with | * and updated metadata before we continue with | |||
* level change | * level change | |||
*/ | */ | |||
if (container) | if (container) | |||
ping_monitor(container); | ping_monitor(container); | |||
} | } | |||
memset(&info, 0, sizeof(info)); | memset(&info, 0, sizeof(info)); | |||
info.array = array; | info.array = array; | |||
if (sysfs_init(&info, fd, NULL)) { | if (sysfs_init(&info, fd, NULL)) { | |||
pr_err("failed to intialize sysfs.\n"); | pr_err("failed to initialize sysfs.\n"); | |||
rv = 1; | rv = 1; | |||
goto release; | goto release; | |||
} | } | |||
strcpy(info.text_version, sra->text_version); | strcpy(info.text_version, sra->text_version); | |||
info.component_size = s->size*2; | info.component_size = s->size*2; | |||
info.new_level = s->level; | info.new_level = s->level; | |||
info.new_chunk = s->chunk * 1024; | info.new_chunk = s->chunk * 1024; | |||
if (info.array.level == LEVEL_CONTAINER) { | if (info.array.level == LEVEL_CONTAINER) { | |||
info.delta_disks = UnSet; | info.delta_disks = UnSet; | |||
info.array.raid_disks = s->raiddisks; | info.array.raid_disks = s->raiddisks; | |||
skipping to change at line 2310 | skipping to change at line 2337 | |||
} | } | |||
} else if (array.level == LEVEL_CONTAINER) { | } else if (array.level == LEVEL_CONTAINER) { | |||
/* This change is to be applied to every array in the | /* This change is to be applied to every array in the | |||
* container. This is only needed when the metadata imposes | * container. This is only needed when the metadata imposes | |||
* restraints of the various arrays in the container. | * restraints of the various arrays in the container. | |||
* Currently we only know that IMSM requires all arrays | * Currently we only know that IMSM requires all arrays | |||
* to have the same number of devices so changing the | * to have the same number of devices so changing the | |||
* number of devices (On-Line Capacity Expansion) must be | * number of devices (On-Line Capacity Expansion) must be | |||
* performed at the level of the container | * performed at the level of the container | |||
*/ | */ | |||
if (fd > 0) { | close_fd(&fd); | |||
close(fd); | ||||
fd = -1; | ||||
} | ||||
rv = reshape_container(container, devname, -1, st, &info, | rv = reshape_container(container, devname, -1, st, &info, | |||
c->force, c->backup_file, c->verbose, | c->force, c->backup_file, c->verbose, | |||
0, 0, 0); | 0, 0, 0); | |||
frozen = 0; | frozen = 0; | |||
} else { | } else { | |||
/* get spare devices from external metadata | /* get spare devices from external metadata | |||
*/ | */ | |||
if (st->ss->external) { | if (st->ss->external) { | |||
struct mdinfo *info2; | struct mdinfo *info2; | |||
skipping to change at line 2615 | skipping to change at line 2639 | |||
} else { | } else { | |||
/* Decrease data offset */ | /* Decrease data offset */ | |||
if (before < min) { | if (before < min) { | |||
if (can_fallback) | if (can_fallback) | |||
goto fallback; | goto fallback; | |||
pr_err("insufficient head-room on %s\n", | pr_err("insufficient head-room on %s\n", | |||
dn); | dn); | |||
goto release; | goto release; | |||
} | } | |||
if (data_offset != INVALID_SECTORS && | if (data_offset != INVALID_SECTORS && | |||
data_offset < sd->data_offset - min) { | data_offset > sd->data_offset - min) { | |||
pr_err("--data-offset too small on %s\n", | pr_err("--data-offset too large on %s\n", | |||
dn); | dn); | |||
goto release; | goto release; | |||
} | } | |||
if (data_offset != INVALID_SECTORS) | if (data_offset != INVALID_SECTORS) | |||
new_data_offset = data_offset; | new_data_offset = data_offset; | |||
else | else | |||
new_data_offset = choose_offset(sd->data_ offset - before, | new_data_offset = choose_offset(sd->data_ offset - before, | |||
sd->data_ offset, | sd->data_ offset, | |||
sd->data_ offset - before, | sd->data_ offset - before, | |||
sd->data_ offset - min); | sd->data_ offset - min); | |||
skipping to change at line 2905 | skipping to change at line 2929 | |||
return -1; | return -1; | |||
} | } | |||
static int impose_level(int fd, int level, char *devname, int verbose) | static int impose_level(int fd, int level, char *devname, int verbose) | |||
{ | { | |||
char *c; | char *c; | |||
struct mdu_array_info_s array; | struct mdu_array_info_s array; | |||
struct mdinfo info; | struct mdinfo info; | |||
if (sysfs_init(&info, fd, NULL)) { | if (sysfs_init(&info, fd, NULL)) { | |||
pr_err("failed to intialize sysfs.\n"); | pr_err("failed to initialize sysfs.\n"); | |||
return 1; | return 1; | |||
} | } | |||
md_get_array_info(fd, &array); | md_get_array_info(fd, &array); | |||
if (level == 0 && (array.level >= 4 && array.level <= 6)) { | if (level == 0 && (array.level >= 4 && array.level <= 6)) { | |||
/* To convert to RAID0 we need to fail and | /* To convert to RAID0 we need to fail and | |||
* remove any non-data devices. */ | * remove any non-data devices. */ | |||
int found = 0; | int found = 0; | |||
int d; | int d; | |||
int data_disks = array.raid_disks - 1; | int data_disks = array.raid_disks - 1; | |||
skipping to change at line 2984 | skipping to change at line 3008 | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
int sigterm = 0; | int sigterm = 0; | |||
static void catch_term(int sig) | static void catch_term(int sig) | |||
{ | { | |||
sigterm = 1; | 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", "restart", | ||||
pathbuf, NULL); | ||||
status = execl("/bin/systemctl", "systemctl", "restart", | ||||
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, | static int reshape_array(char *container, int fd, char *devname, | |||
struct supertype *st, struct mdinfo *info, | struct supertype *st, struct mdinfo *info, | |||
int force, struct mddev_dev *devlist, | int force, struct mddev_dev *devlist, | |||
unsigned long long data_offset, | unsigned long long data_offset, | |||
char *backup_file, int verbose, int forked, | char *backup_file, int verbose, int forked, | |||
int restart, int freeze_reshape) | int restart, int freeze_reshape) | |||
{ | { | |||
struct reshape reshape; | struct reshape reshape; | |||
int spares_needed; | int spares_needed; | |||
char *msg; | char *msg; | |||
skipping to change at line 3288 | skipping to change at line 3271 | |||
} | } | |||
} | } | |||
if (info->new_chunk != 0 && | if (info->new_chunk != 0 && | |||
info->new_chunk != array.chunk_size) { | info->new_chunk != array.chunk_size) { | |||
if (sysfs_set_num(info, NULL, | if (sysfs_set_num(info, NULL, | |||
"chunk_size", info->new_chunk) != 0) { | "chunk_size", info->new_chunk) != 0) { | |||
pr_err("failed to set chunk size\n"); | pr_err("failed to set chunk size\n"); | |||
goto release; | goto release; | |||
} else if (verbose >= 0) | } else if (verbose >= 0) | |||
printf("chunk size for %s set to %d\n", | printf("chunk size for %s set to %d\n", | |||
devname, array.chunk_size); | devname, info->new_chunk); | |||
} | } | |||
unfreeze(st); | unfreeze(st); | |||
return 0; | return 0; | |||
} | } | |||
/* | /* | |||
* There are three possibilities. | * There are three possibilities. | |||
* 1/ The array will shrink. | * 1/ The array will shrink. | |||
* We need to ensure the reshape will pause before reaching | * We need to ensure the reshape will pause before reaching | |||
* the 'critical section'. We also need to fork and wait for | * the 'critical section'. We also need to fork and wait for | |||
skipping to change at line 3403 | skipping to change at line 3386 | |||
} | } | |||
if (info->new_level == reshape.level) | if (info->new_level == reshape.level) | |||
return 0; | return 0; | |||
/* need to adjust level when reshape completes */ | /* need to adjust level when reshape completes */ | |||
switch(fork()) { | switch(fork()) { | |||
case -1: /* ignore error, but don't wait */ | case -1: /* ignore error, but don't wait */ | |||
return 0; | return 0; | |||
default: /* parent */ | default: /* parent */ | |||
return 0; | return 0; | |||
case 0: | case 0: | |||
manage_fork_fds(0); | ||||
map_fork(); | map_fork(); | |||
break; | break; | |||
} | } | |||
close(fd); | close(fd); | |||
wait_reshape(sra); | wait_reshape(sra); | |||
fd = open_dev(sra->sys_name); | fd = open_dev(sra->sys_name); | |||
if (fd >= 0) | if (fd >= 0) | |||
impose_level(fd, info->new_level, devname, verbose); | impose_level(fd, info->new_level, devname, verbose); | |||
return 0; | return 0; | |||
case 1: /* Couldn't set data_offset, try the old way */ | case 1: /* Couldn't set data_offset, try the old way */ | |||
skipping to change at line 3494 | skipping to change at line 3478 | |||
* If only changing raid_disks, use ioctl, else use | * If only changing raid_disks, use ioctl, else use | |||
* sysfs. | * sysfs. | |||
*/ | */ | |||
sync_metadata(st); | sync_metadata(st); | |||
if (impose_reshape(sra, info, st, fd, restart, | if (impose_reshape(sra, info, st, fd, restart, | |||
devname, container, &reshape) < 0) | devname, container, &reshape) < 0) | |||
goto release; | goto release; | |||
err = start_reshape(sra, restart, reshape.before.data_disks, | err = start_reshape(sra, restart, reshape.before.data_disks, | |||
reshape.after.data_disks); | reshape.after.data_disks, st); | |||
if (err) { | if (err) { | |||
pr_err("Cannot %s reshape for %s\n", | pr_err("Cannot %s reshape for %s\n", | |||
restart ? "continue" : "start", devname); | restart ? "continue" : "start", devname); | |||
goto release; | goto release; | |||
} | } | |||
if (restart) | if (restart) | |||
sysfs_set_str(sra, NULL, "array_state", "active"); | sysfs_set_str(sra, NULL, "array_state", "active"); | |||
if (freeze_reshape) { | if (freeze_reshape) { | |||
free(fdlist); | free(fdlist); | |||
free(offsets); | free(offsets); | |||
sysfs_free(sra); | sysfs_free(sra); | |||
pr_err("Reshape has to be continued from location %llu when root filesystem has been mounted.\n", | pr_err("Reshape has to be continued from location %llu when root filesystem has been mounted.\n", | |||
sra->reshape_progress); | sra->reshape_progress); | |||
return 1; | return 1; | |||
} | } | |||
if (!forked && !check_env("MDADM_NO_SYSTEMCTL")) | if (!forked) | |||
if (continue_via_systemd(container ?: sra->sys_name)) { | if (continue_via_systemd(container ?: sra->sys_name, | |||
GROW_SERVICE)) { | ||||
free(fdlist); | free(fdlist); | |||
free(offsets); | free(offsets); | |||
sysfs_free(sra); | sysfs_free(sra); | |||
return 0; | return 0; | |||
} | } | |||
close(fd); | ||||
/* Now we just need to kick off the reshape and watch, while | /* Now we just need to kick off the reshape and watch, while | |||
* handling backups of the data... | * handling backups of the data... | |||
* This is all done by a forked background process. | * This is all done by a forked background process. | |||
*/ | */ | |||
switch(forked ? 0 : fork()) { | switch(forked ? 0 : fork()) { | |||
case -1: | case -1: | |||
pr_err("Cannot run child to monitor reshape: %s\n", | pr_err("Cannot run child to monitor reshape: %s\n", | |||
strerror(errno)); | strerror(errno)); | |||
abort_reshape(sra); | abort_reshape(sra); | |||
goto release; | goto release; | |||
skipping to change at line 3571 | skipping to change at line 3557 | |||
free_mdstat(mds); | free_mdstat(mds); | |||
if (delayed == 1 && get_linux_version() < 3007000) { | if (delayed == 1 && get_linux_version() < 3007000) { | |||
pr_err("Reshape is delayed, but cannot wait carefully wit h this kernel.\n" | pr_err("Reshape is delayed, but cannot wait carefully wit h this kernel.\n" | |||
" You might experience problems until other reshapes complete.\n"); | " You might experience problems until other reshapes complete.\n"); | |||
delayed = 0; | delayed = 0; | |||
} | } | |||
if (delayed) | if (delayed) | |||
mdstat_wait(30 - (delayed-1) * 25); | mdstat_wait(30 - (delayed-1) * 25); | |||
} while (delayed); | } while (delayed); | |||
mdstat_close(); | mdstat_close(); | |||
close(fd); | ||||
if (check_env("MDADM_GROW_VERIFY")) | if (check_env("MDADM_GROW_VERIFY")) | |||
fd = open(devname, O_RDONLY | O_DIRECT); | fd = open(devname, O_RDONLY | O_DIRECT); | |||
else | else | |||
fd = -1; | fd = -1; | |||
mlockall(MCL_FUTURE); | mlockall(MCL_FUTURE); | |||
signal(SIGTERM, catch_term); | signal(SIGTERM, catch_term); | |||
if (st->ss->external) { | if (st->ss->external) { | |||
/* metadata handler takes it from here */ | /* metadata handler takes it from here */ | |||
skipping to change at line 3706 | skipping to change at line 3691 | |||
unfreeze(st); | unfreeze(st); | |||
return 1; | return 1; | |||
} | } | |||
sync_metadata(st); | sync_metadata(st); | |||
/* ping monitor to be sure that update is on disk | /* ping monitor to be sure that update is on disk | |||
*/ | */ | |||
ping_monitor(container); | ping_monitor(container); | |||
if (!forked && !freeze_reshape && !check_env("MDADM_NO_SYSTEMCTL")) | if (!forked && !freeze_reshape) | |||
if (continue_via_systemd(container)) | if (continue_via_systemd(container, GROW_SERVICE)) | |||
return 0; | return 0; | |||
switch (forked ? 0 : fork()) { | switch (forked ? 0 : fork()) { | |||
case -1: /* error */ | case -1: /* error */ | |||
perror("Cannot fork to complete reshape\n"); | perror("Cannot fork to complete reshape\n"); | |||
unfreeze(st); | unfreeze(st); | |||
return 1; | return 1; | |||
default: /* parent */ | default: /* parent */ | |||
if (!freeze_reshape) | if (!freeze_reshape) | |||
printf("%s: multi-array reshape continues in background\n ", Name); | printf("%s: multi-array reshape continues in background\n ", Name); | |||
return 0; | return 0; | |||
case 0: /* child */ | case 0: /* child */ | |||
manage_fork_fds(0); | ||||
map_fork(); | map_fork(); | |||
break; | break; | |||
} | } | |||
/* close unused handle in child process | /* close unused handle in child process | |||
*/ | */ | |||
if (mdfd > -1) | if (mdfd > -1) | |||
close(mdfd); | close(mdfd); | |||
while(1) { | while(1) { | |||
End of changes. 23 change blocks. | ||||
72 lines changed or deleted | 61 lines changed or added |