Assemble.c (mdadm-4.1) | : | Assemble.c (mdadm-4.2) | ||
---|---|---|---|---|
skipping to change at line 28 | skipping to change at line 28 | |||
* along with this program; if not, write to the Free Software | * along with this program; if not, write to the Free Software | |||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
* | * | |||
* Author: Neil Brown | * Author: Neil Brown | |||
* Email: <neilb@suse.de> | * Email: <neilb@suse.de> | |||
*/ | */ | |||
#include "mdadm.h" | #include "mdadm.h" | |||
#include <ctype.h> | #include <ctype.h> | |||
mapping_t assemble_statuses[] = { | ||||
{ "but cannot be started", INCR_NO }, | ||||
{ "but not safe to start", INCR_UNSAFE }, | ||||
{ "and started", INCR_YES }, | ||||
{ NULL, INCR_ALREADY } | ||||
}; | ||||
/** | ||||
* struct assembly_array_info - General, meaningful information for assembly. | ||||
* @name: Array name. | ||||
* @new_cnt: Count of drives known to be members, recently added. | ||||
* @preexist_cnt: Count of member drives in pre-assembled array. | ||||
* @exp_cnt: Count of known expansion targets. | ||||
* | ||||
* FIXME: @exp_new_cnt for recently added expansion targets. | ||||
*/ | ||||
struct assembly_array_info { | ||||
char *name; | ||||
int new_cnt; | ||||
int preexist_cnt; | ||||
int exp_cnt; | ||||
}; | ||||
/** | ||||
* set_array_assembly_status() - generate status of assembly for an array. | ||||
* @c: Global settings. | ||||
* @result: Pointer to status mask. | ||||
* @status: Status to be set/printed. | ||||
* @arr: Array information. | ||||
* | ||||
* Print status message to user or set it in @result if it is not NULL. | ||||
*/ | ||||
static void set_array_assembly_status(struct context *c, | ||||
int *result, int status, | ||||
struct assembly_array_info *arr) | ||||
{ | ||||
int raid_disks = arr->preexist_cnt + arr->new_cnt; | ||||
char *status_msg = map_num(assemble_statuses, status); | ||||
if (c->export && result) | ||||
*result |= status; | ||||
if (c->export || c->verbose < 0) | ||||
return; | ||||
pr_err("%s has been assembled with %d device%s", arr->name, | ||||
raid_disks, raid_disks == 1 ? "":"s"); | ||||
if (arr->preexist_cnt > 0) | ||||
fprintf(stderr, " (%d new)", arr->new_cnt); | ||||
if (arr->exp_cnt) | ||||
fprintf(stderr, " ( + %d for expansion)", arr->exp_cnt); | ||||
if (status_msg) | ||||
fprintf(stderr, " %s", status_msg); | ||||
fprintf(stderr, ".\n"); | ||||
} | ||||
static int name_matches(char *found, char *required, char *homehost, int require _homehost) | static int name_matches(char *found, char *required, char *homehost, int require _homehost) | |||
{ | { | |||
/* See if the name found matches the required name, possibly | /* See if the name found matches the required name, possibly | |||
* prefixed with 'homehost' | * prefixed with 'homehost' | |||
*/ | */ | |||
char *sep; | char *sep; | |||
unsigned int l; | unsigned int l; | |||
if (strcmp(found, required)==0) | if (strcmp(found, required)==0) | |||
return 1; | return 1; | |||
skipping to change at line 272 | skipping to change at line 328 | |||
pr_err("%s has metadata type %s for which auto-assembly is disabled\n", | pr_err("%s has metadata type %s for which auto-assembly is disabled\n", | |||
devname, tst->ss->name); | devname, tst->ss->name); | |||
tmpdev->used = 2; | tmpdev->used = 2; | |||
} | } | |||
} | } | |||
if (dfd >= 0) close(dfd); | if (dfd >= 0) close(dfd); | |||
if (tmpdev->used == 2) { | if (tmpdev->used == 2) { | |||
if (auto_assem || !inargv) | if (auto_assem || !inargv) | |||
/* Ignore unrecognised devices during auto-assemb ly */ | /* Ignore unrecognised devices during auto-assemb ly */ | |||
goto loop; | goto loop; | |||
if (ident->uuid_set || ident->name[0] || | if (ident->name[0] || | |||
ident->super_minor != UnSet) | ident->super_minor != UnSet) | |||
/* Ignore unrecognised device if looking for | /* Ignore unrecognised device if looking for | |||
* specific array */ | * specific array */ | |||
goto loop; | goto loop; | |||
if (ident->uuid_set) | ||||
/* ignore unrecognized device if looking for | ||||
* specific uuid | ||||
*/ | ||||
goto loop; | ||||
pr_err("%s has no superblock - assembly aborted\n", | pr_err("%s has no superblock - assembly aborted\n", | |||
devname); | devname); | |||
if (st) | if (st) | |||
st->ss->free_super(st); | st->ss->free_super(st); | |||
dev_policy_free(pol); | dev_policy_free(pol); | |||
domain_free(domains); | domain_free(domains); | |||
if (tst) | if (tst) | |||
tst->ss->free_super(tst); | tst->ss->free_super(tst); | |||
return -1; | return -1; | |||
skipping to change at line 438 | skipping to change at line 499 | |||
* an array unless there are no more arrays of | * an array unless there are no more arrays of | |||
* this type to be found. It can be included | * this type to be found. It can be included | |||
* in an array of this type though. | * in an array of this type though. | |||
*/ | */ | |||
tmpdev->used = 3; | tmpdev->used = 3; | |||
goto loop; | goto loop; | |||
} | } | |||
if (st->ss != tst->ss || | if (st->ss != tst->ss || | |||
st->minor_version != tst->minor_version || | st->minor_version != tst->minor_version || | |||
st->ss->compare_super(st, tst) != 0) { | st->ss->compare_super(st, tst, 1) != 0) { | |||
/* Some mismatch. If exactly one array matches th is host, | /* Some mismatch. If exactly one array matches th is host, | |||
* we can resolve on that one. | * we can resolve on that one. | |||
* Or, if we are auto assembling, we just ignore the second | * Or, if we are auto assembling, we just ignore the second | |||
* for now. | * for now. | |||
*/ | */ | |||
if (auto_assem) | if (auto_assem) | |||
goto loop; | goto loop; | |||
if (c->homehost) { | if (c->homehost) { | |||
int first = st->ss->match_home(st, c->hom ehost); | int first = st->ss->match_home(st, c->hom ehost); | |||
int last = tst->ss->match_home(tst, c->ho mehost); | int last = tst->ss->match_home(tst, c->ho mehost); | |||
skipping to change at line 510 | skipping to change at line 571 | |||
continue; | continue; | |||
tmpdev->used = 1; | tmpdev->used = 1; | |||
content = *contentp; | content = *contentp; | |||
if (!st->sb) { | if (!st->sb) { | |||
/* we need sb from one of the spares */ | /* we need sb from one of the spares */ | |||
int dfd = dev_open(tmpdev->devname, O_RDONLY); | int dfd = dev_open(tmpdev->devname, O_RDONLY); | |||
if (dfd < 0 || | if (dfd < 0 || | |||
st->ss->load_super(st, dfd, NULL)) | st->ss->load_super(st, dfd, NULL)) | |||
tmpdev->used = 2; | tmpdev->used = 2; | |||
if (dfd > 0) | close_fd(&dfd); | |||
close(dfd); | ||||
} | } | |||
} | } | |||
/* Now reject spares that don't match domains of identified members */ | /* Now reject spares that don't match domains of identified members */ | |||
for (tmpdev = devlist; tmpdev; tmpdev = tmpdev->next) { | for (tmpdev = devlist; tmpdev; tmpdev = tmpdev->next) { | |||
if (tmpdev->used != 3) | if (tmpdev->used != 3) | |||
continue; | continue; | |||
if (!stat_is_blkdev(tmpdev->devname, &rdev)) { | if (!stat_is_blkdev(tmpdev->devname, &rdev)) { | |||
tmpdev->used = 2; | tmpdev->used = 2; | |||
} else { | } else { | |||
skipping to change at line 581 | skipping to change at line 641 | |||
int bestcnt = 0; | int bestcnt = 0; | |||
int *best = *bestp; | int *best = *bestp; | |||
struct supertype *st = *stp; | struct supertype *st = *stp; | |||
for (tmpdev = devlist; tmpdev; tmpdev=tmpdev->next) { | for (tmpdev = devlist; tmpdev; tmpdev=tmpdev->next) { | |||
char *devname = tmpdev->devname; | char *devname = tmpdev->devname; | |||
struct stat stb; | struct stat stb; | |||
struct supertype *tst; | struct supertype *tst; | |||
int i; | int i; | |||
int dfd; | int dfd; | |||
int disk_state; | ||||
if (tmpdev->used != 1) | if (tmpdev->used != 1) | |||
continue; | continue; | |||
/* looks like a good enough match to update the super block if ne eded */ | /* looks like a good enough match to update the super block if ne eded */ | |||
if (c->update) { | if (c->update) { | |||
/* prepare useful information in info structures */ | /* prepare useful information in info structures */ | |||
struct stat stb2; | struct stat stb2; | |||
int err; | int err; | |||
fstat(mdfd, &stb2); | fstat(mdfd, &stb2); | |||
skipping to change at line 714 | skipping to change at line 775 | |||
pr_err("%s is identified as a member of %s, slot %d%s.\n" , | pr_err("%s is identified as a member of %s, slot %d%s.\n" , | |||
devname, mddev, content->disk.raid_disk, | devname, mddev, content->disk.raid_disk, | |||
(content->disk.state & (1<<MD_DISK_REPLACEMENT)) ? " replacement":""); | (content->disk.state & (1<<MD_DISK_REPLACEMENT)) ? " replacement":""); | |||
devices[devcnt].devname = devname; | devices[devcnt].devname = devname; | |||
devices[devcnt].uptodate = 0; | devices[devcnt].uptodate = 0; | |||
devices[devcnt].included = (tmpdev->disposition == 'I'); | devices[devcnt].included = (tmpdev->disposition == 'I'); | |||
devices[devcnt].i = *content; | devices[devcnt].i = *content; | |||
devices[devcnt].i.disk.major = major(stb.st_rdev); | devices[devcnt].i.disk.major = major(stb.st_rdev); | |||
devices[devcnt].i.disk.minor = minor(stb.st_rdev); | devices[devcnt].i.disk.minor = minor(stb.st_rdev); | |||
if (devices[devcnt].i.disk.state == 6) { | disk_state = devices[devcnt].i.disk.state & ~((1<<MD_DISK_FAILFAS | |||
T) | | ||||
(1<<MD_DISK_WRITEMO | ||||
STLY)); | ||||
if (disk_state == ((1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC))) { | ||||
if (most_recent < 0 || | if (most_recent < 0 || | |||
devices[devcnt].i.events | devices[devcnt].i.events | |||
> devices[most_recent].i.events) { | > devices[most_recent].i.events) { | |||
struct supertype *tmp = tst; | struct supertype *tmp = tst; | |||
tst = st; | tst = st; | |||
st = tmp; | st = tmp; | |||
most_recent = devcnt; | most_recent = devcnt; | |||
} | } | |||
} | } | |||
tst->ss->free_super(tst); | tst->ss->free_super(tst); | |||
skipping to change at line 879 | skipping to change at line 942 | |||
if (chosen_drive < 0 || | if (chosen_drive < 0 || | |||
devices[j].i.events | devices[j].i.events | |||
> devices[chosen_drive].i.events) | > devices[chosen_drive].i.events) | |||
chosen_drive = j; | chosen_drive = j; | |||
} | } | |||
if (chosen_drive < 0) | if (chosen_drive < 0) | |||
break; | break; | |||
current_events = devices[chosen_drive].i.events; | current_events = devices[chosen_drive].i.events; | |||
add_another: | add_another: | |||
if (c->verbose >= 0) | if (c->verbose >= 0) | |||
pr_err("forcing event count in %s(%d) from %d upto %d\n", | pr_err("forcing event count in %s(%d) from %d up to %d\n" , | |||
devices[chosen_drive].devname, | devices[chosen_drive].devname, | |||
devices[chosen_drive].i.disk.raid_disk, | devices[chosen_drive].i.disk.raid_disk, | |||
(int)(devices[chosen_drive].i.events), | (int)(devices[chosen_drive].i.events), | |||
(int)(devices[most_recent].i.events)); | (int)(devices[most_recent].i.events)); | |||
fd = dev_open(devices[chosen_drive].devname, | fd = dev_open(devices[chosen_drive].devname, | |||
devices[chosen_drive].included ? O_RDWR | devices[chosen_drive].included ? O_RDWR | |||
: (O_RDWR|O_EXCL)); | : (O_RDWR|O_EXCL)); | |||
if (fd < 0) { | if (fd < 0) { | |||
pr_err("Couldn't open %s for write - not updating\n", | pr_err("Couldn't open %s for write - not updating\n", | |||
devices[chosen_drive].devname); | devices[chosen_drive].devname); | |||
skipping to change at line 1031 | skipping to change at line 1094 | |||
if (dfd >= 0) { | if (dfd >= 0) { | |||
remove_partitions(dfd); | remove_partitions(dfd); | |||
close(dfd); | close(dfd); | |||
} | } | |||
rv = add_disk(mdfd, st, content, &devices[j].i); | rv = add_disk(mdfd, st, content, &devices[j].i); | |||
if (rv) { | if (rv) { | |||
pr_err("failed to add %s to %s: %s\n", | pr_err("failed to add %s to %s: %s\n", | |||
devices[j].devname, mddev, | devices[j].devname, mddev, | |||
strerror(errno)); | strerror(errno)); | |||
if (errno == EINVAL && content->array.level == 0 | ||||
&& | ||||
content->array.layout != 0) { | ||||
cont_err("Possibly your kernel doesn't su | ||||
pport RAID0 layouts.\n"); | ||||
cont_err("Please upgrade.\n"); | ||||
} | ||||
if (i < content->array.raid_disks * 2 || | if (i < content->array.raid_disks * 2 || | |||
i == bestcnt) | i == bestcnt) | |||
okcnt--; | okcnt--; | |||
else | else | |||
sparecnt--; | sparecnt--; | |||
} else if (c->verbose > 0) { | } else if (c->verbose > 0) { | |||
pr_err("added %s to %s as %d%s%s\n", | pr_err("added %s to %s as %d%s%s\n", | |||
devices[j].devname, mddev, | devices[j].devname, mddev, | |||
devices[j].i.disk.raid_disk, | devices[j].i.disk.raid_disk, | |||
devices[j].uptodate?"": | devices[j].uptodate?"": | |||
skipping to change at line 1058 | skipping to change at line 1126 | |||
pr_err("%s is already in %s as %d\n", | pr_err("%s is already in %s as %d\n", | |||
devices[j].devname, mddev, | devices[j].devname, mddev, | |||
devices[j].i.disk.raid_disk); | devices[j].i.disk.raid_disk); | |||
} else if (c->verbose > 0 && | } else if (c->verbose > 0 && | |||
i < content->array.raid_disks * 2 && (i & 1) == 0) | i < content->array.raid_disks * 2 && (i & 1) == 0) | |||
pr_err("no uptodate device for slot %d of %s\n", | pr_err("no uptodate device for slot %d of %s\n", | |||
i/2, mddev); | i/2, mddev); | |||
} | } | |||
if (content->array.level == LEVEL_CONTAINER) { | if (content->array.level == LEVEL_CONTAINER) { | |||
sysfs_rules_apply(mddev, content); | ||||
if (c->verbose >= 0) { | if (c->verbose >= 0) { | |||
pr_err("Container %s has been assembled with %d drive%s", | pr_err("Container %s has been assembled with %d drive%s", | |||
mddev, okcnt + sparecnt + journalcnt, | mddev, okcnt + sparecnt + journalcnt, | |||
okcnt + sparecnt + journalcnt == 1 ? "" : "s"); | okcnt + sparecnt + journalcnt == 1 ? "" : "s"); | |||
if (okcnt < (unsigned)content->array.raid_disks) | if (okcnt < (unsigned)content->array.raid_disks) | |||
fprintf(stderr, " (out of %d)", | fprintf(stderr, " (out of %d)\n", | |||
content->array.raid_disks); | content->array.raid_disks); | |||
fprintf(stderr, "\n"); | else | |||
fprintf(stderr, "\n"); | ||||
} | } | |||
if (st->ss->validate_container) { | if (st->ss->validate_container) { | |||
struct mdinfo *devices_list; | struct mdinfo *devices_list; | |||
struct mdinfo *info_devices; | struct mdinfo *info_devices; | |||
unsigned int count; | unsigned int count; | |||
devices_list = NULL; | devices_list = NULL; | |||
info_devices = xmalloc(sizeof(struct mdinfo) * | info_devices = xmalloc(sizeof(struct mdinfo) * | |||
(okcnt + sparecnt)); | (okcnt + sparecnt)); | |||
skipping to change at line 1139 | skipping to change at line 1209 | |||
c->freeze_reshape); | c->freeze_reshape); | |||
} else if (c->readonly && | } else if (c->readonly && | |||
sysfs_attribute_available(content, NULL, | sysfs_attribute_available(content, NULL, | |||
"array_state")) { | "array_state")) { | |||
rv = sysfs_set_str(content, NULL, | rv = sysfs_set_str(content, NULL, | |||
"array_state", "readonly"); | "array_state", "readonly"); | |||
} else | } else | |||
rv = ioctl(mdfd, RUN_ARRAY, NULL); | rv = ioctl(mdfd, RUN_ARRAY, NULL); | |||
reopen_mddev(mdfd); /* drop O_EXCL */ | reopen_mddev(mdfd); /* drop O_EXCL */ | |||
if (rv == 0) { | if (rv == 0) { | |||
sysfs_rules_apply(mddev, content); | ||||
if (c->verbose >= 0) { | if (c->verbose >= 0) { | |||
pr_err("%s has been started with %d drive%s", | pr_err("%s has been started with %d drive%s", | |||
mddev, okcnt, okcnt==1?"":"s"); | mddev, okcnt, okcnt==1?"":"s"); | |||
if (okcnt < (unsigned)content->array.raid_disks) | if (okcnt < (unsigned)content->array.raid_disks) | |||
fprintf(stderr, " (out of %d)", | fprintf(stderr, " (out of %d)", | |||
content->array.raid_disks); | content->array.raid_disks); | |||
if (rebuilding_cnt) | if (rebuilding_cnt) | |||
fprintf(stderr, "%s %d rebuilding", | fprintf(stderr, "%s %d rebuilding", | |||
sparecnt?",":" and", | sparecnt?",":" and", | |||
rebuilding_cnt); | rebuilding_cnt); | |||
skipping to change at line 1216 | skipping to change at line 1287 | |||
sra = sysfs_read(mdfd, NULL, 0); | sra = sysfs_read(mdfd, NULL, 0); | |||
if (sra) | if (sra) | |||
sysfs_set_str(sra, NULL, | sysfs_set_str(sra, NULL, | |||
"sync_action", "repair"); | "sync_action", "repair"); | |||
sysfs_free(sra); | sysfs_free(sra); | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
pr_err("failed to RUN_ARRAY %s: %s\n", mddev, strerror(errno)); | pr_err("failed to RUN_ARRAY %s: %s\n", mddev, strerror(errno)); | |||
if (errno == 524 /* ENOTSUP */ && | ||||
content->array.level == 0 && content->array.layout == 0) | ||||
cont_err("Please use --update=layout-original or --update | ||||
=layout-alternate\n"); | ||||
if (!enough(content->array.level, content->array.raid_disks, | if (!enough(content->array.level, content->array.raid_disks, | |||
content->array.layout, 1, avail)) | content->array.layout, 1, avail)) | |||
pr_err("Not enough devices to start the array.\n"); | pr_err("Not enough devices to start the array.\n"); | |||
else if (!enough(content->array.level, | else if (!enough(content->array.level, | |||
content->array.raid_disks, | content->array.raid_disks, | |||
content->array.layout, clean, avail)) | content->array.layout, clean, avail)) | |||
pr_err("Not enough devices to start the array while not c lean - consider --force.\n"); | pr_err("Not enough devices to start the array while not c lean - consider --force.\n"); | |||
return 1; | return 1; | |||
skipping to change at line 1470 | skipping to change at line 1544 | |||
?: st->ss->match_home(st, "any")) { | ?: st->ss->match_home(st, "any")) { | |||
case 1: | case 1: | |||
trustworthy = LOCAL; | trustworthy = LOCAL; | |||
name = strchr(content->name, ':'); | name = strchr(content->name, ':'); | |||
if (name) | if (name) | |||
name++; | name++; | |||
else | else | |||
name = content->name; | name = content->name; | |||
break; | break; | |||
} | } | |||
if (mddev && map_by_name(&map, mddev) != NULL) { | ||||
pr_err("Cannot create device with %s because is in use\n" | ||||
, mddev); | ||||
goto out; | ||||
} | ||||
if (!auto_assem) | if (!auto_assem) | |||
/* If the array is listed in mdadm.conf or on | /* If the array is listed in mdadm.conf or on | |||
* command line, then we trust the name | * command line, then we trust the name | |||
* even if the array doesn't look local | * even if the array doesn't look local | |||
*/ | */ | |||
trustworthy = LOCAL; | trustworthy = LOCAL; | |||
if (name[0] == 0 && | if (name[0] == 0 && | |||
content->array.level == LEVEL_CONTAINER) { | content->array.level == LEVEL_CONTAINER) { | |||
name = content->text_version; | name = content->text_version; | |||
skipping to change at line 1707 | skipping to change at line 1785 | |||
continue; | continue; | |||
if (devices[j].i.disk.raid_disk == MD_DISK_ROLE_JOURNAL) | if (devices[j].i.disk.raid_disk == MD_DISK_ROLE_JOURNAL) | |||
desired_state = (1<<MD_DISK_JOURNAL); | desired_state = (1<<MD_DISK_JOURNAL); | |||
else if (i >= content->array.raid_disks * 2) | else if (i >= content->array.raid_disks * 2) | |||
desired_state = 0; | desired_state = 0; | |||
else if (i & 1) | else if (i & 1) | |||
desired_state = (1<<MD_DISK_ACTIVE) | (1<<MD_DISK_REPLACE MENT); | desired_state = (1<<MD_DISK_ACTIVE) | (1<<MD_DISK_REPLACE MENT); | |||
else | else | |||
desired_state = (1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC); | desired_state = (1<<MD_DISK_ACTIVE) | (1<<MD_DISK_SYNC); | |||
desired_state |= devices[j].i.disk.state & ((1<<MD_DISK_FAILFAST) | ||||
| | ||||
(1<<MD_DISK_WRITEMOST | ||||
LY)); | ||||
if (!devices[j].uptodate) | if (!devices[j].uptodate) | |||
continue; | continue; | |||
devices[j].i.disk.state = desired_state; | devices[j].i.disk.state = desired_state; | |||
if (!(devices[j].i.array.state & 1)) | if (!(devices[j].i.array.state & 1)) | |||
clean = 0; | clean = 0; | |||
if (st->ss->update_super(st, &devices[j].i, "assemble", NULL, | if (st->ss->update_super(st, &devices[j].i, "assemble", NULL, | |||
c->verbose, 0, NULL)) { | c->verbose, 0, NULL)) { | |||
if (c->force) { | if (c->force) { | |||
skipping to change at line 1892 | skipping to change at line 1973 | |||
return 1; | return 1; | |||
} | } | |||
return rv == 2 ? 0 : rv; | return rv == 2 ? 0 : rv; | |||
} | } | |||
int assemble_container_content(struct supertype *st, int mdfd, | int assemble_container_content(struct supertype *st, int mdfd, | |||
struct mdinfo *content, struct context *c, | struct mdinfo *content, struct context *c, | |||
char *chosen_name, int *result) | char *chosen_name, int *result) | |||
{ | { | |||
struct mdinfo *dev, *sra, *dev2; | struct mdinfo *dev, *sra, *dev2; | |||
int working = 0, preexist = 0; | struct assembly_array_info array = {chosen_name, 0, 0, 0}; | |||
int expansion = 0; | ||||
int old_raid_disks; | int old_raid_disks; | |||
int start_reshape; | int start_reshape; | |||
char *avail; | char *avail; | |||
int err; | int err; | |||
int is_raid456, is_clean, all_disks; | ||||
if (sysfs_init(content, mdfd, NULL)) { | if (sysfs_init(content, mdfd, NULL)) { | |||
pr_err("Unable to initialize sysfs\n"); | pr_err("Unable to initialize sysfs\n"); | |||
return 1; | return 1; | |||
} | } | |||
sra = sysfs_read(mdfd, NULL, GET_VERSION|GET_DEVS); | sra = sysfs_read(mdfd, NULL, GET_VERSION|GET_DEVS); | |||
if (sra == NULL || strcmp(sra->text_version, content->text_version) != 0) { | if (sra == NULL || strcmp(sra->text_version, content->text_version) != 0) { | |||
if (content->array.major_version == -1 && | if (content->array.major_version == -1 && | |||
content->array.minor_version == -2 && | content->array.minor_version == -2 && | |||
skipping to change at line 1954 | skipping to change at line 2035 | |||
sysfs_set_str(sra, dev2, "state", "remove"); | sysfs_set_str(sra, dev2, "state", "remove"); | |||
} | } | |||
old_raid_disks = content->array.raid_disks - content->delta_disks; | old_raid_disks = content->array.raid_disks - content->delta_disks; | |||
avail = xcalloc(content->array.raid_disks, 1); | avail = xcalloc(content->array.raid_disks, 1); | |||
for (dev = content->devs; dev; dev = dev->next) { | for (dev = content->devs; dev; dev = dev->next) { | |||
if (dev->disk.raid_disk >= 0) | if (dev->disk.raid_disk >= 0) | |||
avail[dev->disk.raid_disk] = 1; | avail[dev->disk.raid_disk] = 1; | |||
if (sysfs_add_disk(content, dev, 1) == 0) { | if (sysfs_add_disk(content, dev, 1) == 0) { | |||
if (dev->disk.raid_disk >= old_raid_disks && | if (dev->disk.raid_disk >= old_raid_disks && | |||
content->reshape_active) | content->reshape_active) | |||
expansion++; | array.exp_cnt++; | |||
else | else | |||
working++; | array.new_cnt++; | |||
} else if (errno == EEXIST) | } else if (errno == EEXIST) | |||
preexist++; | array.preexist_cnt++; | |||
} | } | |||
sysfs_free(sra); | sysfs_free(sra); | |||
if (working + expansion == 0 && c->runstop <= 0) { | ||||
free(avail); | all_disks = array.new_cnt + array.exp_cnt + array.preexist_cnt; | |||
return 1;/* Nothing new, don't try to start */ | ||||
} | ||||
map_update(NULL, fd2devnm(mdfd), content->text_version, | map_update(NULL, fd2devnm(mdfd), content->text_version, | |||
content->uuid, chosen_name); | content->uuid, chosen_name); | |||
if (content->consistency_policy == CONSISTENCY_POLICY_PPL && | if (content->consistency_policy == CONSISTENCY_POLICY_PPL && | |||
st->ss->validate_ppl) { | st->ss->validate_ppl) { | |||
content->array.state |= 1; | content->array.state |= 1; | |||
err = 0; | err = 0; | |||
for (dev = content->devs; dev; dev = dev->next) { | for (dev = content->devs; dev; dev = dev->next) { | |||
int dfd; | int dfd; | |||
skipping to change at line 2015 | skipping to change at line 2095 | |||
close(dfd); | close(dfd); | |||
if (err) | if (err) | |||
break; | break; | |||
} | } | |||
if (err) { | if (err) { | |||
free(avail); | free(avail); | |||
return err; | return err; | |||
} | } | |||
} else if (c->force) { | ||||
/* Set the array as 'clean' so that we can proceed with starting | ||||
* it even if we don't have all devices. Mdmon doesn't care | ||||
* if the dirty flag is set in metadata, it will start managing | ||||
* it anyway. | ||||
* This is really important for raid456 (RWH case), other levels | ||||
* are started anyway. | ||||
*/ | ||||
content->array.state |= 1; | ||||
} | } | |||
is_raid456 = (content->array.level >= 4 && content->array.level <= 6); | ||||
is_clean = content->array.state & 1; | ||||
if (enough(content->array.level, content->array.raid_disks, | if (enough(content->array.level, content->array.raid_disks, | |||
content->array.layout, content->array.state & 1, avail) == 0) | content->array.layout, is_clean, avail) == 0) { | |||
{ | set_array_assembly_status(c, result, INCR_NO, &array); | |||
if (c->export && result) | ||||
*result |= INCR_NO; | if (c->verbose >= 0 && is_raid456 && !is_clean) | |||
else if (c->verbose >= 0) { | pr_err("Consider --force to start dirty degraded array\n" | |||
pr_err("%s assembled with %d device%s", | ); | |||
chosen_name, preexist + working, | ||||
preexist + working == 1 ? "":"s"); | ||||
if (preexist) | ||||
fprintf(stderr, " (%d new)", working); | ||||
fprintf(stderr, " but not started\n"); | ||||
} | ||||
free(avail); | free(avail); | |||
return 1; | return 1; | |||
} | } | |||
free(avail); | free(avail); | |||
if (c->runstop <= 0 && | if (c->runstop <= 0 && all_disks < content->array.working_disks) { | |||
(working + preexist + expansion) < | ||||
content->array.working_disks) { | set_array_assembly_status(c, result, INCR_UNSAFE, &array); | |||
if (c->export && result) | ||||
*result |= INCR_UNSAFE; | if (c->verbose >= 0 && c->force) | |||
else if (c->verbose >= 0) { | pr_err("Consider --run to start array as degraded.\n"); | |||
pr_err("%s assembled with %d device%s", | ||||
chosen_name, preexist + working, | ||||
preexist + working == 1 ? "":"s"); | ||||
if (preexist) | ||||
fprintf(stderr, " (%d new)", working); | ||||
fprintf(stderr, " but not safe to start\n"); | ||||
} | ||||
return 1; | return 1; | |||
} | } | |||
if (is_raid456 && content->resync_start != MaxSector && c->force && | ||||
all_disks < content->array.raid_disks) { | ||||
content->resync_start = MaxSector; | ||||
err = sysfs_set_num(content, NULL, "resync_start", MaxSector); | ||||
if (err) | ||||
return 1; | ||||
pr_err("%s array state forced to clean. It may cause data corrupt | ||||
ion.\n", | ||||
chosen_name); | ||||
} | ||||
/* | ||||
* Before activating the array, perform extra steps required | ||||
* to configure the internal write-intent bitmap. | ||||
*/ | ||||
if (content->consistency_policy == CONSISTENCY_POLICY_BITMAP && | ||||
st->ss->set_bitmap) | ||||
st->ss->set_bitmap(st, content); | ||||
if (start_reshape) { | if (start_reshape) { | |||
int spare = content->array.raid_disks + expansion; | int spare = content->array.raid_disks + array.exp_cnt; | |||
if (restore_backup(st, content, | if (restore_backup(st, content, | |||
working, | array.new_cnt, | |||
spare, &c->backup_file, c->verbose) == 1) | spare, &c->backup_file, c->verbose) == 1) | |||
return 1; | return 1; | |||
err = sysfs_set_str(content, NULL, | if (content->reshape_progress == 0) { | |||
"array_state", "readonly"); | /* If reshape progress is 0 - we are assembling the | |||
* array that was stopped, before reshape has started. | ||||
* Array needs to be started as active, Grow_continue() | ||||
* will start the reshape. | ||||
*/ | ||||
sysfs_set_num(content, NULL, "reshape_position", | ||||
MaxSector); | ||||
err = sysfs_set_str(content, NULL, | ||||
"array_state", "active"); | ||||
sysfs_set_num(content, NULL, "reshape_position", 0); | ||||
} else { | ||||
err = sysfs_set_str(content, NULL, | ||||
"array_state", "readonly"); | ||||
} | ||||
if (err) | if (err) | |||
return 1; | return 1; | |||
if (st->ss->external) { | if (st->ss->external) { | |||
if (!mdmon_running(st->container_devnm)) | if (!mdmon_running(st->container_devnm)) | |||
start_mdmon(st->container_devnm); | start_mdmon(st->container_devnm); | |||
ping_monitor(st->container_devnm); | ping_monitor(st->container_devnm); | |||
if (mdmon_running(st->container_devnm) && | if (mdmon_running(st->container_devnm) && | |||
st->update_tail == NULL) | st->update_tail == NULL) | |||
st->update_tail = &st->updates; | st->update_tail = &st->updates; | |||
skipping to change at line 2102 | skipping to change at line 2216 | |||
sysfs_set_safemode(content, content->safe_mode_delay); | sysfs_set_safemode(content, content->safe_mode_delay); | |||
/* Block subarray here if it is not reshaped now | /* Block subarray here if it is not reshaped now | |||
* It has be blocked a little later to allow mdmon to switch in | * It has be blocked a little later to allow mdmon to switch in | |||
* in to R/W state | * in to R/W state | |||
*/ | */ | |||
if (st->ss->external && content->recovery_blocked && | if (st->ss->external && content->recovery_blocked && | |||
!start_reshape) | !start_reshape) | |||
block_subarray(content); | block_subarray(content); | |||
if (c->export && result) { | if (err) | |||
if (err) | set_array_assembly_status(c, result, INCR_NO, &array); | |||
*result |= INCR_NO; | else { | |||
else | set_array_assembly_status(c, result, INCR_YES, &array); | |||
*result |= INCR_YES; | ||||
} else if (c->verbose >= 0) { | ||||
if (err) | ||||
pr_err("array %s now has %d device%s", | ||||
chosen_name, working + preexist, | ||||
working + preexist == 1 ? "":"s"); | ||||
else | ||||
pr_err("Started %s with %d device%s", | ||||
chosen_name, working + preexist, | ||||
working + preexist == 1 ? "":"s"); | ||||
if (preexist) | ||||
fprintf(stderr, " (%d new)", working); | ||||
if (expansion) | ||||
fprintf(stderr, " ( + %d for expansion)", | ||||
expansion); | ||||
fprintf(stderr, "\n"); | ||||
} | ||||
if (!err) | ||||
wait_for(chosen_name, mdfd); | wait_for(chosen_name, mdfd); | |||
sysfs_rules_apply(chosen_name, content); | ||||
} | ||||
return err; | return err; | |||
/* FIXME should have an O_EXCL and wait for read-auto */ | /* FIXME should have an O_EXCL and wait for read-auto */ | |||
} | } | |||
End of changes. 32 change blocks. | ||||
68 lines changed or deleted | 176 lines changed or added |