Merge branch 'master' of git://github.com/djbw/mdadm
This commit is contained in:
commit
1538aca5cb
8
Create.c
8
Create.c
|
@ -235,9 +235,13 @@ int Create(struct supertype *st, char *mddev,
|
||||||
case 6:
|
case 6:
|
||||||
case 0:
|
case 0:
|
||||||
if (chunk == 0) {
|
if (chunk == 0) {
|
||||||
chunk = 512;
|
if (st && st->ss->default_chunk)
|
||||||
|
chunk = st->ss->default_chunk(st);
|
||||||
|
|
||||||
|
chunk = chunk ? : 512;
|
||||||
|
|
||||||
if (verbose > 0)
|
if (verbose > 0)
|
||||||
fprintf(stderr, Name ": chunk size defaults to 512K\n");
|
fprintf(stderr, Name ": chunk size defaults to %dK\n", chunk);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LEVEL_LINEAR:
|
case LEVEL_LINEAR:
|
||||||
|
|
20
Grow.c
20
Grow.c
|
@ -546,7 +546,13 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
sra = sysfs_read(fd, 0, GET_LEVEL);
|
sra = sysfs_read(fd, 0, GET_LEVEL);
|
||||||
frozen = freeze_array(sra);
|
if (sra)
|
||||||
|
frozen = freeze_array(sra);
|
||||||
|
else {
|
||||||
|
fprintf(stderr, Name ": failed to read sysfs parameters for %s\n",
|
||||||
|
devname);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
if (frozen < 0) {
|
if (frozen < 0) {
|
||||||
fprintf(stderr, Name ": %s is performing resync/recovery and cannot"
|
fprintf(stderr, Name ": %s is performing resync/recovery and cannot"
|
||||||
" be reshaped\n", devname);
|
" be reshaped\n", devname);
|
||||||
|
@ -1970,6 +1976,12 @@ int Grow_continue(int mdfd, struct supertype *st, struct mdinfo *info,
|
||||||
int cache;
|
int cache;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
|
|
||||||
|
sra = sysfs_read(-1, devname2devnum(info->sys_name),
|
||||||
|
GET_COMPONENT|GET_DEVS|GET_OFFSET|GET_STATE|
|
||||||
|
GET_CACHE);
|
||||||
|
if (!sra)
|
||||||
|
return 1;
|
||||||
|
|
||||||
err = sysfs_set_str(info, NULL, "array_state", "readonly");
|
err = sysfs_set_str(info, NULL, "array_state", "readonly");
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
@ -1990,7 +2002,6 @@ int Grow_continue(int mdfd, struct supertype *st, struct mdinfo *info,
|
||||||
ochunk = info->array.chunk_size;
|
ochunk = info->array.chunk_size;
|
||||||
nchunk = info->new_chunk;
|
nchunk = info->new_chunk;
|
||||||
|
|
||||||
|
|
||||||
a = (ochunk/512) * odata;
|
a = (ochunk/512) * odata;
|
||||||
b = (nchunk/512) * ndata;
|
b = (nchunk/512) * ndata;
|
||||||
/* Find GCD */
|
/* Find GCD */
|
||||||
|
@ -2003,11 +2014,6 @@ int Grow_continue(int mdfd, struct supertype *st, struct mdinfo *info,
|
||||||
/* LCM == product / GCD */
|
/* LCM == product / GCD */
|
||||||
blocks = (ochunk/512) * (nchunk/512) * odata * ndata / a;
|
blocks = (ochunk/512) * (nchunk/512) * odata * ndata / a;
|
||||||
|
|
||||||
sra = sysfs_read(-1, devname2devnum(info->sys_name),
|
|
||||||
GET_COMPONENT|GET_DEVS|GET_OFFSET|GET_STATE|
|
|
||||||
GET_CACHE);
|
|
||||||
|
|
||||||
|
|
||||||
if (ndata == odata)
|
if (ndata == odata)
|
||||||
while (blocks * 32 < sra->component_size &&
|
while (blocks * 32 < sra->component_size &&
|
||||||
blocks < 16*1024*2)
|
blocks < 16*1024*2)
|
||||||
|
|
|
@ -385,6 +385,8 @@ int Incremental(char *devname, int verbose, int runstop,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sra = sysfs_read(mdfd, fd2devnum(mdfd), (GET_DEVS | GET_STATE));
|
sra = sysfs_read(mdfd, fd2devnum(mdfd), (GET_DEVS | GET_STATE));
|
||||||
|
if (!sra)
|
||||||
|
return 2;
|
||||||
|
|
||||||
if (sra->devs) {
|
if (sra->devs) {
|
||||||
sprintf(dn, "%d:%d", sra->devs->disk.major,
|
sprintf(dn, "%d:%d", sra->devs->disk.major,
|
||||||
|
@ -602,6 +604,9 @@ static int count_active(struct supertype *st, int mdfd, char **availp,
|
||||||
struct mdinfo *sra = sysfs_read(mdfd, -1, GET_DEVS | GET_STATE);
|
struct mdinfo *sra = sysfs_read(mdfd, -1, GET_DEVS | GET_STATE);
|
||||||
char *avail = NULL;
|
char *avail = NULL;
|
||||||
|
|
||||||
|
if (!sra)
|
||||||
|
return 0;
|
||||||
|
|
||||||
for (d = sra->devs ; d ; d = d->next) {
|
for (d = sra->devs ; d ; d = d->next) {
|
||||||
char dn[30];
|
char dn[30];
|
||||||
int dfd;
|
int dfd;
|
||||||
|
|
78
Kill.c
78
Kill.c
|
@ -79,3 +79,81 @@ int Kill(char *dev, struct supertype *st, int force, int quiet, int noexcl)
|
||||||
close(fd);
|
close(fd);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Kill_subarray(char *dev, char *subarray, int quiet)
|
||||||
|
{
|
||||||
|
/* Delete a subarray out of a container, the subarry must be
|
||||||
|
* inactive. The subarray string must be a subarray index
|
||||||
|
* number.
|
||||||
|
*
|
||||||
|
* 0 = successfully deleted subarray from all container members
|
||||||
|
* 1 = failed to sync metadata to one or more devices
|
||||||
|
* 2 = failed to find the container, subarray, or other resource
|
||||||
|
* issue
|
||||||
|
*/
|
||||||
|
struct supertype supertype, *st = &supertype;
|
||||||
|
int fd, rv = 2;
|
||||||
|
|
||||||
|
memset(st, 0, sizeof(*st));
|
||||||
|
|
||||||
|
if (snprintf(st->subarray, sizeof(st->subarray), "%s", subarray) >=
|
||||||
|
sizeof(st->subarray)) {
|
||||||
|
if (!quiet)
|
||||||
|
fprintf(stderr,
|
||||||
|
Name ": Input overflow for subarray '%s' > %zu bytes\n",
|
||||||
|
subarray, sizeof(st->subarray) - 1);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open_subarray(dev, st, quiet);
|
||||||
|
if (fd < 0)
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
if (!st->ss->kill_subarray) {
|
||||||
|
if (!quiet)
|
||||||
|
fprintf(stderr,
|
||||||
|
Name ": Operation not supported for %s metadata\n",
|
||||||
|
st->ss->name);
|
||||||
|
goto free_super;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_subarray_active(subarray, st->devname)) {
|
||||||
|
if (!quiet)
|
||||||
|
fprintf(stderr,
|
||||||
|
Name ": Subarray-%s still active, aborting\n",
|
||||||
|
subarray);
|
||||||
|
goto free_super;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mdmon_running(st->devnum))
|
||||||
|
st->update_tail = &st->updates;
|
||||||
|
|
||||||
|
/* ok we've found our victim, drop the axe */
|
||||||
|
rv = st->ss->kill_subarray(st);
|
||||||
|
if (rv) {
|
||||||
|
if (!quiet)
|
||||||
|
fprintf(stderr,
|
||||||
|
Name ": Failed to delete subarray-%s from %s\n",
|
||||||
|
subarray, dev);
|
||||||
|
goto free_super;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME these routines do not report success/failure */
|
||||||
|
if (st->update_tail)
|
||||||
|
flush_metadata_updates(st);
|
||||||
|
else
|
||||||
|
st->ss->sync_metadata(st);
|
||||||
|
|
||||||
|
if (!quiet)
|
||||||
|
fprintf(stderr,
|
||||||
|
Name ": Deleted subarray-%s from %s, UUIDs may have changed\n",
|
||||||
|
subarray, dev);
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
|
||||||
|
free_super:
|
||||||
|
st->ss->free_super(st);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
3
Makefile
3
Makefile
|
@ -157,8 +157,9 @@ mdadm.O2 : $(SRCS) mdadm.h mdmon.O2
|
||||||
mdmon.O2 : $(MON_SRCS) mdadm.h mdmon.h
|
mdmon.O2 : $(MON_SRCS) mdadm.h mdmon.h
|
||||||
$(CC) -o mdmon.O2 $(CFLAGS) -DHAVE_STDINT_H -O2 -D_FORTIFY_SOURCE=2 $(MON_SRCS)
|
$(CC) -o mdmon.O2 $(CFLAGS) -DHAVE_STDINT_H -O2 -D_FORTIFY_SOURCE=2 $(MON_SRCS)
|
||||||
|
|
||||||
|
# use '-z now' to guarantee no dynamic linker interactions with the monitor thread
|
||||||
mdmon : $(MON_OBJS)
|
mdmon : $(MON_OBJS)
|
||||||
$(CC) $(LDFLAGS) -o mdmon $(MON_OBJS) $(LDLIBS)
|
$(CC) $(LDFLAGS) -z now -o mdmon $(MON_OBJS) $(LDLIBS)
|
||||||
msg.o: msg.c msg.h
|
msg.o: msg.c msg.h
|
||||||
|
|
||||||
test_stripe : restripe.c mdadm.h
|
test_stripe : restripe.c mdadm.h
|
||||||
|
|
53
Manage.c
53
Manage.c
|
@ -1005,4 +1005,57 @@ int autodetect(void)
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Update_subarray(char *dev, char *subarray, char *update, mddev_ident_t ident, int quiet)
|
||||||
|
{
|
||||||
|
struct supertype supertype, *st = &supertype;
|
||||||
|
int fd, rv = 2;
|
||||||
|
|
||||||
|
memset(st, 0, sizeof(*st));
|
||||||
|
if (snprintf(st->subarray, sizeof(st->subarray), "%s", subarray) >=
|
||||||
|
sizeof(st->subarray)) {
|
||||||
|
if (!quiet)
|
||||||
|
fprintf(stderr,
|
||||||
|
Name ": Input overflow for subarray '%s' > %zu bytes\n",
|
||||||
|
subarray, sizeof(st->subarray) - 1);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open_subarray(dev, st, quiet);
|
||||||
|
if (fd < 0)
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
if (!st->ss->update_subarray) {
|
||||||
|
if (!quiet)
|
||||||
|
fprintf(stderr,
|
||||||
|
Name ": Operation not supported for %s metadata\n",
|
||||||
|
st->ss->name);
|
||||||
|
goto free_super;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mdmon_running(st->devnum))
|
||||||
|
st->update_tail = &st->updates;
|
||||||
|
|
||||||
|
rv = st->ss->update_subarray(st, update, ident);
|
||||||
|
|
||||||
|
if (rv) {
|
||||||
|
if (!quiet)
|
||||||
|
fprintf(stderr, Name ": Failed to update %s of subarray-%s in %s\n",
|
||||||
|
update, subarray, dev);
|
||||||
|
} else if (st->update_tail)
|
||||||
|
flush_metadata_updates(st);
|
||||||
|
else
|
||||||
|
st->ss->sync_metadata(st);
|
||||||
|
|
||||||
|
if (rv == 0 && strcmp(update, "name") == 0 && !quiet)
|
||||||
|
fprintf(stderr,
|
||||||
|
Name ": Updated subarray-%s name from %s, UUIDs may have changed\n",
|
||||||
|
subarray, dev);
|
||||||
|
|
||||||
|
free_super:
|
||||||
|
st->ss->free_super(st);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
2
ReadMe.c
2
ReadMe.c
|
@ -108,6 +108,8 @@ struct option long_options[] = {
|
||||||
{"examine-bitmap", 0, 0, 'X'},
|
{"examine-bitmap", 0, 0, 'X'},
|
||||||
{"auto-detect", 0, 0, AutoDetect},
|
{"auto-detect", 0, 0, AutoDetect},
|
||||||
{"detail-platform", 0, 0, DetailPlatform},
|
{"detail-platform", 0, 0, DetailPlatform},
|
||||||
|
{"kill-subarray", 1, 0, KillSubarray},
|
||||||
|
{"update-subarray", 1, 0, UpdateSubarray},
|
||||||
|
|
||||||
/* synonyms */
|
/* synonyms */
|
||||||
{"monitor", 0, 0, 'F'},
|
{"monitor", 0, 0, 'F'},
|
||||||
|
|
|
@ -315,7 +315,7 @@ static void manage_container(struct mdstat_ent *mdstat,
|
||||||
* To see what is removed and what is added.
|
* To see what is removed and what is added.
|
||||||
* These need to be remove from, or added to, the array
|
* These need to be remove from, or added to, the array
|
||||||
*/
|
*/
|
||||||
mdi = sysfs_read(-1, mdstat->devnum, GET_DEVS|SKIP_GONE_DEVS);
|
mdi = sysfs_read(-1, mdstat->devnum, GET_DEVS);
|
||||||
if (!mdi) {
|
if (!mdi) {
|
||||||
/* invalidate the current count so we can try again */
|
/* invalidate the current count so we can try again */
|
||||||
container->devcnt = -1;
|
container->devcnt = -1;
|
||||||
|
@ -540,6 +540,7 @@ static void manage_new(struct mdstat_ent *mdstat,
|
||||||
new->info.state_fd = sysfs_open(new->devnum, NULL, "array_state");
|
new->info.state_fd = sysfs_open(new->devnum, NULL, "array_state");
|
||||||
new->resync_start_fd = sysfs_open(new->devnum, NULL, "resync_start");
|
new->resync_start_fd = sysfs_open(new->devnum, NULL, "resync_start");
|
||||||
new->metadata_fd = sysfs_open(new->devnum, NULL, "metadata_version");
|
new->metadata_fd = sysfs_open(new->devnum, NULL, "metadata_version");
|
||||||
|
new->sync_completed_fd = sysfs_open(new->devnum, NULL, "sync_completed");
|
||||||
dprintf("%s: inst: %d action: %d state: %d\n", __func__, atoi(inst),
|
dprintf("%s: inst: %d action: %d state: %d\n", __func__, atoi(inst),
|
||||||
new->action_fd, new->info.state_fd);
|
new->action_fd, new->info.state_fd);
|
||||||
|
|
||||||
|
|
|
@ -368,7 +368,7 @@ void RebuildMap(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (md = mdstat ; md ; md = md->next) {
|
for (md = mdstat ; md ; md = md->next) {
|
||||||
struct mdinfo *sra = sysfs_read(-1, md->devnum, GET_DEVS|SKIP_GONE_DEVS);
|
struct mdinfo *sra = sysfs_read(-1, md->devnum, GET_DEVS);
|
||||||
struct mdinfo *sd;
|
struct mdinfo *sd;
|
||||||
|
|
||||||
if (!sra)
|
if (!sra)
|
||||||
|
@ -486,7 +486,8 @@ void RebuildMap(void)
|
||||||
for (md = mdstat ; md ; md = md->next) {
|
for (md = mdstat ; md ; md = md->next) {
|
||||||
struct mdinfo *sra = sysfs_read(-1, md->devnum,
|
struct mdinfo *sra = sysfs_read(-1, md->devnum,
|
||||||
GET_VERSION);
|
GET_VERSION);
|
||||||
sysfs_uevent(sra, "change");
|
if (sra)
|
||||||
|
sysfs_uevent(sra, "change");
|
||||||
sysfs_free(sra);
|
sysfs_free(sra);
|
||||||
}
|
}
|
||||||
map_free(map);
|
map_free(map);
|
||||||
|
|
47
mdadm.8.in
47
mdadm.8.in
|
@ -1193,6 +1193,24 @@ overwritten with zeros. With
|
||||||
the block where the superblock would be is overwritten even if it
|
the block where the superblock would be is overwritten even if it
|
||||||
doesn't appear to be valid.
|
doesn't appear to be valid.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B \-\-kill\-subarray=
|
||||||
|
If the device is a container and the argument to \-\-kill\-subarray
|
||||||
|
specifies an inactive subarray in the container, then the subarray is
|
||||||
|
deleted. Deleting all subarrays will leave an 'empty-container' or
|
||||||
|
spare superblock on the drives. See \-\-zero\-superblock for completely
|
||||||
|
removing a superblock. Note that some formats depend on the subarray
|
||||||
|
index for generating a UUID, this command will fail if it would change
|
||||||
|
the UUID of an active subarray.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B \-\-update\-subarray=
|
||||||
|
If the device is a container and the argument to \-\-update\-subarray
|
||||||
|
specifies a subarray in the container, then attempt to update the given
|
||||||
|
superblock field in the subarray. See below in
|
||||||
|
.B MISC MODE
|
||||||
|
for details.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR \-t ", " \-\-test
|
.BR \-t ", " \-\-test
|
||||||
When used with
|
When used with
|
||||||
|
@ -1216,14 +1234,11 @@ listed, otherwise it will return failure.
|
||||||
For each md device given, or each device in /proc/mdstat if
|
For each md device given, or each device in /proc/mdstat if
|
||||||
.B \-\-scan
|
.B \-\-scan
|
||||||
is given, arrange for the array to be marked clean as soon as possible.
|
is given, arrange for the array to be marked clean as soon as possible.
|
||||||
Also, quiesce resync so that the monitor for external metadata arrays
|
|
||||||
(mdmon) has an opportunity to checkpoint the resync position.
|
|
||||||
.I mdadm
|
.I mdadm
|
||||||
will return with success if the array uses external metadata and we
|
will return with success if the array uses external metadata and we
|
||||||
successfully waited. For native arrays this returns immediately as the
|
successfully waited. For native arrays this returns immediately as the
|
||||||
kernel handles both dirty-clean transitions and resync checkpointing in
|
kernel handles dirty-clean transitions at shutdown. No action is taken
|
||||||
the kernel at shutdown. No action is taken if safe-mode handling is
|
if safe-mode handling is disabled.
|
||||||
disabled.
|
|
||||||
|
|
||||||
.SH For Incremental Assembly mode:
|
.SH For Incremental Assembly mode:
|
||||||
.TP
|
.TP
|
||||||
|
@ -1775,6 +1790,28 @@ metadata is platform independent
|
||||||
metadata failed to find its platform components on this system
|
metadata failed to find its platform components on this system
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B \-\-update\-subarray=
|
||||||
|
If the device is a container and the argument to \-\-update\-subarray
|
||||||
|
specifies a subarray in the container, then attempt to update the given
|
||||||
|
superblock field in the subarray. Similar to updating an array in
|
||||||
|
"assemble" mode, the field to update is selected by
|
||||||
|
.B \-U
|
||||||
|
or
|
||||||
|
.B \-\-update=
|
||||||
|
option. Currently only
|
||||||
|
.B name
|
||||||
|
is supported.
|
||||||
|
|
||||||
|
The
|
||||||
|
.B name
|
||||||
|
option updates the subarray name in the metadata, it may not affect the
|
||||||
|
device node name or the device node symlink until the subarray is
|
||||||
|
re\-assembled. If updating
|
||||||
|
.B name
|
||||||
|
would change the UUID of an active subarray this operation is blocked,
|
||||||
|
and the command will end in an error.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B \-\-examine
|
.B \-\-examine
|
||||||
The device should be a component of an md array.
|
The device should be a component of an md array.
|
||||||
|
|
47
mdadm.c
47
mdadm.c
|
@ -103,6 +103,7 @@ int main(int argc, char *argv[])
|
||||||
int dosyslog = 0;
|
int dosyslog = 0;
|
||||||
int rebuild_map = 0;
|
int rebuild_map = 0;
|
||||||
int auto_update_home = 0;
|
int auto_update_home = 0;
|
||||||
|
char *subarray = NULL;
|
||||||
|
|
||||||
int print_help = 0;
|
int print_help = 0;
|
||||||
FILE *outf;
|
FILE *outf;
|
||||||
|
@ -216,6 +217,15 @@ int main(int argc, char *argv[])
|
||||||
case 'W':
|
case 'W':
|
||||||
case Waitclean:
|
case Waitclean:
|
||||||
case DetailPlatform:
|
case DetailPlatform:
|
||||||
|
case KillSubarray:
|
||||||
|
case UpdateSubarray:
|
||||||
|
if (opt == KillSubarray || opt == UpdateSubarray) {
|
||||||
|
if (subarray) {
|
||||||
|
fprintf(stderr, Name ": subarray can only be specified once\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
subarray = optarg;
|
||||||
|
}
|
||||||
case 'K': if (!mode) newmode = MISC; break;
|
case 'K': if (!mode) newmode = MISC; break;
|
||||||
}
|
}
|
||||||
if (mode && newmode == mode) {
|
if (mode && newmode == mode) {
|
||||||
|
@ -589,11 +599,16 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
case O(CREATE,'N'):
|
case O(CREATE,'N'):
|
||||||
case O(ASSEMBLE,'N'):
|
case O(ASSEMBLE,'N'):
|
||||||
|
case O(MISC,'N'):
|
||||||
if (ident.name[0]) {
|
if (ident.name[0]) {
|
||||||
fprintf(stderr, Name ": name cannot be set twice. "
|
fprintf(stderr, Name ": name cannot be set twice. "
|
||||||
"Second value %s.\n", optarg);
|
"Second value %s.\n", optarg);
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
|
if (mode == MISC && !subarray) {
|
||||||
|
fprintf(stderr, Name ": -N/--name only valid with --update-subarray in misc mode\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
if (strlen(optarg) > 32) {
|
if (strlen(optarg) > 32) {
|
||||||
fprintf(stderr, Name ": name '%s' is too long, 32 chars max.\n",
|
fprintf(stderr, Name ": name '%s' is too long, 32 chars max.\n",
|
||||||
optarg);
|
optarg);
|
||||||
|
@ -620,11 +635,16 @@ int main(int argc, char *argv[])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case O(ASSEMBLE,'U'): /* update the superblock */
|
case O(ASSEMBLE,'U'): /* update the superblock */
|
||||||
|
case O(MISC,'U'):
|
||||||
if (update) {
|
if (update) {
|
||||||
fprintf(stderr, Name ": Can only update one aspect of superblock, both %s and %s given.\n",
|
fprintf(stderr, Name ": Can only update one aspect of superblock, both %s and %s given.\n",
|
||||||
update, optarg);
|
update, optarg);
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
|
if (mode == MISC && !subarray) {
|
||||||
|
fprintf(stderr, Name ": Only subarrays can be updated in misc mode\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
update = optarg;
|
update = optarg;
|
||||||
if (strcmp(update, "sparc2.2")==0)
|
if (strcmp(update, "sparc2.2")==0)
|
||||||
continue;
|
continue;
|
||||||
|
@ -812,10 +832,21 @@ int main(int argc, char *argv[])
|
||||||
case O(MISC,'W'):
|
case O(MISC,'W'):
|
||||||
case O(MISC, Waitclean):
|
case O(MISC, Waitclean):
|
||||||
case O(MISC, DetailPlatform):
|
case O(MISC, DetailPlatform):
|
||||||
|
case O(MISC, KillSubarray):
|
||||||
|
case O(MISC, UpdateSubarray):
|
||||||
if (devmode && devmode != opt &&
|
if (devmode && devmode != opt &&
|
||||||
(devmode == 'E' || (opt == 'E' && devmode != 'Q'))) {
|
(devmode == 'E' || (opt == 'E' && devmode != 'Q'))) {
|
||||||
fprintf(stderr, Name ": --examine/-E cannot be given with -%c\n",
|
fprintf(stderr, Name ": --examine/-E cannot be given with ");
|
||||||
devmode =='E'?opt:devmode);
|
if (devmode == 'E') {
|
||||||
|
if (option_index >= 0)
|
||||||
|
fprintf(stderr, "--%s\n",
|
||||||
|
long_options[option_index].name);
|
||||||
|
else
|
||||||
|
fprintf(stderr, "-%c\n", opt);
|
||||||
|
} else if (isalpha(devmode))
|
||||||
|
fprintf(stderr, "-%c\n", devmode);
|
||||||
|
else
|
||||||
|
fprintf(stderr, "previous option\n");
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
devmode = opt;
|
devmode = opt;
|
||||||
|
@ -1408,6 +1439,18 @@ int main(int argc, char *argv[])
|
||||||
rv |= Wait(dv->devname); continue;
|
rv |= Wait(dv->devname); continue;
|
||||||
case Waitclean:
|
case Waitclean:
|
||||||
rv |= WaitClean(dv->devname, -1, verbose-quiet); continue;
|
rv |= WaitClean(dv->devname, -1, verbose-quiet); continue;
|
||||||
|
case KillSubarray:
|
||||||
|
rv |= Kill_subarray(dv->devname, subarray, quiet);
|
||||||
|
continue;
|
||||||
|
case UpdateSubarray:
|
||||||
|
if (update == NULL) {
|
||||||
|
fprintf(stderr,
|
||||||
|
Name ": -U/--update must be specified with --update-subarray\n");
|
||||||
|
rv |= 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
rv |= Update_subarray(dv->devname, subarray, update, &ident, quiet);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
mdfd = open_mddev(dv->devname, 1);
|
mdfd = open_mddev(dv->devname, 1);
|
||||||
if (mdfd>=0) {
|
if (mdfd>=0) {
|
||||||
|
|
18
mdadm.h
18
mdadm.h
|
@ -260,6 +260,7 @@ extern char Version[], Usage[], Help[], OptionHelp[],
|
||||||
|
|
||||||
/* for option that don't have short equivilents, we assign arbitrary
|
/* for option that don't have short equivilents, we assign arbitrary
|
||||||
* small numbers. '1' means an undecorated option, so we start at '2'.
|
* small numbers. '1' means an undecorated option, so we start at '2'.
|
||||||
|
* (note we must stop before we get to 65 i.e. 'A')
|
||||||
*/
|
*/
|
||||||
enum special_options {
|
enum special_options {
|
||||||
AssumeClean = 2,
|
AssumeClean = 2,
|
||||||
|
@ -268,13 +269,15 @@ enum special_options {
|
||||||
ReAdd,
|
ReAdd,
|
||||||
NoDegraded,
|
NoDegraded,
|
||||||
Sparc22,
|
Sparc22,
|
||||||
BackupFile,
|
BackupFile, /* 8 */
|
||||||
HomeHost,
|
HomeHost,
|
||||||
AutoHomeHost,
|
AutoHomeHost,
|
||||||
Symlinks,
|
Symlinks,
|
||||||
AutoDetect,
|
AutoDetect,
|
||||||
Waitclean,
|
Waitclean,
|
||||||
DetailPlatform,
|
DetailPlatform,
|
||||||
|
KillSubarray,
|
||||||
|
UpdateSubarray, /* 16 */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* structures read from config file */
|
/* structures read from config file */
|
||||||
|
@ -409,7 +412,6 @@ enum sysfs_read_flags {
|
||||||
GET_SIZE = (1 << 12),
|
GET_SIZE = (1 << 12),
|
||||||
GET_STATE = (1 << 13),
|
GET_STATE = (1 << 13),
|
||||||
GET_ERROR = (1 << 14),
|
GET_ERROR = (1 << 14),
|
||||||
SKIP_GONE_DEVS = (1 << 15),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* If fd >= 0, get the array it is open on,
|
/* If fd >= 0, get the array it is open on,
|
||||||
|
@ -616,6 +618,12 @@ extern struct superswitch {
|
||||||
struct mdinfo *(*container_content)(struct supertype *st);
|
struct mdinfo *(*container_content)(struct supertype *st);
|
||||||
/* Allow a metadata handler to override mdadm's default layouts */
|
/* Allow a metadata handler to override mdadm's default layouts */
|
||||||
int (*default_layout)(int level); /* optional */
|
int (*default_layout)(int level); /* optional */
|
||||||
|
/* query the supertype for default chunk size */
|
||||||
|
int (*default_chunk)(struct supertype *st); /* optional */
|
||||||
|
/* Permit subarray's to be deleted from inactive containers */
|
||||||
|
int (*kill_subarray)(struct supertype *st); /* optional */
|
||||||
|
/* Permit subarray's to be modified */
|
||||||
|
int (*update_subarray)(struct supertype *st, char *update, mddev_ident_t ident); /* optional */
|
||||||
|
|
||||||
/* for mdmon */
|
/* for mdmon */
|
||||||
int (*open_new)(struct supertype *c, struct active_array *a,
|
int (*open_new)(struct supertype *c, struct active_array *a,
|
||||||
|
@ -812,6 +820,8 @@ extern int Monitor(mddev_dev_t devlist,
|
||||||
int dosyslog, int test, char *pidfile, int increments);
|
int dosyslog, int test, char *pidfile, int increments);
|
||||||
|
|
||||||
extern int Kill(char *dev, struct supertype *st, int force, int quiet, int noexcl);
|
extern int Kill(char *dev, struct supertype *st, int force, int quiet, int noexcl);
|
||||||
|
extern int Kill_subarray(char *dev, char *subarray, int quiet);
|
||||||
|
extern int Update_subarray(char *dev, char *subarray, char *update, mddev_ident_t ident, int quiet);
|
||||||
extern int Wait(char *dev);
|
extern int Wait(char *dev);
|
||||||
extern int WaitClean(char *dev, int sock, int verbose);
|
extern int WaitClean(char *dev, int sock, int verbose);
|
||||||
|
|
||||||
|
@ -918,6 +928,10 @@ extern int create_mddev(char *dev, char *name, int autof, int trustworthy,
|
||||||
#define METADATA 3
|
#define METADATA 3
|
||||||
extern int open_mddev(char *dev, int report_errors);
|
extern int open_mddev(char *dev, int report_errors);
|
||||||
extern int open_container(int fd);
|
extern int open_container(int fd);
|
||||||
|
extern int is_container_member(struct mdstat_ent *ent, char *devname);
|
||||||
|
extern int is_subarray_active(char *subarray, char *devname);
|
||||||
|
extern int open_subarray(char *dev, struct supertype *st, int quiet);
|
||||||
|
extern struct superswitch *version_to_superswitch(char *vers);
|
||||||
|
|
||||||
extern char *pid_dir;
|
extern char *pid_dir;
|
||||||
extern int mdmon_running(int devnum);
|
extern int mdmon_running(int devnum);
|
||||||
|
|
28
mdmon.c
28
mdmon.c
|
@ -104,15 +104,6 @@ int __clone2(int (*fn)(void *),
|
||||||
return mon_tid;
|
return mon_tid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct superswitch *find_metadata_methods(char *vers)
|
|
||||||
{
|
|
||||||
if (strcmp(vers, "ddf") == 0)
|
|
||||||
return &super_ddf;
|
|
||||||
if (strcmp(vers, "imsm") == 0)
|
|
||||||
return &super_imsm;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int make_pidfile(char *devname)
|
static int make_pidfile(char *devname)
|
||||||
{
|
{
|
||||||
char path[100];
|
char path[100];
|
||||||
|
@ -136,18 +127,6 @@ static int make_pidfile(char *devname)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int is_container_member(struct mdstat_ent *mdstat, char *container)
|
|
||||||
{
|
|
||||||
if (mdstat->metadata_version == NULL ||
|
|
||||||
strncmp(mdstat->metadata_version, "external:", 9) != 0 ||
|
|
||||||
!is_subarray(mdstat->metadata_version+9) ||
|
|
||||||
strncmp(mdstat->metadata_version+10, container, strlen(container)) != 0 ||
|
|
||||||
mdstat->metadata_version[10+strlen(container)] != '/')
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void try_kill_monitor(pid_t pid, char *devname, int sock)
|
static void try_kill_monitor(pid_t pid, char *devname, int sock)
|
||||||
{
|
{
|
||||||
char buf[100];
|
char buf[100];
|
||||||
|
@ -394,8 +373,7 @@ static int mdmon(char *devname, int devnum, int must_fork, int takeover)
|
||||||
exit(3);
|
exit(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
mdi = sysfs_read(mdfd, container->devnum,
|
mdi = sysfs_read(mdfd, container->devnum, GET_VERSION|GET_LEVEL|GET_DEVS);
|
||||||
GET_VERSION|GET_LEVEL|GET_DEVS|SKIP_GONE_DEVS);
|
|
||||||
|
|
||||||
if (!mdi) {
|
if (!mdi) {
|
||||||
fprintf(stderr, "mdmon: failed to load sysfs info for %s\n",
|
fprintf(stderr, "mdmon: failed to load sysfs info for %s\n",
|
||||||
|
@ -414,9 +392,9 @@ static int mdmon(char *devname, int devnum, int must_fork, int takeover)
|
||||||
exit(3);
|
exit(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
container->ss = find_metadata_methods(mdi->text_version);
|
container->ss = version_to_superswitch(mdi->text_version);
|
||||||
if (container->ss == NULL) {
|
if (container->ss == NULL) {
|
||||||
fprintf(stderr, "mdmon: %s uses unknown metadata: %s\n",
|
fprintf(stderr, "mdmon: %s uses unsupported metadata: %s\n",
|
||||||
devname, mdi->text_version);
|
devname, mdi->text_version);
|
||||||
exit(3);
|
exit(3);
|
||||||
}
|
}
|
||||||
|
|
9
mdmon.h
9
mdmon.h
|
@ -32,6 +32,15 @@ struct active_array {
|
||||||
int action_fd;
|
int action_fd;
|
||||||
int resync_start_fd;
|
int resync_start_fd;
|
||||||
int metadata_fd; /* for monitoring rw/ro status */
|
int metadata_fd; /* for monitoring rw/ro status */
|
||||||
|
int sync_completed_fd; /* for checkpoint notification events */
|
||||||
|
unsigned long long last_checkpoint; /* sync_completed fires for many
|
||||||
|
* reasons this field makes sure the
|
||||||
|
* kernel has made progress before
|
||||||
|
* moving the checkpoint. It is
|
||||||
|
* cleared by the metadata handler
|
||||||
|
* when it determines recovery is
|
||||||
|
* terminated.
|
||||||
|
*/
|
||||||
|
|
||||||
enum array_state prev_state, curr_state, next_state;
|
enum array_state prev_state, curr_state, next_state;
|
||||||
enum sync_action prev_action, curr_action, next_action;
|
enum sync_action prev_action, curr_action, next_action;
|
||||||
|
|
37
monitor.c
37
monitor.c
|
@ -80,6 +80,24 @@ static unsigned long long read_resync_start(int fd)
|
||||||
return strtoull(buf, NULL, 10);
|
return strtoull(buf, NULL, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned long long read_sync_completed(int fd)
|
||||||
|
{
|
||||||
|
unsigned long long val;
|
||||||
|
char buf[50];
|
||||||
|
int n;
|
||||||
|
char *ep;
|
||||||
|
|
||||||
|
n = read_attr(buf, 50, fd);
|
||||||
|
|
||||||
|
if (n <= 0)
|
||||||
|
return 0;
|
||||||
|
buf[n] = 0;
|
||||||
|
val = strtoull(buf, &ep, 0);
|
||||||
|
if (ep == buf || (*ep != 0 && *ep != '\n' && *ep != ' '))
|
||||||
|
return 0;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
static enum array_state read_state(int fd)
|
static enum array_state read_state(int fd)
|
||||||
{
|
{
|
||||||
char buf[20];
|
char buf[20];
|
||||||
|
@ -195,6 +213,7 @@ static void signal_manager(void)
|
||||||
|
|
||||||
static int read_and_act(struct active_array *a)
|
static int read_and_act(struct active_array *a)
|
||||||
{
|
{
|
||||||
|
unsigned long long sync_completed;
|
||||||
int check_degraded = 0;
|
int check_degraded = 0;
|
||||||
int deactivate = 0;
|
int deactivate = 0;
|
||||||
struct mdinfo *mdi;
|
struct mdinfo *mdi;
|
||||||
|
@ -206,6 +225,7 @@ static int read_and_act(struct active_array *a)
|
||||||
a->curr_state = read_state(a->info.state_fd);
|
a->curr_state = read_state(a->info.state_fd);
|
||||||
a->curr_action = read_action(a->action_fd);
|
a->curr_action = read_action(a->action_fd);
|
||||||
a->info.resync_start = read_resync_start(a->resync_start_fd);
|
a->info.resync_start = read_resync_start(a->resync_start_fd);
|
||||||
|
sync_completed = read_sync_completed(a->sync_completed_fd);
|
||||||
for (mdi = a->info.devs; mdi ; mdi = mdi->next) {
|
for (mdi = a->info.devs; mdi ; mdi = mdi->next) {
|
||||||
mdi->next_state = 0;
|
mdi->next_state = 0;
|
||||||
if (mdi->state_fd >= 0) {
|
if (mdi->state_fd >= 0) {
|
||||||
|
@ -307,6 +327,22 @@ static int read_and_act(struct active_array *a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for recovery checkpoint notifications. We need to be a
|
||||||
|
* minimum distance away from the last checkpoint to prevent
|
||||||
|
* over checkpointing. Note reshape checkpointing is not
|
||||||
|
* handled here.
|
||||||
|
*/
|
||||||
|
if (sync_completed > a->last_checkpoint &&
|
||||||
|
sync_completed - a->last_checkpoint > a->info.component_size >> 4 &&
|
||||||
|
a->curr_action > reshape) {
|
||||||
|
/* A (non-reshape) sync_action has reached a checkpoint.
|
||||||
|
* Record the updated position in the metadata
|
||||||
|
*/
|
||||||
|
a->last_checkpoint = sync_completed;
|
||||||
|
a->container->ss->set_array_state(a, a->curr_state <= clean);
|
||||||
|
} else if (sync_completed > a->last_checkpoint)
|
||||||
|
a->last_checkpoint = sync_completed;
|
||||||
|
|
||||||
a->container->ss->sync_metadata(a->container);
|
a->container->ss->sync_metadata(a->container);
|
||||||
dprintf("%s(%d): state:%s action:%s next(", __func__, a->info.container_member,
|
dprintf("%s(%d): state:%s action:%s next(", __func__, a->info.container_member,
|
||||||
array_states[a->curr_state], sync_actions[a->curr_action]);
|
array_states[a->curr_state], sync_actions[a->curr_action]);
|
||||||
|
@ -461,6 +497,7 @@ static int wait_and_act(struct supertype *container, int nowait)
|
||||||
|
|
||||||
add_fd(&rfds, &maxfd, a->info.state_fd);
|
add_fd(&rfds, &maxfd, a->info.state_fd);
|
||||||
add_fd(&rfds, &maxfd, a->action_fd);
|
add_fd(&rfds, &maxfd, a->action_fd);
|
||||||
|
add_fd(&rfds, &maxfd, a->sync_completed_fd);
|
||||||
for (mdi = a->info.devs ; mdi ; mdi = mdi->next)
|
for (mdi = a->info.devs ; mdi ; mdi = mdi->next)
|
||||||
add_fd(&rfds, &maxfd, mdi->state_fd);
|
add_fd(&rfds, &maxfd, mdi->state_fd);
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,55 @@ static inline int imsm_orom_has_chunk(const struct imsm_orom *orom, int chunk)
|
||||||
return !!(orom->sss & (1 << (fs - 1)));
|
return !!(orom->sss & (1 << (fs - 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fls - find last (most-significant) bit set
|
||||||
|
* @x: the word to search
|
||||||
|
* The funciton is borrowed from Linux kernel code
|
||||||
|
* include/asm-generic/bitops/fls.h
|
||||||
|
*/
|
||||||
|
static inline int fls(int x)
|
||||||
|
{
|
||||||
|
int r = 32;
|
||||||
|
|
||||||
|
if (!x)
|
||||||
|
return 0;
|
||||||
|
if (!(x & 0xffff0000u)) {
|
||||||
|
x <<= 16;
|
||||||
|
r -= 16;
|
||||||
|
}
|
||||||
|
if (!(x & 0xff000000u)) {
|
||||||
|
x <<= 8;
|
||||||
|
r -= 8;
|
||||||
|
}
|
||||||
|
if (!(x & 0xf0000000u)) {
|
||||||
|
x <<= 4;
|
||||||
|
r -= 4;
|
||||||
|
}
|
||||||
|
if (!(x & 0xc0000000u)) {
|
||||||
|
x <<= 2;
|
||||||
|
r -= 2;
|
||||||
|
}
|
||||||
|
if (!(x & 0x80000000u)) {
|
||||||
|
x <<= 1;
|
||||||
|
r -= 1;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* imsm_orom_default_chunk - return the largest chunk size supported via orom
|
||||||
|
* @orom: orom pointer from find_imsm_orom
|
||||||
|
*/
|
||||||
|
static inline int imsm_orom_default_chunk(const struct imsm_orom *orom)
|
||||||
|
{
|
||||||
|
int fs = fls(orom->sss);
|
||||||
|
|
||||||
|
if (!fs)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return min(512, (1 << fs));
|
||||||
|
}
|
||||||
|
|
||||||
struct sys_dev {
|
struct sys_dev {
|
||||||
char *path;
|
char *path;
|
||||||
struct sys_dev *next;
|
struct sys_dev *next;
|
||||||
|
|
33
super-ddf.c
33
super-ddf.c
|
@ -845,10 +845,18 @@ static int load_super_ddf(struct supertype *st, int fd,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st->subarray[0]) {
|
if (st->subarray[0]) {
|
||||||
|
unsigned long val;
|
||||||
struct vcl *v;
|
struct vcl *v;
|
||||||
|
char *ep;
|
||||||
|
|
||||||
|
val = strtoul(st->subarray, &ep, 10);
|
||||||
|
if (*ep != '\0') {
|
||||||
|
free(super);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (v = super->conflist; v; v = v->next)
|
for (v = super->conflist; v; v = v->next)
|
||||||
if (v->vcnum == atoi(st->subarray))
|
if (v->vcnum == val)
|
||||||
super->currentconf = v;
|
super->currentconf = v;
|
||||||
if (!super->currentconf) {
|
if (!super->currentconf) {
|
||||||
free(super);
|
free(super);
|
||||||
|
@ -2807,14 +2815,8 @@ static int load_super_ddf_all(struct supertype *st, int fd,
|
||||||
int seq;
|
int seq;
|
||||||
char nm[20];
|
char nm[20];
|
||||||
int dfd;
|
int dfd;
|
||||||
int devnum = fd2devnum(fd);
|
|
||||||
enum sysfs_read_flags flags;
|
|
||||||
|
|
||||||
flags = GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE;
|
sra = sysfs_read(fd, 0, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE);
|
||||||
if (mdmon_running(devnum))
|
|
||||||
flags |= SKIP_GONE_DEVS;
|
|
||||||
|
|
||||||
sra = sysfs_read(fd, 0, flags);
|
|
||||||
if (!sra)
|
if (!sra)
|
||||||
return 1;
|
return 1;
|
||||||
if (sra->array.major_version != -1 ||
|
if (sra->array.major_version != -1 ||
|
||||||
|
@ -2871,14 +2873,25 @@ static int load_super_ddf_all(struct supertype *st, int fd,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (st->subarray[0]) {
|
if (st->subarray[0]) {
|
||||||
|
unsigned long val;
|
||||||
struct vcl *v;
|
struct vcl *v;
|
||||||
|
char *ep;
|
||||||
|
|
||||||
|
val = strtoul(st->subarray, &ep, 10);
|
||||||
|
if (*ep != '\0') {
|
||||||
|
free(super);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (v = super->conflist; v; v = v->next)
|
for (v = super->conflist; v; v = v->next)
|
||||||
if (v->vcnum == atoi(st->subarray))
|
if (v->vcnum == val)
|
||||||
super->currentconf = v;
|
super->currentconf = v;
|
||||||
if (!super->currentconf)
|
if (!super->currentconf) {
|
||||||
|
free(super);
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*sbp = super;
|
*sbp = super;
|
||||||
if (st->ss == NULL) {
|
if (st->ss == NULL) {
|
||||||
st->ss = &super_ddf;
|
st->ss = &super_ddf;
|
||||||
|
|
333
super-intel.c
333
super-intel.c
|
@ -282,6 +282,8 @@ struct extent {
|
||||||
enum imsm_update_type {
|
enum imsm_update_type {
|
||||||
update_activate_spare,
|
update_activate_spare,
|
||||||
update_create_array,
|
update_create_array,
|
||||||
|
update_kill_array,
|
||||||
|
update_rename_array,
|
||||||
update_add_disk,
|
update_add_disk,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -303,6 +305,17 @@ struct imsm_update_create_array {
|
||||||
struct imsm_dev dev;
|
struct imsm_dev dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct imsm_update_kill_array {
|
||||||
|
enum imsm_update_type type;
|
||||||
|
int dev_idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct imsm_update_rename_array {
|
||||||
|
enum imsm_update_type type;
|
||||||
|
__u8 name[MAX_RAID_SERIAL_LEN];
|
||||||
|
int dev_idx;
|
||||||
|
};
|
||||||
|
|
||||||
struct imsm_update_add_disk {
|
struct imsm_update_add_disk {
|
||||||
enum imsm_update_type type;
|
enum imsm_update_type type;
|
||||||
};
|
};
|
||||||
|
@ -639,7 +652,7 @@ static __u64 blocks_per_migr_unit(struct imsm_dev *dev);
|
||||||
static void print_imsm_dev(struct imsm_dev *dev, char *uuid, int disk_idx)
|
static void print_imsm_dev(struct imsm_dev *dev, char *uuid, int disk_idx)
|
||||||
{
|
{
|
||||||
__u64 sz;
|
__u64 sz;
|
||||||
int slot;
|
int slot, i;
|
||||||
struct imsm_map *map = get_imsm_map(dev, 0);
|
struct imsm_map *map = get_imsm_map(dev, 0);
|
||||||
__u32 ord;
|
__u32 ord;
|
||||||
|
|
||||||
|
@ -648,6 +661,12 @@ static void print_imsm_dev(struct imsm_dev *dev, char *uuid, int disk_idx)
|
||||||
printf(" UUID : %s\n", uuid);
|
printf(" UUID : %s\n", uuid);
|
||||||
printf(" RAID Level : %d\n", get_imsm_raid_level(map));
|
printf(" RAID Level : %d\n", get_imsm_raid_level(map));
|
||||||
printf(" Members : %d\n", map->num_members);
|
printf(" Members : %d\n", map->num_members);
|
||||||
|
printf(" Slots : [");
|
||||||
|
for (i = 0; i < map->num_members; i++) {
|
||||||
|
ord = get_imsm_ord_tbl_ent(dev, i);
|
||||||
|
printf("%s", ord & IMSM_ORD_REBUILD ? "_" : "U");
|
||||||
|
}
|
||||||
|
printf("]\n");
|
||||||
slot = get_imsm_disk_slot(map, disk_idx);
|
slot = get_imsm_disk_slot(map, disk_idx);
|
||||||
if (slot >= 0) {
|
if (slot >= 0) {
|
||||||
ord = get_imsm_ord_tbl_ent(dev, slot);
|
ord = get_imsm_ord_tbl_ent(dev, slot);
|
||||||
|
@ -2747,14 +2766,9 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
|
||||||
int retry;
|
int retry;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
int i;
|
int i;
|
||||||
enum sysfs_read_flags flags;
|
|
||||||
|
|
||||||
flags = GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE;
|
|
||||||
if (mdmon_running(devnum))
|
|
||||||
flags |= SKIP_GONE_DEVS;
|
|
||||||
|
|
||||||
/* check if 'fd' an opened container */
|
/* check if 'fd' an opened container */
|
||||||
sra = sysfs_read(fd, 0, flags);
|
sra = sysfs_read(fd, 0, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE);
|
||||||
if (!sra)
|
if (!sra)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@ -2812,11 +2826,20 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st->subarray[0]) {
|
if (st->subarray[0]) {
|
||||||
if (atoi(st->subarray) <= super->anchor->num_raid_devs)
|
unsigned long val;
|
||||||
super->current_vol = atoi(st->subarray);
|
char *ep;
|
||||||
|
|
||||||
|
err = 1;
|
||||||
|
val = strtoul(st->subarray, &ep, 10);
|
||||||
|
if (*ep != '\0') {
|
||||||
|
free_imsm(super);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val < super->anchor->num_raid_devs)
|
||||||
|
super->current_vol = val;
|
||||||
else {
|
else {
|
||||||
free_imsm(super);
|
free_imsm(super);
|
||||||
err = 1;
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2883,8 +2906,17 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st->subarray[0]) {
|
if (st->subarray[0]) {
|
||||||
if (atoi(st->subarray) <= super->anchor->num_raid_devs)
|
unsigned long val;
|
||||||
super->current_vol = atoi(st->subarray);
|
char *ep;
|
||||||
|
|
||||||
|
val = strtoul(st->subarray, &ep, 10);
|
||||||
|
if (*ep != '\0') {
|
||||||
|
free_imsm(super);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val < super->anchor->num_raid_devs)
|
||||||
|
super->current_vol = val;
|
||||||
else {
|
else {
|
||||||
free_imsm(super);
|
free_imsm(super);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -2974,6 +3006,30 @@ static void imsm_update_version_info(struct intel_super *super)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int check_name(struct intel_super *super, char *name, int quiet)
|
||||||
|
{
|
||||||
|
struct imsm_super *mpb = super->anchor;
|
||||||
|
char *reason = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (strlen(name) > MAX_RAID_SERIAL_LEN)
|
||||||
|
reason = "must be 16 characters or less";
|
||||||
|
|
||||||
|
for (i = 0; i < mpb->num_raid_devs; i++) {
|
||||||
|
struct imsm_dev *dev = get_imsm_dev(super, i);
|
||||||
|
|
||||||
|
if (strncmp((char *) dev->volume, name, MAX_RAID_SERIAL_LEN) == 0) {
|
||||||
|
reason = "already exists";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reason && !quiet)
|
||||||
|
fprintf(stderr, Name ": imsm volume name %s\n", reason);
|
||||||
|
|
||||||
|
return !reason;
|
||||||
|
}
|
||||||
|
|
||||||
static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
|
static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
|
||||||
unsigned long long size, char *name,
|
unsigned long long size, char *name,
|
||||||
char *homehost, int *uuid)
|
char *homehost, int *uuid)
|
||||||
|
@ -3025,16 +3081,8 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
|
||||||
if (super->current_vol == 0)
|
if (super->current_vol == 0)
|
||||||
mpb->num_disks = 0;
|
mpb->num_disks = 0;
|
||||||
|
|
||||||
for (i = 0; i < super->current_vol; i++) {
|
if (!check_name(super, name, 0))
|
||||||
dev = get_imsm_dev(super, i);
|
return 0;
|
||||||
if (strncmp((char *) dev->volume, name,
|
|
||||||
MAX_RAID_SERIAL_LEN) == 0) {
|
|
||||||
fprintf(stderr, Name": '%s' is already defined for this container\n",
|
|
||||||
name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(st->subarray, "%d", idx);
|
sprintf(st->subarray, "%d", idx);
|
||||||
dv = malloc(sizeof(*dv));
|
dv = malloc(sizeof(*dv));
|
||||||
if (!dv) {
|
if (!dv) {
|
||||||
|
@ -4066,6 +4114,140 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
|
||||||
close(cfd);
|
close(cfd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int default_chunk_imsm(struct supertype *st)
|
||||||
|
{
|
||||||
|
struct intel_super *super = st->sb;
|
||||||
|
|
||||||
|
if (!super->orom)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return imsm_orom_default_chunk(super->orom);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_missing(struct intel_super *super, struct imsm_dev *dev);
|
||||||
|
|
||||||
|
static int kill_subarray_imsm(struct supertype *st)
|
||||||
|
{
|
||||||
|
/* remove the subarray currently referenced by ->current_vol */
|
||||||
|
__u8 i;
|
||||||
|
struct intel_dev **dp;
|
||||||
|
struct intel_super *super = st->sb;
|
||||||
|
__u8 current_vol = super->current_vol;
|
||||||
|
struct imsm_super *mpb = super->anchor;
|
||||||
|
|
||||||
|
if (super->current_vol < 0)
|
||||||
|
return 2;
|
||||||
|
super->current_vol = -1; /* invalidate subarray cursor */
|
||||||
|
|
||||||
|
/* block deletions that would change the uuid of active subarrays
|
||||||
|
*
|
||||||
|
* FIXME when immutable ids are available, but note that we'll
|
||||||
|
* also need to fixup the invalidated/active subarray indexes in
|
||||||
|
* mdstat
|
||||||
|
*/
|
||||||
|
for (i = 0; i < mpb->num_raid_devs; i++) {
|
||||||
|
char subarray[4];
|
||||||
|
|
||||||
|
if (i < current_vol)
|
||||||
|
continue;
|
||||||
|
sprintf(subarray, "%u", i);
|
||||||
|
if (is_subarray_active(subarray, st->devname)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
Name ": deleting subarray-%d would change the UUID of active subarray-%d, aborting\n",
|
||||||
|
current_vol, i);
|
||||||
|
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st->update_tail) {
|
||||||
|
struct imsm_update_kill_array *u = malloc(sizeof(*u));
|
||||||
|
|
||||||
|
if (!u)
|
||||||
|
return 2;
|
||||||
|
u->type = update_kill_array;
|
||||||
|
u->dev_idx = current_vol;
|
||||||
|
append_metadata_update(st, u, sizeof(*u));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (dp = &super->devlist; *dp;)
|
||||||
|
if ((*dp)->index == current_vol) {
|
||||||
|
*dp = (*dp)->next;
|
||||||
|
} else {
|
||||||
|
handle_missing(super, (*dp)->dev);
|
||||||
|
if ((*dp)->index > current_vol)
|
||||||
|
(*dp)->index--;
|
||||||
|
dp = &(*dp)->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no more raid devices, all active components are now spares,
|
||||||
|
* but of course failed are still failed
|
||||||
|
*/
|
||||||
|
if (--mpb->num_raid_devs == 0) {
|
||||||
|
struct dl *d;
|
||||||
|
|
||||||
|
for (d = super->disks; d; d = d->next)
|
||||||
|
if (d->index > -2) {
|
||||||
|
d->index = -1;
|
||||||
|
d->disk.status = SPARE_DISK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super->updates_pending++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int update_subarray_imsm(struct supertype *st, char *update, mddev_ident_t ident)
|
||||||
|
{
|
||||||
|
/* update the subarray currently referenced by ->current_vol */
|
||||||
|
struct intel_super *super = st->sb;
|
||||||
|
struct imsm_super *mpb = super->anchor;
|
||||||
|
|
||||||
|
if (super->current_vol < 0)
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
if (strcmp(update, "name") == 0) {
|
||||||
|
char *name = ident->name;
|
||||||
|
|
||||||
|
if (is_subarray_active(st->subarray, st->devname)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
Name ": Unable to update name of active subarray\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!check_name(super, name, 0))
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
if (st->update_tail) {
|
||||||
|
struct imsm_update_rename_array *u = malloc(sizeof(*u));
|
||||||
|
|
||||||
|
if (!u)
|
||||||
|
return 2;
|
||||||
|
u->type = update_rename_array;
|
||||||
|
u->dev_idx = super->current_vol;
|
||||||
|
snprintf((char *) u->name, MAX_RAID_SERIAL_LEN, "%s", name);
|
||||||
|
append_metadata_update(st, u, sizeof(*u));
|
||||||
|
} else {
|
||||||
|
struct imsm_dev *dev;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
dev = get_imsm_dev(super, super->current_vol);
|
||||||
|
snprintf((char *) dev->volume, MAX_RAID_SERIAL_LEN, "%s", name);
|
||||||
|
for (i = 0; i < mpb->num_raid_devs; i++) {
|
||||||
|
dev = get_imsm_dev(super, i);
|
||||||
|
handle_missing(super, dev);
|
||||||
|
}
|
||||||
|
super->updates_pending++;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif /* MDASSEMBLE */
|
#endif /* MDASSEMBLE */
|
||||||
|
|
||||||
static int is_rebuilding(struct imsm_dev *dev)
|
static int is_rebuilding(struct imsm_dev *dev)
|
||||||
|
@ -4415,6 +4597,24 @@ static void mark_missing(struct imsm_dev *dev, struct imsm_disk *disk, int idx)
|
||||||
memmove(&disk->serial[0], &disk->serial[1], MAX_RAID_SERIAL_LEN - 1);
|
memmove(&disk->serial[0], &disk->serial[1], MAX_RAID_SERIAL_LEN - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_missing(struct intel_super *super, struct imsm_dev *dev)
|
||||||
|
{
|
||||||
|
__u8 map_state;
|
||||||
|
struct dl *dl;
|
||||||
|
int failed;
|
||||||
|
|
||||||
|
if (!super->missing)
|
||||||
|
return;
|
||||||
|
failed = imsm_count_failed(super, dev);
|
||||||
|
map_state = imsm_check_degraded(super, dev, failed);
|
||||||
|
|
||||||
|
dprintf("imsm: mark missing\n");
|
||||||
|
end_migration(dev, map_state);
|
||||||
|
for (dl = super->missing; dl; dl = dl->next)
|
||||||
|
mark_missing(dev, &dl->disk, dl->index);
|
||||||
|
super->updates_pending++;
|
||||||
|
}
|
||||||
|
|
||||||
/* Handle dirty -> clean transititions and resync. Degraded and rebuild
|
/* Handle dirty -> clean transititions and resync. Degraded and rebuild
|
||||||
* states are handled in imsm_set_disk() with one exception, when a
|
* states are handled in imsm_set_disk() with one exception, when a
|
||||||
* resync is stopped due to a new failure this routine will set the
|
* resync is stopped due to a new failure this routine will set the
|
||||||
|
@ -4431,15 +4631,8 @@ static int imsm_set_array_state(struct active_array *a, int consistent)
|
||||||
__u32 blocks_per_unit;
|
__u32 blocks_per_unit;
|
||||||
|
|
||||||
/* before we activate this array handle any missing disks */
|
/* before we activate this array handle any missing disks */
|
||||||
if (consistent == 2 && super->missing) {
|
if (consistent == 2)
|
||||||
struct dl *dl;
|
handle_missing(super, dev);
|
||||||
|
|
||||||
dprintf("imsm: mark missing\n");
|
|
||||||
end_migration(dev, map_state);
|
|
||||||
for (dl = super->missing; dl; dl = dl->next)
|
|
||||||
mark_missing(dev, &dl->disk, dl->index);
|
|
||||||
super->updates_pending++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (consistent == 2 &&
|
if (consistent == 2 &&
|
||||||
(!is_resync_complete(&a->info) ||
|
(!is_resync_complete(&a->info) ||
|
||||||
|
@ -4456,6 +4649,7 @@ static int imsm_set_array_state(struct active_array *a, int consistent)
|
||||||
dprintf("imsm: mark resync done\n");
|
dprintf("imsm: mark resync done\n");
|
||||||
end_migration(dev, map_state);
|
end_migration(dev, map_state);
|
||||||
super->updates_pending++;
|
super->updates_pending++;
|
||||||
|
a->last_checkpoint = 0;
|
||||||
}
|
}
|
||||||
} else if (!is_resyncing(dev) && !failed) {
|
} else if (!is_resyncing(dev) && !failed) {
|
||||||
/* mark the start of the init process if nothing is failed */
|
/* mark the start of the init process if nothing is failed */
|
||||||
|
@ -4469,14 +4663,11 @@ static int imsm_set_array_state(struct active_array *a, int consistent)
|
||||||
|
|
||||||
/* check if we can update curr_migr_unit from resync_start, recovery_start */
|
/* check if we can update curr_migr_unit from resync_start, recovery_start */
|
||||||
blocks_per_unit = blocks_per_migr_unit(dev);
|
blocks_per_unit = blocks_per_migr_unit(dev);
|
||||||
if (blocks_per_unit && failed <= 1) {
|
if (blocks_per_unit) {
|
||||||
__u32 units32;
|
__u32 units32;
|
||||||
__u64 units;
|
__u64 units;
|
||||||
|
|
||||||
if (migr_type(dev) == MIGR_REBUILD)
|
units = a->last_checkpoint / blocks_per_unit;
|
||||||
units = min_recovery_start(&a->info) / blocks_per_unit;
|
|
||||||
else
|
|
||||||
units = a->info.resync_start / blocks_per_unit;
|
|
||||||
units32 = units;
|
units32 = units;
|
||||||
|
|
||||||
/* check that we did not overflow 32-bits, and that
|
/* check that we did not overflow 32-bits, and that
|
||||||
|
@ -4548,17 +4739,20 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
|
||||||
map = get_imsm_map(dev, 0);
|
map = get_imsm_map(dev, 0);
|
||||||
map->failed_disk_num = ~0;
|
map->failed_disk_num = ~0;
|
||||||
super->updates_pending++;
|
super->updates_pending++;
|
||||||
|
a->last_checkpoint = 0;
|
||||||
} else if (map_state == IMSM_T_STATE_DEGRADED &&
|
} else if (map_state == IMSM_T_STATE_DEGRADED &&
|
||||||
map->map_state != map_state &&
|
map->map_state != map_state &&
|
||||||
!dev->vol.migr_state) {
|
!dev->vol.migr_state) {
|
||||||
dprintf("imsm: mark degraded\n");
|
dprintf("imsm: mark degraded\n");
|
||||||
map->map_state = map_state;
|
map->map_state = map_state;
|
||||||
super->updates_pending++;
|
super->updates_pending++;
|
||||||
|
a->last_checkpoint = 0;
|
||||||
} else if (map_state == IMSM_T_STATE_FAILED &&
|
} else if (map_state == IMSM_T_STATE_FAILED &&
|
||||||
map->map_state != map_state) {
|
map->map_state != map_state) {
|
||||||
dprintf("imsm: mark failed\n");
|
dprintf("imsm: mark failed\n");
|
||||||
end_migration(dev, map_state);
|
end_migration(dev, map_state);
|
||||||
super->updates_pending++;
|
super->updates_pending++;
|
||||||
|
a->last_checkpoint = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5135,6 +5329,70 @@ static void imsm_process_update(struct supertype *st,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case update_kill_array: {
|
||||||
|
struct imsm_update_kill_array *u = (void *) update->buf;
|
||||||
|
int victim = u->dev_idx;
|
||||||
|
struct active_array *a;
|
||||||
|
struct intel_dev **dp;
|
||||||
|
struct imsm_dev *dev;
|
||||||
|
|
||||||
|
/* sanity check that we are not affecting the uuid of
|
||||||
|
* active arrays, or deleting an active array
|
||||||
|
*
|
||||||
|
* FIXME when immutable ids are available, but note that
|
||||||
|
* we'll also need to fixup the invalidated/active
|
||||||
|
* subarray indexes in mdstat
|
||||||
|
*/
|
||||||
|
for (a = st->arrays; a; a = a->next)
|
||||||
|
if (a->info.container_member >= victim)
|
||||||
|
break;
|
||||||
|
/* by definition if mdmon is running at least one array
|
||||||
|
* is active in the container, so checking
|
||||||
|
* mpb->num_raid_devs is just extra paranoia
|
||||||
|
*/
|
||||||
|
dev = get_imsm_dev(super, victim);
|
||||||
|
if (a || !dev || mpb->num_raid_devs == 1) {
|
||||||
|
dprintf("failed to delete subarray-%d\n", victim);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (dp = &super->devlist; *dp;)
|
||||||
|
if ((*dp)->index == super->current_vol) {
|
||||||
|
*dp = (*dp)->next;
|
||||||
|
} else {
|
||||||
|
if ((*dp)->index > victim)
|
||||||
|
(*dp)->index--;
|
||||||
|
dp = &(*dp)->next;
|
||||||
|
}
|
||||||
|
mpb->num_raid_devs--;
|
||||||
|
super->updates_pending++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case update_rename_array: {
|
||||||
|
struct imsm_update_rename_array *u = (void *) update->buf;
|
||||||
|
char name[MAX_RAID_SERIAL_LEN+1];
|
||||||
|
int target = u->dev_idx;
|
||||||
|
struct active_array *a;
|
||||||
|
struct imsm_dev *dev;
|
||||||
|
|
||||||
|
/* sanity check that we are not affecting the uuid of
|
||||||
|
* an active array
|
||||||
|
*/
|
||||||
|
snprintf(name, MAX_RAID_SERIAL_LEN, "%s", (char *) u->name);
|
||||||
|
name[MAX_RAID_SERIAL_LEN] = '\0';
|
||||||
|
for (a = st->arrays; a; a = a->next)
|
||||||
|
if (a->info.container_member == target)
|
||||||
|
break;
|
||||||
|
dev = get_imsm_dev(super, u->dev_idx);
|
||||||
|
if (a || !dev || !check_name(super, name, 1)) {
|
||||||
|
dprintf("failed to rename subarray-%d\n", target);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf((char *) dev->volume, MAX_RAID_SERIAL_LEN, name);
|
||||||
|
super->updates_pending++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case update_add_disk:
|
case update_add_disk:
|
||||||
|
|
||||||
/* we may be able to repair some arrays if disks are
|
/* we may be able to repair some arrays if disks are
|
||||||
|
@ -5308,8 +5566,11 @@ struct superswitch super_imsm = {
|
||||||
.brief_detail_super = brief_detail_super_imsm,
|
.brief_detail_super = brief_detail_super_imsm,
|
||||||
.write_init_super = write_init_super_imsm,
|
.write_init_super = write_init_super_imsm,
|
||||||
.validate_geometry = validate_geometry_imsm,
|
.validate_geometry = validate_geometry_imsm,
|
||||||
|
.default_chunk = default_chunk_imsm,
|
||||||
.add_to_super = add_to_super_imsm,
|
.add_to_super = add_to_super_imsm,
|
||||||
.detail_platform = detail_platform_imsm,
|
.detail_platform = detail_platform_imsm,
|
||||||
|
.kill_subarray = kill_subarray_imsm,
|
||||||
|
.update_subarray = update_subarray_imsm,
|
||||||
#endif
|
#endif
|
||||||
.match_home = match_home_imsm,
|
.match_home = match_home_imsm,
|
||||||
.uuid_from_super= uuid_from_super_imsm,
|
.uuid_from_super= uuid_from_super_imsm,
|
||||||
|
|
23
sysfs.c
23
sysfs.c
|
@ -273,22 +273,20 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
|
||||||
|
|
||||||
strcpy(dbase, "block/dev");
|
strcpy(dbase, "block/dev");
|
||||||
if (load_sys(fname, buf)) {
|
if (load_sys(fname, buf)) {
|
||||||
|
/* assume this is a stale reference to a hot
|
||||||
|
* removed device
|
||||||
|
*/
|
||||||
free(dev);
|
free(dev);
|
||||||
if (options & SKIP_GONE_DEVS)
|
continue;
|
||||||
continue;
|
|
||||||
else
|
|
||||||
goto abort;
|
|
||||||
}
|
}
|
||||||
sscanf(buf, "%d:%d", &dev->disk.major, &dev->disk.minor);
|
sscanf(buf, "%d:%d", &dev->disk.major, &dev->disk.minor);
|
||||||
|
|
||||||
/* special case check for block devices that can go 'offline' */
|
/* special case check for block devices that can go 'offline' */
|
||||||
if (options & SKIP_GONE_DEVS) {
|
strcpy(dbase, "block/device/state");
|
||||||
strcpy(dbase, "block/device/state");
|
if (load_sys(fname, buf) == 0 &&
|
||||||
if (load_sys(fname, buf) == 0 &&
|
strncmp(buf, "offline", 7) == 0) {
|
||||||
strncmp(buf, "offline", 7) == 0) {
|
free(dev);
|
||||||
free(dev);
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* finally add this disk to the array */
|
/* finally add this disk to the array */
|
||||||
|
@ -852,9 +850,6 @@ int WaitClean(char *dev, int sock, int verbose)
|
||||||
tm.tv_sec = 5;
|
tm.tv_sec = 5;
|
||||||
tm.tv_usec = 0;
|
tm.tv_usec = 0;
|
||||||
|
|
||||||
/* give mdmon a chance to checkpoint resync */
|
|
||||||
sysfs_set_str(mdi, NULL, "sync_action", "idle");
|
|
||||||
|
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
|
|
||||||
/* wait for array_state to be clean */
|
/* wait for array_state to be clean */
|
||||||
|
|
137
util.c
137
util.c
|
@ -1392,6 +1392,143 @@ int open_container(int fd)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct superswitch *version_to_superswitch(char *vers)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; superlist[i]; i++) {
|
||||||
|
struct superswitch *ss = superlist[i];
|
||||||
|
|
||||||
|
if (strcmp(vers, ss->name) == 0)
|
||||||
|
return ss;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_container_member(struct mdstat_ent *mdstat, char *container)
|
||||||
|
{
|
||||||
|
if (mdstat->metadata_version == NULL ||
|
||||||
|
strncmp(mdstat->metadata_version, "external:", 9) != 0 ||
|
||||||
|
!is_subarray(mdstat->metadata_version+9) ||
|
||||||
|
strncmp(mdstat->metadata_version+10, container, strlen(container)) != 0 ||
|
||||||
|
mdstat->metadata_version[10+strlen(container)] != '/')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_subarray_active(char *subarray, char *container)
|
||||||
|
{
|
||||||
|
struct mdstat_ent *mdstat = mdstat_read(0, 0);
|
||||||
|
struct mdstat_ent *ent;
|
||||||
|
|
||||||
|
for (ent = mdstat; ent; ent = ent->next) {
|
||||||
|
if (is_container_member(ent, container)) {
|
||||||
|
char *inst = &ent->metadata_version[10+strlen(container)+1];
|
||||||
|
|
||||||
|
if (strcmp(inst, subarray) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free_mdstat(mdstat);
|
||||||
|
|
||||||
|
return ent != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open_subarray - opens a subarray in a container
|
||||||
|
* @dev: container device name
|
||||||
|
* @st: supertype with only ->subarray set
|
||||||
|
* @quiet: block reporting errors flag
|
||||||
|
*
|
||||||
|
* On success returns an fd to a container and fills in *st
|
||||||
|
*/
|
||||||
|
int open_subarray(char *dev, struct supertype *st, int quiet)
|
||||||
|
{
|
||||||
|
struct mdinfo *mdi;
|
||||||
|
int fd, err = 1;
|
||||||
|
|
||||||
|
fd = open(dev, O_RDWR|O_EXCL);
|
||||||
|
if (fd < 0) {
|
||||||
|
if (!quiet)
|
||||||
|
fprintf(stderr, Name ": Couldn't open %s, aborting\n",
|
||||||
|
dev);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
st->devnum = fd2devnum(fd);
|
||||||
|
if (st->devnum == NoMdDev) {
|
||||||
|
if (!quiet)
|
||||||
|
fprintf(stderr,
|
||||||
|
Name ": Failed to determine device number for %s\n",
|
||||||
|
dev);
|
||||||
|
goto close_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
mdi = sysfs_read(fd, st->devnum, GET_VERSION|GET_LEVEL);
|
||||||
|
if (!mdi) {
|
||||||
|
if (!quiet)
|
||||||
|
fprintf(stderr, Name ": Failed to read sysfs for %s\n",
|
||||||
|
dev);
|
||||||
|
goto close_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mdi->array.level != UnSet) {
|
||||||
|
if (!quiet)
|
||||||
|
fprintf(stderr, Name ": %s is not a container\n", dev);
|
||||||
|
goto free_sysfs;
|
||||||
|
}
|
||||||
|
|
||||||
|
st->ss = version_to_superswitch(mdi->text_version);
|
||||||
|
if (!st->ss) {
|
||||||
|
if (!quiet)
|
||||||
|
fprintf(stderr,
|
||||||
|
Name ": Operation not supported for %s metadata\n",
|
||||||
|
mdi->text_version);
|
||||||
|
goto free_sysfs;
|
||||||
|
}
|
||||||
|
|
||||||
|
st->devname = devnum2devname(st->devnum);
|
||||||
|
if (!st->devname) {
|
||||||
|
if (!quiet)
|
||||||
|
fprintf(stderr, Name ": Failed to allocate device name\n");
|
||||||
|
goto free_sysfs;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st->ss->load_super(st, fd, NULL)) {
|
||||||
|
if (!quiet)
|
||||||
|
fprintf(stderr, Name ": Failed to find subarray-%s in %s\n",
|
||||||
|
st->subarray, dev);
|
||||||
|
goto free_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!st->loaded_container) {
|
||||||
|
if (!quiet)
|
||||||
|
fprintf(stderr, Name ": %s is not a container\n", dev);
|
||||||
|
goto free_super;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
|
||||||
|
free_super:
|
||||||
|
if (err)
|
||||||
|
st->ss->free_super(st);
|
||||||
|
free_name:
|
||||||
|
if (err)
|
||||||
|
free(st->devname);
|
||||||
|
free_sysfs:
|
||||||
|
sysfs_free(mdi);
|
||||||
|
close_fd:
|
||||||
|
if (err)
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
int add_disk(int mdfd, struct supertype *st,
|
int add_disk(int mdfd, struct supertype *st,
|
||||||
struct mdinfo *sra, struct mdinfo *info)
|
struct mdinfo *sra, struct mdinfo *info)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue