summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2023-02-25 16:18:46 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2023-02-25 16:18:46 +0000
commitbf5c2aa1d837ea8bb6a4c379ac125b1a41efc9bf (patch)
treeabe74458156206a4adf2950b1cbcad241a72e80e
parentAdding upstream version 4.2. (diff)
downloadmdadm-bf5c2aa1d837ea8bb6a4c379ac125b1a41efc9bf.tar.xz
mdadm-bf5c2aa1d837ea8bb6a4c379ac125b1a41efc9bf.zip
Adding upstream version 4.2+20230223.upstream/4.2+20230223
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--.gitignore1
-rw-r--r--Assemble.c82
-rw-r--r--Build.c23
-rw-r--r--Create.c89
-rw-r--r--Detail.c4
-rw-r--r--Examine.c2
-rw-r--r--Grow.c204
-rw-r--r--Incremental.c46
-rw-r--r--Makefile13
-rw-r--r--Manage.c193
-rw-r--r--Monitor.c292
-rw-r--r--Query.c4
-rw-r--r--ReadMe.c52
-rw-r--r--config.c52
-rw-r--r--lib.c12
-rw-r--r--managemon.c9
-rw-r--r--maps.c55
-rw-r--r--mdadm.8.in301
-rw-r--r--mdadm.c251
-rw-r--r--mdadm.conf.5.in (renamed from mdadm.conf.5)99
-rw-r--r--mdadm.h137
-rw-r--r--mdmon.c73
-rw-r--r--mdopen.c17
-rw-r--r--monitor.c4
-rw-r--r--platform-intel.c18
-rw-r--r--probe_roms.c6
-rw-r--r--raid6check.c25
-rw-r--r--super-ddf.c183
-rw-r--r--super-intel.c475
-rw-r--r--super0.c109
-rw-r--r--super1.c207
-rw-r--r--sysfs.c11
-rw-r--r--systemd/mdadm-grow-continue@.service1
-rw-r--r--systemd/mdadm-last-resort@.service1
-rw-r--r--systemd/mdcheck_continue.service3
-rw-r--r--systemd/mdcheck_start.service1
-rw-r--r--systemd/mdmon@.service1
-rw-r--r--systemd/mdmonitor-oneshot.service1
-rw-r--r--systemd/mdmonitor.service1
-rwxr-xr-xtest71
-rw-r--r--tests/00createnames93
-rw-r--r--tests/00raid010
-rw-r--r--tests/00readonly5
-rw-r--r--tests/01r5integ.broken7
-rw-r--r--tests/01raid6integ.broken7
-rw-r--r--tests/02lineargrow2
-rw-r--r--tests/03r0assem6
-rw-r--r--tests/04r0update4
-rw-r--r--tests/04r5swap.broken7
-rw-r--r--tests/04update-metadata8
-rw-r--r--tests/07autoassemble.broken8
-rw-r--r--tests/07autodetect.broken5
-rw-r--r--tests/07changelevelintr.broken9
-rw-r--r--tests/07changelevels.broken9
-rw-r--r--tests/07reshape5intr.broken45
-rw-r--r--tests/07revert-grow.broken31
-rw-r--r--tests/07revert-shrink.broken9
-rw-r--r--tests/07testreshape5.broken12
-rw-r--r--tests/09imsm-assemble.broken6
-rw-r--r--tests/09imsm-create-fail-rebuild.broken5
-rw-r--r--tests/09imsm-overlap28
-rw-r--r--tests/09imsm-overlap.broken7
-rw-r--r--tests/10ddf-assemble-missing.broken6
-rw-r--r--tests/10ddf-fail-create-race.broken7
-rw-r--r--tests/10ddf-fail-two-spares.broken5
-rw-r--r--tests/10ddf-incremental-wrong-order.broken9
-rw-r--r--tests/14imsm-r1_2d-grow-r1_3d.broken5
-rw-r--r--tests/14imsm-r1_2d-takeover-r0_2d.broken6
-rw-r--r--tests/18imsm-r10_4d-takeover-r0_2d.broken5
-rw-r--r--tests/18imsm-r1_2d-takeover-r0_1d.broken6
-rw-r--r--tests/19raid6auto-repair.broken5
-rw-r--r--tests/19raid6repair.broken5
-rw-r--r--udev-md-raid-arrays.rules2
-rw-r--r--udev-md-raid-assembly.rules13
-rw-r--r--udev-md-raid-safe-timeouts.rules2
-rw-r--r--util.c110
76 files changed, 2267 insertions, 1371 deletions
diff --git a/.gitignore b/.gitignore
index 217fe76..8d791c6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
/*-stamp
/mdadm
/mdadm.8
+/mdadm.conf.5
/mdadm.udeb
/mdassemble
/mdmon
diff --git a/Assemble.c b/Assemble.c
index 704b829..4980494 100644
--- a/Assemble.c
+++ b/Assemble.c
@@ -63,7 +63,7 @@ static void set_array_assembly_status(struct context *c,
struct assembly_array_info *arr)
{
int raid_disks = arr->preexist_cnt + arr->new_cnt;
- char *status_msg = map_num(assemble_statuses, status);
+ char *status_msg = map_num_s(assemble_statuses, status);
if (c->export && result)
*result |= status;
@@ -77,9 +77,7 @@ static void set_array_assembly_status(struct context *c,
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");
+ fprintf(stderr, " %s.\n", status_msg);
}
static int name_matches(char *found, char *required, char *homehost, int require_homehost)
@@ -137,17 +135,17 @@ static int ident_matches(struct mddev_ident *ident,
struct mdinfo *content,
struct supertype *tst,
char *homehost, int require_homehost,
- char *update, char *devname)
+ enum update_opt update, char *devname)
{
- if (ident->uuid_set && (!update || strcmp(update, "uuid")!= 0) &&
+ if (ident->uuid_set && update != UOPT_UUID &&
same_uuid(content->uuid, ident->uuid, tst->ss->swapuuid)==0 &&
memcmp(content->uuid, uuid_zero, sizeof(int[4])) != 0) {
if (devname)
pr_err("%s has wrong uuid.\n", devname);
return 0;
}
- if (ident->name[0] && (!update || strcmp(update, "name")!= 0) &&
+ if (ident->name[0] && update != UOPT_NAME &&
name_matches(content->name, ident->name, homehost, require_homehost)==0) {
if (devname)
pr_err("%s has wrong name.\n", devname);
@@ -650,11 +648,10 @@ static int load_devices(struct devs *devices, char *devmap,
int err;
fstat(mdfd, &stb2);
- if (strcmp(c->update, "uuid") == 0 && !ident->uuid_set)
+ if (c->update == UOPT_UUID && !ident->uuid_set)
random_uuid((__u8 *)ident->uuid);
- if (strcmp(c->update, "ppl") == 0 &&
- ident->bitmap_fd >= 0) {
+ if (c->update == UOPT_PPL && ident->bitmap_fd >= 0) {
pr_err("PPL is not compatible with bitmap\n");
close(mdfd);
free(devices);
@@ -686,30 +683,30 @@ static int load_devices(struct devs *devices, char *devmap,
strcpy(content->name, ident->name);
content->array.md_minor = minor(stb2.st_rdev);
- if (strcmp(c->update, "byteorder") == 0)
+ if (c->update == UOPT_BYTEORDER)
err = 0;
- else if (strcmp(c->update, "home-cluster") == 0) {
+ else if (c->update == UOPT_HOME_CLUSTER) {
tst->cluster_name = c->homecluster;
err = tst->ss->write_bitmap(tst, dfd, NameUpdate);
- } else if (strcmp(c->update, "nodes") == 0) {
+ } else if (c->update == UOPT_NODES) {
tst->nodes = c->nodes;
err = tst->ss->write_bitmap(tst, dfd, NodeNumUpdate);
- } else if (strcmp(c->update, "revert-reshape") == 0 &&
- c->invalid_backup)
+ } else if (c->update == UOPT_REVERT_RESHAPE && c->invalid_backup)
err = tst->ss->update_super(tst, content,
- "revert-reshape-nobackup",
+ UOPT_SPEC_REVERT_RESHAPE_NOBACKUP,
devname, c->verbose,
ident->uuid_set,
c->homehost);
else
- err = tst->ss->update_super(tst, content, c->update,
+ err = tst->ss->update_super(tst, content,
+ c->update,
devname, c->verbose,
ident->uuid_set,
c->homehost);
if (err < 0) {
if (err == -1)
pr_err("--update=%s not understood for %s metadata\n",
- c->update, tst->ss->name);
+ map_num(update_options, c->update), tst->ss->name);
tst->ss->free_super(tst);
free(tst);
close(mdfd);
@@ -719,7 +716,7 @@ static int load_devices(struct devs *devices, char *devmap,
*stp = st;
return -1;
}
- if (strcmp(c->update, "uuid")==0 &&
+ if (c->update == UOPT_UUID &&
!ident->uuid_set) {
ident->uuid_set = 1;
memcpy(ident->uuid, content->uuid, 16);
@@ -728,7 +725,7 @@ static int load_devices(struct devs *devices, char *devmap,
pr_err("Could not re-write superblock on %s.\n",
devname);
- if (strcmp(c->update, "uuid")==0 &&
+ if (c->update == UOPT_UUID &&
ident->bitmap_fd >= 0 && !bitmap_done) {
if (bitmap_update_uuid(ident->bitmap_fd,
content->uuid,
@@ -908,8 +905,7 @@ static int force_array(struct mdinfo *content,
* devices in RAID4 or last devices in RAID4/5/6.
*/
delta = devices[j].i.delta_disks;
- if (devices[j].i.array.level >= 4 &&
- devices[j].i.array.level <= 6 &&
+ if (is_level456(devices[j].i.array.level) &&
i/2 >= content->array.raid_disks - delta)
/* OK */;
else if (devices[j].i.array.level == 4 &&
@@ -963,7 +959,7 @@ static int force_array(struct mdinfo *content,
continue;
}
content->events = devices[most_recent].i.events;
- tst->ss->update_super(tst, content, "force-one",
+ tst->ss->update_super(tst, content, UOPT_SPEC_FORCE_ONE,
devices[chosen_drive].devname, c->verbose,
0, NULL);
@@ -1123,7 +1119,7 @@ static int start_array(int mdfd,
i/2, mddev);
}
- if (content->array.level == LEVEL_CONTAINER) {
+ if (is_container(content->array.level)) {
sysfs_rules_apply(mddev, content);
if (c->verbose >= 0) {
pr_err("Container %s has been assembled with %d drive%s",
@@ -1187,8 +1183,7 @@ static int start_array(int mdfd,
pr_err("%s: Need a backup file to complete reshape of this array.\n",
mddev);
pr_err("Please provided one with \"--backup-file=...\"\n");
- if (c->update &&
- strcmp(c->update, "revert-reshape") == 0)
+ if (c->update == UOPT_REVERT_RESHAPE)
pr_err("(Don't specify --update=revert-reshape again, that part succeeded.)\n");
return 1;
}
@@ -1228,8 +1223,7 @@ static int start_array(int mdfd,
fprintf(stderr, ".\n");
}
if (content->reshape_active &&
- content->array.level >= 4 &&
- content->array.level <= 6) {
+ is_level456(content->array.level)) {
/* might need to increase the size
* of the stripe cache - default is 256
*/
@@ -1487,7 +1481,7 @@ try_again:
*/
if (map_lock(&map))
pr_err("failed to get exclusive lock on mapfile - continue anyway...\n");
- if (c->update && strcmp(c->update,"uuid") == 0)
+ if (c->update == UOPT_UUID)
mp = NULL;
else
mp = map_by_uuid(&map, content->uuid);
@@ -1553,8 +1547,7 @@ try_again:
*/
trustworthy = LOCAL;
- if (name[0] == 0 &&
- content->array.level == LEVEL_CONTAINER) {
+ if (!name[0] && is_container(content->array.level)) {
name = content->text_version;
trustworthy = METADATA;
}
@@ -1635,7 +1628,7 @@ try_again:
goto out;
}
- if (c->update && strcmp(c->update, "byteorder")==0)
+ if (c->update == UOPT_BYTEORDER)
st->minor_version = 90;
st->ss->getinfo_super(st, content, NULL);
@@ -1793,7 +1786,7 @@ try_again:
if (!(devices[j].i.array.state & 1))
clean = 0;
- if (st->ss->update_super(st, &devices[j].i, "assemble", NULL,
+ if (st->ss->update_super(st, &devices[j].i, UOPT_SPEC_ASSEMBLE, NULL,
c->verbose, 0, NULL)) {
if (c->force) {
if (c->verbose >= 0)
@@ -1813,11 +1806,10 @@ try_again:
}
#endif
}
- if (c->force && !clean &&
+ if (c->force && !clean && !is_container(content->array.level) &&
!enough(content->array.level, content->array.raid_disks,
- content->array.layout, clean,
- avail)) {
- change += st->ss->update_super(st, content, "force-array",
+ content->array.layout, clean, avail)) {
+ change += st->ss->update_super(st, content, UOPT_SPEC_FORCE_ARRAY,
devices[chosen_drive].devname, c->verbose,
0, NULL);
was_forced = 1;
@@ -1904,7 +1896,7 @@ try_again:
/* First, fill in the map, so that udev can find our name
* as soon as we become active.
*/
- if (c->update && strcmp(c->update, "metadata")==0) {
+ if (c->update == UOPT_METADATA) {
content->array.major_version = 1;
content->array.minor_version = 0;
strcpy(content->text_version, "1.0");
@@ -1951,7 +1943,7 @@ out:
break;
close(mdfd);
}
- usleep(usecs);
+ sleep_for(0, USEC_TO_NSEC(usecs), true);
usecs <<= 1;
}
}
@@ -1976,7 +1968,8 @@ int assemble_container_content(struct supertype *st, int mdfd,
int start_reshape;
char *avail;
int err;
- int is_raid456, is_clean, all_disks;
+ int is_clean, all_disks;
+ bool is_raid456;
if (sysfs_init(content, mdfd, NULL)) {
pr_err("Unable to initialize sysfs\n");
@@ -1984,7 +1977,12 @@ int assemble_container_content(struct supertype *st, int mdfd,
}
sra = sysfs_read(mdfd, NULL, GET_VERSION|GET_DEVS);
- if (sra == NULL || strcmp(sra->text_version, content->text_version) != 0) {
+ if (sra == NULL) {
+ pr_err("Failed to read sysfs parameters\n");
+ return 1;
+ }
+
+ if (strcmp(sra->text_version, content->text_version) != 0) {
if (content->array.major_version == -1 &&
content->array.minor_version == -2 &&
c->readonly &&
@@ -2104,7 +2102,7 @@ int assemble_container_content(struct supertype *st, int mdfd,
content->array.state |= 1;
}
- is_raid456 = (content->array.level >= 4 && content->array.level <= 6);
+ is_raid456 = is_level456(content->array.level);
is_clean = content->array.state & 1;
if (enough(content->array.level, content->array.raid_disks,
diff --git a/Build.c b/Build.c
index 962c2e3..8d6f6f5 100644
--- a/Build.c
+++ b/Build.c
@@ -71,28 +71,7 @@ int Build(char *mddev, struct mddev_dev *devlist,
}
if (s->layout == UnSet)
- switch(s->level) {
- default: /* no layout */
- s->layout = 0;
- break;
- case 10:
- s->layout = 0x102; /* near=2, far=1 */
- if (c->verbose > 0)
- pr_err("layout defaults to n1\n");
- break;
- case 5:
- case 6:
- s->layout = map_name(r5layout, "default");
- if (c->verbose > 0)
- pr_err("layout defaults to %s\n", map_num(r5layout, s->layout));
- break;
- case LEVEL_FAULTY:
- s->layout = map_name(faultylayout, "default");
-
- if (c->verbose > 0)
- pr_err("layout defaults to %s\n", map_num(faultylayout, s->layout));
- break;
- }
+ s->layout = default_layout(NULL, s->level, c->verbose);
/* We need to create the device. It can have no name. */
map_lock(&map);
diff --git a/Create.c b/Create.c
index 0ff1922..953e737 100644
--- a/Create.c
+++ b/Create.c
@@ -39,39 +39,54 @@ static int round_size_and_verify(unsigned long long *size, int chunk)
return 0;
}
-static int default_layout(struct supertype *st, int level, int verbose)
+/**
+ * default_layout() - Get default layout for level.
+ * @st: metadata requested, could be NULL.
+ * @level: raid level requested.
+ * @verbose: verbose level.
+ *
+ * Try to ask metadata handler first, otherwise use global defaults.
+ *
+ * Return: Layout or &UnSet, return value meaning depends of level used.
+ */
+int default_layout(struct supertype *st, int level, int verbose)
{
int layout = UnSet;
+ mapping_t *layout_map = NULL;
+ char *layout_name = NULL;
if (st && st->ss->default_geometry)
st->ss->default_geometry(st, &level, &layout, NULL);
- if (layout == UnSet)
- switch(level) {
- default: /* no layout */
- layout = 0;
- break;
- case 0:
- layout = RAID0_ORIG_LAYOUT;
- break;
- case 10:
- layout = 0x102; /* near=2, far=1 */
- if (verbose > 0)
- pr_err("layout defaults to n2\n");
- break;
- case 5:
- case 6:
- layout = map_name(r5layout, "default");
- if (verbose > 0)
- pr_err("layout defaults to %s\n", map_num(r5layout, layout));
- break;
- case LEVEL_FAULTY:
- layout = map_name(faultylayout, "default");
+ if (layout != UnSet)
+ return layout;
- if (verbose > 0)
- pr_err("layout defaults to %s\n", map_num(faultylayout, layout));
- break;
- }
+ switch (level) {
+ default: /* no layout */
+ layout = 0;
+ break;
+ case 0:
+ layout = RAID0_ORIG_LAYOUT;
+ break;
+ case 10:
+ layout = 0x102; /* near=2, far=1 */
+ layout_name = "n2";
+ break;
+ case 5:
+ case 6:
+ layout_map = r5layout;
+ break;
+ case LEVEL_FAULTY:
+ layout_map = faultylayout;
+ break;
+ }
+
+ if (layout_map) {
+ layout = map_name(layout_map, "default");
+ layout_name = map_num_s(layout_map, layout);
+ }
+ if (layout_name && verbose > 0)
+ pr_err("layout defaults to %s\n", layout_name);
return layout;
}
@@ -80,7 +95,7 @@ int Create(struct supertype *st, char *mddev,
char *name, int *uuid,
int subdevs, struct mddev_dev *devlist,
struct shape *s,
- struct context *c, unsigned long long data_offset)
+ struct context *c)
{
/*
* Create a new raid array.
@@ -273,7 +288,7 @@ int Create(struct supertype *st, char *mddev,
newsize = s->size * 2;
if (st && ! st->ss->validate_geometry(st, s->level, s->layout, s->raiddisks,
&s->chunk, s->size*2,
- data_offset, NULL,
+ s->data_offset, NULL,
&newsize, s->consistency_policy,
c->verbose >= 0))
return 1;
@@ -308,10 +323,10 @@ int Create(struct supertype *st, char *mddev,
info.array.working_disks = 0;
dnum = 0;
for (dv = devlist; dv; dv = dv->next)
- if (data_offset == VARIABLE_OFFSET)
+ if (s->data_offset == VARIABLE_OFFSET)
dv->data_offset = INVALID_SECTORS;
else
- dv->data_offset = data_offset;
+ dv->data_offset = s->data_offset;
for (dv=devlist; dv && !have_container; dv=dv->next, dnum++) {
char *dname = dv->devname;
@@ -327,7 +342,7 @@ int Create(struct supertype *st, char *mddev,
missing_disks ++;
continue;
}
- if (data_offset == VARIABLE_OFFSET) {
+ if (s->data_offset == VARIABLE_OFFSET) {
doff = strchr(dname, ':');
if (doff) {
*doff++ = 0;
@@ -335,7 +350,7 @@ int Create(struct supertype *st, char *mddev,
} else
dv->data_offset = INVALID_SECTORS;
} else
- dv->data_offset = data_offset;
+ dv->data_offset = s->data_offset;
dfd = open(dname, O_RDONLY);
if (dfd < 0) {
@@ -472,7 +487,7 @@ int Create(struct supertype *st, char *mddev,
st->minor_version >= 1)
/* metadata at front */
warn |= check_partitions(fd, dname, 0, 0);
- else if (s->level == 1 || s->level == LEVEL_CONTAINER ||
+ else if (s->level == 1 || is_container(s->level) ||
(s->level == 0 && s->raiddisks == 1))
/* partitions could be meaningful */
warn |= check_partitions(fd, dname, freesize*2, s->size*2);
@@ -520,7 +535,7 @@ int Create(struct supertype *st, char *mddev,
if (!st->ss->validate_geometry(st, s->level, s->layout,
s->raiddisks,
&s->chunk, minsize*2,
- data_offset,
+ s->data_offset,
NULL, NULL,
s->consistency_policy, 0)) {
pr_err("devices too large for RAID level %d\n", s->level);
@@ -739,7 +754,7 @@ int Create(struct supertype *st, char *mddev,
}
}
if (!st->ss->init_super(st, &info.array, s, name, c->homehost, uuid,
- data_offset))
+ s->data_offset))
goto abort_locked;
total_slots = info.array.nr_disks;
@@ -982,7 +997,7 @@ int Create(struct supertype *st, char *mddev,
* again returns container info.
*/
st->ss->getinfo_super(st, &info_new, NULL);
- if (st->ss->external && s->level != LEVEL_CONTAINER &&
+ if (st->ss->external && !is_container(s->level) &&
!same_uuid(info_new.uuid, info.uuid, 0)) {
map_update(&map, fd2devnm(mdfd),
info_new.text_version,
@@ -1025,7 +1040,7 @@ int Create(struct supertype *st, char *mddev,
map_unlock(&map);
free(infos);
- if (s->level == LEVEL_CONTAINER) {
+ if (is_container(s->level)) {
/* No need to start. But we should signal udev to
* create links */
sysfs_uevent(&info, "change");
diff --git a/Detail.c b/Detail.c
index 95d4cc7..ce7a844 100644
--- a/Detail.c
+++ b/Detail.c
@@ -495,8 +495,8 @@ int Detail(char *dev, struct context *c)
if (array.state & (1 << MD_SB_CLEAN)) {
if ((array.level == 0) ||
(array.level == LEVEL_LINEAR))
- arrayst = map_num(sysfs_array_states,
- sra->array_state);
+ arrayst = map_num_s(sysfs_array_states,
+ sra->array_state);
else
arrayst = "clean";
} else {
diff --git a/Examine.c b/Examine.c
index 9574a3c..c9605a6 100644
--- a/Examine.c
+++ b/Examine.c
@@ -117,7 +117,7 @@ int Examine(struct mddev_dev *devlist,
}
if (c->SparcAdjust)
- st->ss->update_super(st, NULL, "sparc2.2",
+ st->ss->update_super(st, NULL, UOPT_SPARC22,
devlist->devname, 0, 0, NULL);
/* Ok, its good enough to try, though the checksum could be wrong */
diff --git a/Grow.c b/Grow.c
index 9c6fc95..bb5fe45 100644
--- a/Grow.c
+++ b/Grow.c
@@ -26,7 +26,6 @@
#include <sys/mman.h>
#include <stddef.h>
#include <stdint.h>
-#include <signal.h>
#include <sys/wait.h>
#if ! defined(__BIG_ENDIAN) && ! defined(__LITTLE_ENDIAN)
@@ -197,7 +196,7 @@ int Grow_Add_device(char *devname, int fd, char *newdev)
info.disk.minor = minor(rdev);
info.disk.raid_disk = d;
info.disk.state = (1 << MD_DISK_SYNC) | (1 << MD_DISK_ACTIVE);
- if (st->ss->update_super(st, &info, "linear-grow-new", newdev,
+ if (st->ss->update_super(st, &info, UOPT_SPEC_LINEAR_GROW_NEW, newdev,
0, 0, NULL) != 0) {
pr_err("Preparing new metadata failed on %s\n", newdev);
close(nfd);
@@ -255,7 +254,7 @@ int Grow_Add_device(char *devname, int fd, char *newdev)
info.array.active_disks = nd+1;
info.array.working_disks = nd+1;
- if (st->ss->update_super(st, &info, "linear-grow-update", dv,
+ if (st->ss->update_super(st, &info, UOPT_SPEC_LINEAR_GROW_UPDATE, dv,
0, 0, NULL) != 0) {
pr_err("Updating metadata failed on %s\n", dv);
close(fd2);
@@ -430,9 +429,10 @@ int Grow_addbitmap(char *devname, int fd, struct context *c, struct shape *s)
dv = map_dev(disk.major, disk.minor, 1);
if (!dv)
continue;
- if (((disk.state & (1 << MD_DISK_WRITEMOSTLY)) == 0) &&
+ if ((disk.state & (1 << MD_DISK_WRITEMOSTLY)) &&
(strcmp(s->bitmap_file, "clustered") == 0)) {
pr_err("%s disks marked write-mostly are not supported with clustered bitmap\n",devname);
+ free(mdi);
return 1;
}
fd2 = dev_open(dv, O_RDWR);
@@ -454,8 +454,10 @@ int Grow_addbitmap(char *devname, int fd, struct context *c, struct shape *s)
pr_err("failed to load super-block.\n");
}
close(fd2);
- if (rv)
+ if (rv) {
+ free(mdi);
return 1;
+ }
}
if (offset_setable) {
st->ss->getinfo_super(st, mdi, NULL);
@@ -548,7 +550,7 @@ int Grow_consistency_policy(char *devname, int fd, struct context *c, struct sha
if (s->consistency_policy != CONSISTENCY_POLICY_RESYNC &&
s->consistency_policy != CONSISTENCY_POLICY_PPL) {
pr_err("Operation not supported for consistency policy %s\n",
- map_num(consistency_policies, s->consistency_policy));
+ map_num_s(consistency_policies, s->consistency_policy));
return 1;
}
@@ -579,14 +581,14 @@ int Grow_consistency_policy(char *devname, int fd, struct context *c, struct sha
if (sra->consistency_policy == (unsigned)s->consistency_policy) {
pr_err("Consistency policy is already %s\n",
- map_num(consistency_policies, s->consistency_policy));
+ map_num_s(consistency_policies, s->consistency_policy));
ret = 1;
goto free_info;
} else if (sra->consistency_policy != CONSISTENCY_POLICY_RESYNC &&
sra->consistency_policy != CONSISTENCY_POLICY_PPL) {
pr_err("Current consistency policy is %s, cannot change to %s\n",
- map_num(consistency_policies, sra->consistency_policy),
- map_num(consistency_policies, s->consistency_policy));
+ map_num_s(consistency_policies, sra->consistency_policy),
+ map_num_s(consistency_policies, s->consistency_policy));
ret = 1;
goto free_info;
}
@@ -603,12 +605,12 @@ int Grow_consistency_policy(char *devname, int fd, struct context *c, struct sha
}
if (subarray) {
- char *update;
+ enum update_opt update;
if (s->consistency_policy == CONSISTENCY_POLICY_PPL)
- update = "ppl";
+ update = UOPT_PPL;
else
- update = "no-ppl";
+ update = UOPT_NO_PPL;
sprintf(container_dev, "/dev/%s", st->container_devnm);
@@ -666,7 +668,7 @@ int Grow_consistency_policy(char *devname, int fd, struct context *c, struct sha
goto free_info;
}
- ret = st->ss->update_super(st, sra, "ppl",
+ ret = st->ss->update_super(st, sra, UOPT_PPL,
devname,
c->verbose, 0, NULL);
if (ret) {
@@ -705,8 +707,8 @@ int Grow_consistency_policy(char *devname, int fd, struct context *c, struct sha
}
ret = sysfs_set_str(sra, NULL, "consistency_policy",
- map_num(consistency_policies,
- s->consistency_policy));
+ map_num_s(consistency_policies,
+ s->consistency_policy));
if (ret)
pr_err("Failed to change array consistency policy\n");
@@ -955,7 +957,7 @@ int start_reshape(struct mdinfo *sra, int already_running,
err = sysfs_set_str(sra, NULL, "sync_action",
"reshape");
if (err)
- sleep(1);
+ sleep_for(1, 0, true);
} while (err && errno == EBUSY && cnt-- > 0);
}
return err;
@@ -1001,8 +1003,8 @@ int remove_disks_for_takeover(struct supertype *st,
rv = 1;
sysfs_free(arrays);
if (rv) {
- pr_err("Error. Cannot perform operation on /dev/%s\n", st->devnm);
- pr_err("For this operation it MUST be single array in container\n");
+ pr_err("Error. Cannot perform operation on %s- for this operation "
+ "it MUST be single array in container\n", st->devnm);
return rv;
}
}
@@ -1774,9 +1776,67 @@ static int reshape_container(char *container, char *devname,
char *backup_file, int verbose,
int forked, int restart, int freeze_reshape);
+/**
+ * prepare_external_reshape() - prepares update on external metadata if supported.
+ * @devname: Device name.
+ * @subarray: Subarray.
+ * @st: Supertype.
+ * @container: Container.
+ * @cfd: Container file descriptor.
+ *
+ * Function checks that the requested reshape is supported on external metadata,
+ * and performs an initial check that the container holds the pre-requisite
+ * spare devices (mdmon owns final validation).
+ *
+ * Return: 0 on success, else 1
+ */
+static int prepare_external_reshape(char *devname, char *subarray,
+ struct supertype *st, char *container,
+ const int cfd)
+{
+ struct mdinfo *cc = NULL;
+ struct mdinfo *content = NULL;
+
+ if (st->ss->load_container(st, cfd, NULL)) {
+ pr_err("Cannot read superblock for %s\n", devname);
+ return 1;
+ }
+
+ if (!st->ss->container_content)
+ return 1;
+
+ cc = st->ss->container_content(st, subarray);
+ for (content = cc; content ; content = content->next) {
+ /*
+ * check if reshape is allowed based on metadata
+ * indications stored in content.array.status
+ */
+ if (is_bit_set(&content->array.state, MD_SB_BLOCK_VOLUME) ||
+ is_bit_set(&content->array.state, MD_SB_BLOCK_CONTAINER_RESHAPE)) {
+ pr_err("Cannot reshape arrays in container with unsupported metadata: %s(%s)\n",
+ devname, container);
+ goto error;
+ }
+ if (content->consistency_policy == CONSISTENCY_POLICY_PPL) {
+ pr_err("Operation not supported when ppl consistency policy is enabled\n");
+ goto error;
+ }
+ if (content->consistency_policy == CONSISTENCY_POLICY_BITMAP) {
+ pr_err("Operation not supported when write-intent bitmap consistency policy is enabled\n");
+ goto error;
+ }
+ }
+ sysfs_free(cc);
+ if (mdmon_running(container))
+ st->update_tail = &st->updates;
+ return 0;
+error:
+ sysfs_free(cc);
+ return 1;
+}
+
int Grow_reshape(char *devname, int fd,
struct mddev_dev *devlist,
- unsigned long long data_offset,
struct context *c, struct shape *s)
{
/* Make some changes in the shape of an array.
@@ -1801,7 +1861,7 @@ int Grow_reshape(char *devname, int fd,
struct supertype *st;
char *subarray = NULL;
- int frozen;
+ int frozen = 0;
int changed = 0;
char *container = NULL;
int cfd = -1;
@@ -1810,7 +1870,7 @@ int Grow_reshape(char *devname, int fd,
int added_disks;
struct mdinfo info;
- struct mdinfo *sra;
+ struct mdinfo *sra = NULL;
if (md_get_array_info(fd, &array) < 0) {
pr_err("%s is not an active md array - aborting\n",
@@ -1822,7 +1882,7 @@ int Grow_reshape(char *devname, int fd,
return 1;
}
- if (data_offset != INVALID_SECTORS && array.level != 10 &&
+ if (s->data_offset != INVALID_SECTORS && array.level != 10 &&
(array.level < 4 || array.level > 6)) {
pr_err("--grow --data-offset not yet supported\n");
return 1;
@@ -1867,13 +1927,7 @@ int Grow_reshape(char *devname, int fd,
}
}
- /* in the external case we need to check that the requested reshape is
- * supported, and perform an initial check that the container holds the
- * pre-requisite spare devices (mdmon owns final validation)
- */
if (st->ss->external) {
- int retval;
-
if (subarray) {
container = st->container_devnm;
cfd = open_dev_excl(st->container_devnm);
@@ -1889,58 +1943,20 @@ int Grow_reshape(char *devname, int fd,
return 1;
}
- retval = st->ss->load_container(st, cfd, NULL);
-
- if (retval) {
- pr_err("Cannot read superblock for %s\n", devname);
+ rv = prepare_external_reshape(devname, subarray, st,
+ container, cfd);
+ if (rv > 0) {
free(subarray);
- return 1;
+ close(cfd);
+ goto release;
}
- /* check if operation is supported for metadata handler */
- if (st->ss->container_content) {
- struct mdinfo *cc = NULL;
- struct mdinfo *content = NULL;
-
- cc = st->ss->container_content(st, subarray);
- for (content = cc; content ; content = content->next) {
- int allow_reshape = 1;
-
- /* check if reshape is allowed based on metadata
- * indications stored in content.array.status
- */
- if (content->array.state &
- (1 << MD_SB_BLOCK_VOLUME))
- allow_reshape = 0;
- if (content->array.state &
- (1 << MD_SB_BLOCK_CONTAINER_RESHAPE))
- allow_reshape = 0;
- if (!allow_reshape) {
- pr_err("cannot reshape arrays in container with unsupported metadata: %s(%s)\n",
- devname, container);
- sysfs_free(cc);
- free(subarray);
- return 1;
- }
- if (content->consistency_policy ==
- CONSISTENCY_POLICY_PPL) {
- pr_err("Operation not supported when ppl consistency policy is enabled\n");
- sysfs_free(cc);
- free(subarray);
- return 1;
- }
- if (content->consistency_policy ==
- CONSISTENCY_POLICY_BITMAP) {
- pr_err("Operation not supported when write-intent bitmap is enabled\n");
- sysfs_free(cc);
- free(subarray);
- return 1;
- }
- }
- sysfs_free(cc);
+ if (s->raiddisks && subarray) {
+ pr_err("--raid-devices operation can be performed on a container only\n");
+ close(cfd);
+ free(subarray);
+ return 1;
}
- if (mdmon_running(container))
- st->update_tail = &st->updates;
}
added_disks = 0;
@@ -1998,6 +2014,12 @@ int Grow_reshape(char *devname, int fd,
goto release;
}
+ if (array.level == 0) {
+ pr_err("Component size change is not supported for RAID0\n");
+ rv = 1;
+ goto release;
+ }
+
if (reshape_super(st, s->size, UnSet, UnSet, 0, 0, UnSet, NULL,
devname, APPLY_METADATA_CHANGES,
c->verbose > 0)) {
@@ -2156,7 +2178,7 @@ size_change_error:
devname, s->size);
}
changed = 1;
- } else if (array.level != LEVEL_CONTAINER) {
+ } else if (!is_container(array.level)) {
s->size = get_component_size(fd)/2;
if (s->size == 0)
s->size = array.size;
@@ -2166,7 +2188,7 @@ size_change_error:
if ((s->level == UnSet || s->level == array.level) &&
(s->layout_str == NULL) &&
(s->chunk == 0 || s->chunk == array.chunk_size) &&
- data_offset == INVALID_SECTORS &&
+ s->data_offset == INVALID_SECTORS &&
(s->raiddisks == 0 || s->raiddisks == array.raid_disks)) {
/* Nothing more to do */
if (!changed && c->verbose >= 0)
@@ -2212,7 +2234,7 @@ size_change_error:
info.component_size = s->size*2;
info.new_level = s->level;
info.new_chunk = s->chunk * 1024;
- if (info.array.level == LEVEL_CONTAINER) {
+ if (is_container(info.array.level)) {
info.delta_disks = UnSet;
info.array.raid_disks = s->raiddisks;
} else if (s->raiddisks)
@@ -2236,7 +2258,7 @@ size_change_error:
info.new_layout = UnSet;
if (info.array.level == 6 && info.new_level == UnSet) {
char l[40], *h;
- strcpy(l, map_num(r6layout, info.array.layout));
+ strcpy(l, map_num_s(r6layout, info.array.layout));
h = strrchr(l, '-');
if (h && strcmp(h, "-6") == 0) {
*h = 0;
@@ -2261,7 +2283,7 @@ size_change_error:
info.new_layout = info.array.layout;
else if (info.array.level == 5 && info.new_level == 6) {
char l[40];
- strcpy(l, map_num(r5layout, info.array.layout));
+ strcpy(l, map_num_s(r5layout, info.array.layout));
strcat(l, "-6");
info.new_layout = map_name(r6layout, l);
} else {
@@ -2325,7 +2347,7 @@ size_change_error:
printf("layout for %s set to %d\n",
devname, array.layout);
}
- } else if (array.level == LEVEL_CONTAINER) {
+ } else if (is_container(array.level)) {
/* This change is to be applied to every array in the
* container. This is only needed when the metadata imposes
* restraints of the various arrays in the container.
@@ -2366,7 +2388,7 @@ size_change_error:
}
sync_metadata(st);
rv = reshape_array(container, fd, devname, st, &info, c->force,
- devlist, data_offset, c->backup_file,
+ devlist, s->data_offset, c->backup_file,
c->verbose, 0, 0, 0);
frozen = 0;
}
@@ -2931,7 +2953,7 @@ static int impose_level(int fd, int level, char *devname, int verbose)
}
md_get_array_info(fd, &array);
- if (level == 0 && (array.level >= 4 && array.level <= 6)) {
+ if (level == 0 && is_level456(array.level)) {
/* To convert to RAID0 we need to fail and
* remove any non-data devices. */
int found = 0;
@@ -3221,7 +3243,7 @@ static int reshape_array(char *container, int fd, char *devname,
* level and frozen, we can safely add them.
*/
if (devlist) {
- if (Manage_subdevs(devname, fd, devlist, verbose, 0, NULL, 0))
+ if (Manage_subdevs(devname, fd, devlist, verbose, 0, UOPT_UNDEFINED, 0))
goto release;
}
@@ -3501,7 +3523,6 @@ started:
return 0;
}
- close(fd);
/* Now we just need to kick off the reshape and watch, while
* handling backups of the data...
* This is all done by a forked background process.
@@ -3522,6 +3543,9 @@ started:
break;
}
+ /* Close unused file descriptor in the forked process */
+ close_fd(&fd);
+
/* If another array on the same devices is busy, the
* reshape will wait for them. This would mean that
* the first section that we suspend will stay suspended
@@ -3560,7 +3584,8 @@ started:
fd = -1;
mlockall(MCL_FUTURE);
- signal(SIGTERM, catch_term);
+ if (signal_s(SIGTERM, catch_term) == SIG_ERR)
+ goto release;
if (st->ss->external) {
/* metadata handler takes it from here */
@@ -4925,7 +4950,8 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist,
continue;
st->ss->getinfo_super(st, &dinfo, NULL);
dinfo.reshape_progress = info->reshape_progress;
- st->ss->update_super(st, &dinfo, "_reshape_progress",
+ st->ss->update_super(st, &dinfo,
+ UOPT_SPEC__RESHAPE_PROGRESS,
NULL,0, 0, NULL);
st->ss->store_super(st, fdlist[j]);
st->ss->free_super(st);
@@ -5042,7 +5068,7 @@ int Grow_continue_command(char *devname, int fd,
}
st->ss->getinfo_super(st, content, NULL);
if (!content->reshape_active)
- sleep(3);
+ sleep_for(3, 0, true);
else
break;
} while (cnt-- > 0);
diff --git a/Incremental.c b/Incremental.c
index a57fc32..09b94b9 100644
--- a/Incremental.c
+++ b/Incremental.c
@@ -244,7 +244,7 @@ int Incremental(struct mddev_dev *devlist, struct context *c,
c->autof = ci->autof;
name_to_use = info.name;
- if (name_to_use[0] == 0 && info.array.level == LEVEL_CONTAINER) {
+ if (name_to_use[0] == 0 && is_container(info.array.level)) {
name_to_use = info.text_version;
trustworthy = METADATA;
}
@@ -472,7 +472,7 @@ int Incremental(struct mddev_dev *devlist, struct context *c,
/* 7/ Is there enough devices to possibly start the array? */
/* 7a/ if not, finish with success. */
- if (info.array.level == LEVEL_CONTAINER) {
+ if (is_container(info.array.level)) {
char devnm[32];
/* Try to assemble within the container */
sysfs_uevent(sra, "change");
@@ -1025,7 +1025,7 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol,
close(dfd);
*dfdp = -1;
rv = Manage_subdevs(chosen->sys_name, mdfd, &devlist,
- -1, 0, NULL, 0);
+ -1, 0, UOPT_UNDEFINED, 0);
close(mdfd);
}
if (verbose > 0) {
@@ -1499,7 +1499,7 @@ static int Incremental_container(struct supertype *st, char *devname,
return 0;
}
for (ra = list ; ra ; ra = ra->next) {
- int mdfd;
+ int mdfd = -1;
char chosen_name[1024];
struct map_ent *mp;
struct mddev_ident *match = NULL;
@@ -1514,6 +1514,12 @@ static int Incremental_container(struct supertype *st, char *devname,
if (mp) {
mdfd = open_dev(mp->devnm);
+ if (!is_fd_valid(mdfd)) {
+ pr_err("failed to open %s: %s.\n",
+ mp->devnm, strerror(errno));
+ rv = 2;
+ goto release;
+ }
if (mp->path)
strcpy(chosen_name, mp->path);
else
@@ -1573,21 +1579,25 @@ static int Incremental_container(struct supertype *st, char *devname,
c->autof,
trustworthy,
chosen_name, 0);
+
+ if (!is_fd_valid(mdfd)) {
+ pr_err("create_mddev failed with chosen name %s: %s.\n",
+ chosen_name, strerror(errno));
+ rv = 2;
+ goto release;
+ }
}
- if (only && (!mp || strcmp(mp->devnm, only) != 0))
- continue;
- if (mdfd < 0) {
- pr_err("failed to open %s: %s.\n",
- chosen_name, strerror(errno));
- return 2;
+ if (only && (!mp || strcmp(mp->devnm, only) != 0)) {
+ close_fd(&mdfd);
+ continue;
}
assemble_container_content(st, mdfd, ra, c,
chosen_name, &result);
map_free(map);
map = NULL;
- close(mdfd);
+ close_fd(&mdfd);
}
if (c->export && result) {
char sep = '=';
@@ -1610,7 +1620,11 @@ static int Incremental_container(struct supertype *st, char *devname,
}
printf("\n");
}
- return 0;
+
+release:
+ map_free(map);
+ sysfs_free(list);
+ return rv;
}
static void run_udisks(char *arg1, char *arg2)
@@ -1652,7 +1666,7 @@ static void remove_from_member_array(struct mdstat_ent *memb,
if (subfd >= 0) {
rv = Manage_subdevs(memb->devnm, subfd, devlist, verbose,
- 0, NULL, 0);
+ 0, UOPT_UNDEFINED, 0);
if (rv & 2) {
if (sysfs_init(&mmdi, -1, memb->devnm))
pr_err("unable to initialize sysfs for: %s\n",
@@ -1730,7 +1744,7 @@ int IncrementalRemove(char *devname, char *id_path, int verbose)
memset(&devlist, 0, sizeof(devlist));
devlist.devname = devname;
- devlist.disposition = 'f';
+ devlist.disposition = 'I';
/* for a container, we must fail each member array */
if (ent->metadata_version &&
strncmp(ent->metadata_version, "external:", 9) == 0) {
@@ -1744,7 +1758,7 @@ int IncrementalRemove(char *devname, char *id_path, int verbose)
free_mdstat(mdstat);
} else {
rv |= Manage_subdevs(ent->devnm, mdfd, &devlist,
- verbose, 0, NULL, 0);
+ verbose, 0, UOPT_UNDEFINED, 0);
if (rv & 2) {
/* Failed due to EBUSY, try to stop the array.
* Give udisks a chance to unmount it first.
@@ -1756,7 +1770,7 @@ int IncrementalRemove(char *devname, char *id_path, int verbose)
devlist.disposition = 'r';
rv = Manage_subdevs(ent->devnm, mdfd, &devlist,
- verbose, 0, NULL, 0);
+ verbose, 0, UOPT_UNDEFINED, 0);
end:
close(mdfd);
free_mdstat(ent);
diff --git a/Makefile b/Makefile
index 2a51d81..5eac1a4 100644
--- a/Makefile
+++ b/Makefile
@@ -160,7 +160,7 @@ SRCS = $(patsubst %.o,%.c,$(OBJS))
INCL = mdadm.h part.h bitmap.h
-MON_OBJS = mdmon.o monitor.o managemon.o uuid.o util.o maps.o mdstat.o sysfs.o \
+MON_OBJS = mdmon.o monitor.o managemon.o uuid.o util.o maps.o mdstat.o sysfs.o config.o mapfile.o mdopen.o\
policy.o lib.o \
Kill.o sg_io.o dlink.o ReadMe.o super-intel.o \
super-mbr.o super-gpt.o \
@@ -182,9 +182,9 @@ check_rundir:
echo "***** or set CHECK_RUN_DIR=0"; exit 1; \
fi
-everything: all mdadm.static swap_super test_stripe raid6check \
+everything: all swap_super test_stripe raid6check \
mdadm.Os mdadm.O2 man
-everything-test: all mdadm.static swap_super test_stripe \
+everything-test: all swap_super test_stripe \
mdadm.Os mdadm.O2 man
# mdadm.uclibc doesn't work on x86-64
# mdadm.tcc doesn't work..
@@ -227,7 +227,12 @@ raid6check : raid6check.o mdadm.h $(CHECK_OBJS)
mdadm.8 : mdadm.8.in
sed -e 's/{DEFAULT_METADATA}/$(DEFAULT_METADATA)/g' \
- -e 's,{MAP_PATH},$(MAP_PATH),g' mdadm.8.in > mdadm.8
+ -e 's,{MAP_PATH},$(MAP_PATH),g' -e 's,{CONFFILE},$(CONFFILE),g' \
+ -e 's,{CONFFILE2},$(CONFFILE2),g' mdadm.8.in > mdadm.8
+
+mdadm.conf.5 : mdadm.conf.5.in
+ sed -e 's,{CONFFILE},$(CONFFILE),g' \
+ -e 's,{CONFFILE2},$(CONFFILE2),g' mdadm.conf.5.in > mdadm.conf.5
mdadm.man : mdadm.8
man -l mdadm.8 > mdadm.man
diff --git a/Manage.c b/Manage.c
index f789e0c..fde6aba 100644
--- a/Manage.c
+++ b/Manage.c
@@ -244,7 +244,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry)
"array_state",
"inactive")) < 0 &&
errno == EBUSY) {
- usleep(200000);
+ sleep_for(0, MSEC_TO_NSEC(200), true);
count--;
}
if (err) {
@@ -307,7 +307,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry)
* - unfreeze reshape
* - wait on 'sync_completed' for that point to be reached.
*/
- if (mdi && (mdi->array.level >= 4 && mdi->array.level <= 6) &&
+ if (mdi && is_level456(mdi->array.level) &&
sysfs_attribute_available(mdi, NULL, "sync_action") &&
sysfs_attribute_available(mdi, NULL, "reshape_direction") &&
sysfs_get_str(mdi, NULL, "sync_action", buf, 20) > 0 &&
@@ -328,7 +328,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry)
sysfs_get_ll(mdi, NULL, "sync_max", &old_sync_max) == 0) {
/* must be in the critical section - wait a bit */
delay -= 1;
- usleep(100000);
+ sleep_for(0, MSEC_TO_NSEC(100), true);
}
if (sysfs_set_str(mdi, NULL, "sync_action", "frozen") != 0)
@@ -405,7 +405,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry)
* quite started yet. Wait a bit and
* check 'sync_action' to see.
*/
- usleep(10000);
+ sleep_for(0, MSEC_TO_NSEC(10), true);
sysfs_get_str(mdi, NULL, "sync_action", buf, sizeof(buf));
if (strncmp(buf, "reshape", 7) != 0)
break;
@@ -447,7 +447,7 @@ done:
count = 25; err = 0;
while (count && fd >= 0 &&
(err = ioctl(fd, STOP_ARRAY, NULL)) < 0 && errno == EBUSY) {
- usleep(200000);
+ sleep_for(0, MSEC_TO_NSEC(200), true);
count --;
}
if (fd >= 0 && err) {
@@ -598,9 +598,8 @@ static void add_set(struct mddev_dev *dv, int fd, char set_char)
int attempt_re_add(int fd, int tfd, struct mddev_dev *dv,
struct supertype *dev_st, struct supertype *tst,
- unsigned long rdev,
- char *update, char *devname, int verbose,
- mdu_array_info_t *array)
+ unsigned long rdev, enum update_opt update,
+ char *devname, int verbose, mdu_array_info_t *array)
{
struct mdinfo mdi;
int duuid[4];
@@ -666,19 +665,19 @@ int attempt_re_add(int fd, int tfd, struct mddev_dev *dv,
if (dv->writemostly == FlagSet)
rv = dev_st->ss->update_super(
- dev_st, NULL, "writemostly",
+ dev_st, NULL, UOPT_SPEC_WRITEMOSTLY,
devname, verbose, 0, NULL);
if (dv->writemostly == FlagClear)
rv = dev_st->ss->update_super(
- dev_st, NULL, "readwrite",
+ dev_st, NULL, UOPT_SPEC_READWRITE,
devname, verbose, 0, NULL);
if (dv->failfast == FlagSet)
rv = dev_st->ss->update_super(
- dev_st, NULL, "failfast",
+ dev_st, NULL, UOPT_SPEC_FAILFAST,
devname, verbose, 0, NULL);
if (dv->failfast == FlagClear)
rv = dev_st->ss->update_super(
- dev_st, NULL, "nofailfast",
+ dev_st, NULL, UOPT_SPEC_NOFAILFAST,
devname, verbose, 0, NULL);
if (update)
rv = dev_st->ss->update_super(
@@ -714,8 +713,8 @@ skip_re_add:
int Manage_add(int fd, int tfd, struct mddev_dev *dv,
struct supertype *tst, mdu_array_info_t *array,
int force, int verbose, char *devname,
- char *update, unsigned long rdev, unsigned long long array_size,
- int raid_slot)
+ enum update_opt update, unsigned long rdev,
+ unsigned long long array_size, int raid_slot)
{
unsigned long long ldsize;
struct supertype *dev_st;
@@ -1105,7 +1104,7 @@ int Manage_remove(struct supertype *tst, int fd, struct mddev_dev *dv,
ret = sysfs_unique_holder(devnm, rdev);
if (ret < 2)
break;
- usleep(100 * 1000); /* 100ms */
+ sleep_for(0, MSEC_TO_NSEC(100), true);
} while (--count > 0);
if (ret == 0) {
@@ -1285,38 +1284,97 @@ int Manage_with(struct supertype *tst, int fd, struct mddev_dev *dv,
return -1;
}
+/**
+ * is_remove_safe() - Check if remove is safe.
+ * @array: Array info.
+ * @fd: Array file descriptor.
+ * @devname: Name of device to remove.
+ * @verbose: Verbose.
+ *
+ * The function determines if array will be operational
+ * after removing &devname.
+ *
+ * Return: True if array will be operational, false otherwise.
+ */
+bool is_remove_safe(mdu_array_info_t *array, const int fd, char *devname, const int verbose)
+{
+ dev_t devid = devnm2devid(devname + 5);
+ struct mdinfo *mdi = sysfs_read(fd, NULL, GET_DEVS | GET_DISKS | GET_STATE);
+
+ if (!mdi) {
+ if (verbose)
+ pr_err("Failed to read sysfs attributes for %s\n", devname);
+ return false;
+ }
+
+ char *avail = xcalloc(array->raid_disks, sizeof(char));
+
+ for (mdi = mdi->devs; mdi; mdi = mdi->next) {
+ if (mdi->disk.raid_disk < 0)
+ continue;
+ if (!(mdi->disk.state & (1 << MD_DISK_SYNC)))
+ continue;
+ if (makedev(mdi->disk.major, mdi->disk.minor) == devid)
+ continue;
+ avail[mdi->disk.raid_disk] = 1;
+ }
+ sysfs_free(mdi);
+
+ bool is_enough = enough(array->level, array->raid_disks,
+ array->layout, 1, avail);
+
+ free(avail);
+ return is_enough;
+}
+
+/**
+ * Manage_subdevs() - Execute operation depending on devmode.
+ *
+ * @devname: name of the device.
+ * @fd: file descriptor.
+ * @devlist: list of sub-devices to manage.
+ * @verbose: verbose level.
+ * @test: test flag.
+ * @update: type of update.
+ * @force: force flag.
+ *
+ * This function executes operation defined by devmode
+ * for each dev from devlist.
+ * Devmode can be:
+ * 'a' - add the device
+ * 'S' - add the device as a spare - don't try re-add
+ * 'j' - add the device as a journal device
+ * 'A' - re-add the device
+ * 'r' - remove the device: HOT_REMOVE_DISK
+ * device can be 'faulty' or 'detached' in which case all
+ * matching devices are removed.
+ * 'f' - set the device faulty SET_DISK_FAULTY
+ * device can be 'detached' in which case any device that
+ * is inaccessible will be marked faulty.
+ * 'I' - remove device by using incremental fail
+ * which is executed when device is removed surprisingly.
+ * 'R' - mark this device as wanting replacement.
+ * 'W' - this device is added if necessary and activated as
+ * a replacement for a previous 'R' device.
+ * -----
+ * 'w' - 'W' will be changed to 'w' when it is paired with
+ * a 'R' device. If a 'W' is found while walking the list
+ * it must be unpaired, and is an error.
+ * 'M' - this is created by a 'missing' target. It is a slight
+ * variant on 'A'
+ * 'F' - Another variant of 'A', where the device was faulty
+ * so must be removed from the array first.
+ * 'c' - confirm the device as found (for clustered environments)
+ *
+ * For 'f' and 'r', the device can also be a kernel-internal
+ * name such as 'sdb'.
+ *
+ * Return: 0 on success, otherwise 1 or 2.
+ */
int Manage_subdevs(char *devname, int fd,
struct mddev_dev *devlist, int verbose, int test,
- char *update, int force)
+ enum update_opt update, int force)
{
- /* Do something to each dev.
- * devmode can be
- * 'a' - add the device
- * 'S' - add the device as a spare - don't try re-add
- * 'j' - add the device as a journal device
- * 'A' - re-add the device
- * 'r' - remove the device: HOT_REMOVE_DISK
- * device can be 'faulty' or 'detached' in which case all
- * matching devices are removed.
- * 'f' - set the device faulty SET_DISK_FAULTY
- * device can be 'detached' in which case any device that
- * is inaccessible will be marked faulty.
- * 'R' - mark this device as wanting replacement.
- * 'W' - this device is added if necessary and activated as
- * a replacement for a previous 'R' device.
- * -----
- * 'w' - 'W' will be changed to 'w' when it is paired with
- * a 'R' device. If a 'W' is found while walking the list
- * it must be unpaired, and is an error.
- * 'M' - this is created by a 'missing' target. It is a slight
- * variant on 'A'
- * 'F' - Another variant of 'A', where the device was faulty
- * so must be removed from the array first.
- * 'c' - confirm the device as found (for clustered environments)
- *
- * For 'f' and 'r', the device can also be a kernel-internal
- * name such as 'sdb'.
- */
mdu_array_info_t array;
unsigned long long array_size;
struct mddev_dev *dv;
@@ -1452,8 +1510,9 @@ int Manage_subdevs(char *devname, int fd,
/* Assume this is a kernel-internal name like 'sda1' */
int found = 0;
char dname[55];
- if (dv->disposition != 'r' && dv->disposition != 'f') {
- pr_err("%s only meaningful with -r or -f, not -%c\n",
+ if (dv->disposition != 'r' && dv->disposition != 'f' &&
+ dv->disposition != 'I') {
+ pr_err("%s only meaningful with -r, -f or -I, not -%c\n",
dv->devname, dv->disposition);
goto abort;
}
@@ -1598,7 +1657,14 @@ int Manage_subdevs(char *devname, int fd,
break;
case 'f': /* set faulty */
- /* FIXME check current member */
+ if (!is_remove_safe(&array, fd, dv->devname, verbose)) {
+ pr_err("Cannot remove %s from %s, array will be failed.\n",
+ dv->devname, devname);
+ if (sysfd >= 0)
+ close(sysfd);
+ goto abort;
+ }
+ case 'I': /* incremental fail */
if ((sysfd >= 0 && write(sysfd, "faulty", 6) != 6) ||
(sysfd < 0 && ioctl(fd, SET_DISK_FAULTY,
rdev))) {
@@ -1675,10 +1741,13 @@ int autodetect(void)
return rv;
}
-int Update_subarray(char *dev, char *subarray, char *update, struct mddev_ident *ident, int verbose)
+int Update_subarray(char *dev, char *subarray, enum update_opt update,
+ struct mddev_ident *ident, int verbose)
{
struct supertype supertype, *st = &supertype;
int fd, rv = 2;
+ struct mdinfo *info = NULL;
+ char *update_verb = map_num(update_options, update);
memset(st, 0, sizeof(*st));
@@ -1693,25 +1762,41 @@ int Update_subarray(char *dev, char *subarray, char *update, struct mddev_ident
goto free_super;
}
+ if (is_subarray_active(subarray, st->devnm)) {
+ if (verbose >= 0)
+ pr_err("Subarray %s in %s is active, cannot update %s\n",
+ subarray, dev, update_verb);
+ goto free_super;
+ }
+
if (mdmon_running(st->devnm))
st->update_tail = &st->updates;
+ info = st->ss->container_content(st, subarray);
+
+ if (update == UOPT_PPL && !is_level456(info->array.level)) {
+ pr_err("RWH policy ppl is supported only for raid4, raid5 and raid6.\n");
+ goto free_super;
+ }
+
rv = st->ss->update_subarray(st, subarray, update, ident);
if (rv) {
if (verbose >= 0)
pr_err("Failed to update %s of subarray-%s in %s\n",
- update, subarray, dev);
+ update_verb, subarray, dev);
} else if (st->update_tail)
flush_metadata_updates(st);
else
st->ss->sync_metadata(st);
- if (rv == 0 && strcmp(update, "name") == 0 && verbose >= 0)
+ if (rv == 0 && update == UOPT_NAME && verbose >= 0)
pr_err("Updated subarray-%s name from %s, UUIDs may have changed\n",
subarray, dev);
- free_super:
+free_super:
+ if (info)
+ free(info);
st->ss->free_super(st);
close(fd);
@@ -1746,10 +1831,10 @@ int move_spare(char *from_devname, char *to_devname, dev_t devid)
sprintf(devname, "%d:%d", major(devid), minor(devid));
devlist.disposition = 'r';
- if (Manage_subdevs(from_devname, fd2, &devlist, -1, 0, NULL, 0) == 0) {
+ if (Manage_subdevs(from_devname, fd2, &devlist, -1, 0, UOPT_UNDEFINED, 0) == 0) {
devlist.disposition = 'a';
if (Manage_subdevs(to_devname, fd1, &devlist, -1, 0,
- NULL, 0) == 0) {
+ UOPT_UNDEFINED, 0) == 0) {
/* make sure manager is aware of changes */
ping_manager(to_devname);
ping_manager(from_devname);
@@ -1759,7 +1844,7 @@ int move_spare(char *from_devname, char *to_devname, dev_t devid)
}
else
Manage_subdevs(from_devname, fd2, &devlist,
- -1, 0, NULL, 0);
+ -1, 0, UOPT_UNDEFINED, 0);
}
close(fd1);
close(fd2);
diff --git a/Monitor.c b/Monitor.c
index 30c031a..188cb8b 100644
--- a/Monitor.c
+++ b/Monitor.c
@@ -26,7 +26,6 @@
#include "md_p.h"
#include "md_u.h"
#include <sys/wait.h>
-#include <signal.h>
#include <limits.h>
#include <syslog.h>
#ifndef NO_LIBUDEV
@@ -34,8 +33,8 @@
#endif
struct state {
- char *devname;
- char devnm[32]; /* to sync with mdstat info */
+ char devname[MD_NAME_MAX + sizeof("/dev/md/")]; /* length of "/dev/md/" + device name + terminating byte*/
+ char devnm[MD_NAME_MAX]; /* to sync with mdstat info */
unsigned int utime;
int err;
char *spare_group;
@@ -46,9 +45,9 @@ struct state {
int devstate[MAX_DISKS];
dev_t devid[MAX_DISKS];
int percent;
- char parent_devnm[32]; /* For subarray, devnm of parent.
- * For others, ""
- */
+ char parent_devnm[MD_NAME_MAX]; /* For subarray, devnm of parent.
+ * For others, ""
+ */
struct supertype *metadata;
struct state *subarray;/* for a container it is a link to first subarray
* for a subarray it is a link to next subarray
@@ -67,7 +66,7 @@ struct alert_info {
static int make_daemon(char *pidfile);
static int check_one_sharer(int scan);
static void write_autorebuild_pid(void);
-static void alert(char *event, char *dev, char *disc, struct alert_info *info);
+static void alert(const char *event, const char *dev, const char *disc, struct alert_info *info);
static int check_array(struct state *st, struct mdstat_ent *mdstat,
int test, struct alert_info *info,
int increments, char *prefer);
@@ -75,6 +74,7 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist,
int test, struct alert_info *info);
static void try_spare_migration(struct state *statelist, struct alert_info *info);
static void link_containers_with_subarrays(struct state *list);
+static void free_statelist(struct state *statelist);
#ifndef NO_LIBUDEV
static int check_udev_activity(void);
#endif
@@ -123,13 +123,12 @@ int Monitor(struct mddev_dev *devlist,
* and if we can get_disk_info and find a name
* Then we hot-remove and hot-add to the other array
*
- * If devlist is NULL, then we can monitor everything because --scan
+ * If devlist is NULL, then we can monitor everything if --scan
* was given. We get an initial list from config file and add anything
* that appears in /proc/mdstat
*/
struct state *statelist = NULL;
- struct state *st2;
int finished = 0;
struct mdstat_ent *mdstat = NULL;
char *mailfrom;
@@ -137,24 +136,32 @@ int Monitor(struct mddev_dev *devlist,
struct mddev_ident *mdlist;
int delay_for_event = c->delay;
- if (!mailaddr) {
- mailaddr = conf_get_mailaddr();
- if (mailaddr && ! c->scan)
- pr_err("Monitor using email address \"%s\" from config file\n",
- mailaddr);
+ if (devlist && c->scan) {
+ pr_err("Devices list and --scan option cannot be combined - not monitoring.\n");
+ return 1;
}
- mailfrom = conf_get_mailfrom();
- if (!alert_cmd) {
+ if (!mailaddr)
+ mailaddr = conf_get_mailaddr();
+
+ if (!alert_cmd)
alert_cmd = conf_get_program();
- if (alert_cmd && !c->scan)
- pr_err("Monitor using program \"%s\" from config file\n",
- alert_cmd);
- }
+
+ mailfrom = conf_get_mailfrom();
+
if (c->scan && !mailaddr && !alert_cmd && !dosyslog) {
pr_err("No mail address or alert command - not monitoring.\n");
return 1;
}
+
+ if (c->verbose) {
+ pr_err("Monitor is started with delay %ds\n", c->delay);
+ if (mailaddr)
+ pr_err("Monitor using email address %s\n", mailaddr);
+ if (alert_cmd)
+ pr_err("Monitor using program %s\n", alert_cmd);
+ }
+
info.alert_cmd = alert_cmd;
info.mailaddr = mailaddr;
info.mailfrom = mailfrom;
@@ -183,14 +190,12 @@ int Monitor(struct mddev_dev *devlist,
continue;
if (strcasecmp(mdlist->devname, "<ignore>") == 0)
continue;
+ if (!is_mddev(mdlist->devname))
+ continue;
+
st = xcalloc(1, sizeof *st);
- if (mdlist->devname[0] == '/')
- st->devname = xstrdup(mdlist->devname);
- else {
- st->devname = xmalloc(8+strlen(mdlist->devname)+1);
- strcpy(strcpy(st->devname, "/dev/md/"),
- mdlist->devname);
- }
+ snprintf(st->devname, MD_NAME_MAX + sizeof("/dev/md/"),
+ "/dev/md/%s", basename(mdlist->devname));
st->next = statelist;
st->devnm[0] = 0;
st->percent = RESYNC_UNKNOWN;
@@ -204,9 +209,14 @@ int Monitor(struct mddev_dev *devlist,
struct mddev_dev *dv;
for (dv = devlist; dv; dv = dv->next) {
- struct state *st = xcalloc(1, sizeof *st);
+ struct state *st;
+
+ if (!is_mddev(dv->devname))
+ continue;
+
+ st = xcalloc(1, sizeof *st);
mdlist = conf_get_ident(dv->devname);
- st->devname = xstrdup(dv->devname);
+ snprintf(st->devname, MD_NAME_MAX + sizeof("/dev/md/"), "%s", dv->devname);
st->next = statelist;
st->devnm[0] = 0;
st->percent = RESYNC_UNKNOWN;
@@ -289,17 +299,16 @@ int Monitor(struct mddev_dev *devlist,
for (stp = &statelist; (st = *stp) != NULL; ) {
if (st->from_auto && st->err > 5) {
*stp = st->next;
- free(st->devname);
- free(st->spare_group);
+ if (st->spare_group)
+ free(st->spare_group);
+
free(st);
} else
stp = &st->next;
}
}
- for (st2 = statelist; st2; st2 = statelist) {
- statelist = st2->next;
- free(st2);
- }
+
+ free_statelist(statelist);
if (pidfile)
unlink(pidfile);
@@ -403,109 +412,115 @@ static void write_autorebuild_pid()
}
}
-static void alert(char *event, char *dev, char *disc, struct alert_info *info)
+static void execute_alert_cmd(const char *event, const char *dev, const char *disc, struct alert_info *info)
+{
+ int pid = fork();
+
+ switch (pid) {
+ default:
+ waitpid(pid, NULL, 0);
+ break;
+ case -1:
+ pr_err("Cannot fork to execute alert command");
+ break;
+ case 0:
+ execl(info->alert_cmd, info->alert_cmd, event, dev, disc, NULL);
+ exit(2);
+ }
+}
+
+static void send_event_email(const char *event, const char *dev, const char *disc, struct alert_info *info)
+{
+ FILE *mp, *mdstat;
+ char hname[256];
+ char buf[BUFSIZ];
+ int n;
+
+ mp = popen(Sendmail, "w");
+ if (!mp) {
+ pr_err("Cannot open pipe stream for sendmail.\n");
+ return;
+ }
+
+ gethostname(hname, sizeof(hname));
+ signal(SIGPIPE, SIG_IGN);
+ if (info->mailfrom)
+ fprintf(mp, "From: %s\n", info->mailfrom);
+ else
+ fprintf(mp, "From: %s monitoring <root>\n", Name);
+ fprintf(mp, "To: %s\n", info->mailaddr);
+ fprintf(mp, "Subject: %s event on %s:%s\n\n", event, dev, hname);
+ fprintf(mp, "This is an automatically generated mail message. \n");
+ fprintf(mp, "A %s event had been detected on md device %s.\n\n", event, dev);
+
+ if (disc && disc[0] != ' ')
+ fprintf(mp,
+ "It could be related to component device %s.\n\n", disc);
+ if (disc && disc[0] == ' ')
+ fprintf(mp, "Extra information:%s.\n\n", disc);
+
+ mdstat = fopen("/proc/mdstat", "r");
+ if (!mdstat) {
+ pr_err("Cannot open /proc/mdstat\n");
+ pclose(mp);
+ return;
+ }
+
+ fprintf(mp, "The /proc/mdstat file currently contains the following:\n\n");
+ while ((n = fread(buf, 1, sizeof(buf), mdstat)) > 0)
+ n = fwrite(buf, 1, n, mp);
+ fclose(mdstat);
+ pclose(mp);
+}
+
+static void log_event_to_syslog(const char *event, const char *dev, const char *disc)
{
int priority;
+ /* Log at a different severity depending on the event.
+ *
+ * These are the critical events: */
+ if (strncmp(event, "Fail", 4) == 0 ||
+ strncmp(event, "Degrade", 7) == 0 ||
+ strncmp(event, "DeviceDisappeared", 17) == 0)
+ priority = LOG_CRIT;
+ /* Good to know about, but are not failures: */
+ else if (strncmp(event, "Rebuild", 7) == 0 ||
+ strncmp(event, "MoveSpare", 9) == 0 ||
+ strncmp(event, "Spares", 6) != 0)
+ priority = LOG_WARNING;
+ /* Everything else: */
+ else
+ priority = LOG_INFO;
+ if (disc && disc[0] != ' ')
+ syslog(priority,
+ "%s event detected on md device %s, component device %s", event, dev, disc);
+ else if (disc)
+ syslog(priority, "%s event detected on md device %s: %s", event, dev, disc);
+ else
+ syslog(priority, "%s event detected on md device %s", event, dev);
+}
+
+static void alert(const char *event, const char *dev, const char *disc, struct alert_info *info)
+{
if (!info->alert_cmd && !info->mailaddr && !info->dosyslog) {
time_t now = time(0);
printf("%1.15s: %s on %s %s\n", ctime(&now) + 4,
event, dev, disc?disc:"unknown device");
}
- if (info->alert_cmd) {
- int pid = fork();
- switch(pid) {
- default:
- waitpid(pid, NULL, 0);
- break;
- case -1:
- break;
- case 0:
- execl(info->alert_cmd, info->alert_cmd,
- event, dev, disc, NULL);
- exit(2);
- }
- }
+ if (info->alert_cmd)
+ execute_alert_cmd(event, dev, disc, info);
+
if (info->mailaddr && (strncmp(event, "Fail", 4) == 0 ||
strncmp(event, "Test", 4) == 0 ||
strncmp(event, "Spares", 6) == 0 ||
strncmp(event, "Degrade", 7) == 0)) {
- FILE *mp = popen(Sendmail, "w");
- if (mp) {
- FILE *mdstat;
- char hname[256];
- gethostname(hname, sizeof(hname));
- signal(SIGPIPE, SIG_IGN);
- if (info->mailfrom)
- fprintf(mp, "From: %s\n", info->mailfrom);
- else
- fprintf(mp, "From: %s monitoring <root>\n",
- Name);
- fprintf(mp, "To: %s\n", info->mailaddr);
- fprintf(mp, "Subject: %s event on %s:%s\n\n",
- event, dev, hname);
-
- fprintf(mp,
- "This is an automatically generated mail message from %s\n", Name);
- fprintf(mp, "running on %s\n\n", hname);
-
- fprintf(mp,
- "A %s event had been detected on md device %s.\n\n", event, dev);
-
- if (disc && disc[0] != ' ')
- fprintf(mp,
- "It could be related to component device %s.\n\n", disc);
- if (disc && disc[0] == ' ')
- fprintf(mp, "Extra information:%s.\n\n", disc);
-
- fprintf(mp, "Faithfully yours, etc.\n");
-
- mdstat = fopen("/proc/mdstat", "r");
- if (mdstat) {
- char buf[8192];
- int n;
- fprintf(mp,
- "\nP.S. The /proc/mdstat file currently contains the following:\n\n");
- while ((n = fread(buf, 1, sizeof(buf),
- mdstat)) > 0)
- n = fwrite(buf, 1, n, mp);
- fclose(mdstat);
- }
- pclose(mp);
- }
+ send_event_email(event, dev, disc, info);
}
- /* log the event to syslog maybe */
- if (info->dosyslog) {
- /* Log at a different severity depending on the event.
- *
- * These are the critical events: */
- if (strncmp(event, "Fail", 4) == 0 ||
- strncmp(event, "Degrade", 7) == 0 ||
- strncmp(event, "DeviceDisappeared", 17) == 0)
- priority = LOG_CRIT;
- /* Good to know about, but are not failures: */
- else if (strncmp(event, "Rebuild", 7) == 0 ||
- strncmp(event, "MoveSpare", 9) == 0 ||
- strncmp(event, "Spares", 6) != 0)
- priority = LOG_WARNING;
- /* Everything else: */
- else
- priority = LOG_INFO;
-
- if (disc && disc[0] != ' ')
- syslog(priority,
- "%s event detected on md device %s, component device %s", event, dev, disc);
- else if (disc)
- syslog(priority,
- "%s event detected on md device %s: %s",
- event, dev, disc);
- else
- syslog(priority,
- "%s event detected on md device %s",
- event, dev);
- }
+ if (info->dosyslog)
+ log_event_to_syslog(event, dev, disc);
}
static int check_array(struct state *st, struct mdstat_ent *mdstat,
@@ -540,7 +555,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
goto disappeared;
if (st->devnm[0] == 0)
- strcpy(st->devnm, fd2devnm(fd));
+ snprintf(st->devnm, MD_NAME_MAX, "%s", fd2devnm(fd));
for (mse2 = mdstat; mse2; mse2 = mse2->next)
if (strcmp(mse2->devnm, st->devnm) == 0) {
@@ -670,7 +685,7 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
strncmp(mse->metadata_version, "external:", 9) == 0 &&
is_subarray(mse->metadata_version+9)) {
char *sl;
- strcpy(st->parent_devnm, mse->metadata_version + 10);
+ snprintf(st->parent_devnm, MD_NAME_MAX, "%s", mse->metadata_version + 10);
sl = strchr(st->parent_devnm, '/');
if (sl)
*sl = 0;
@@ -758,14 +773,13 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist,
continue;
}
- st->devname = xstrdup(name);
+ snprintf(st->devname, MD_NAME_MAX + sizeof("/dev/md/"), "%s", name);
if ((fd = open(st->devname, O_RDONLY)) < 0 ||
md_get_array_info(fd, &array) < 0) {
/* no such array */
if (fd >= 0)
close(fd);
put_md_name(st->devname);
- free(st->devname);
if (st->metadata) {
st->metadata->ss->free_super(st->metadata);
free(st->metadata);
@@ -777,7 +791,7 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist,
st->next = *statelist;
st->err = 1;
st->from_auto = 1;
- strcpy(st->devnm, mse->devnm);
+ snprintf(st->devnm, MD_NAME_MAX, "%s", mse->devnm);
st->percent = RESYNC_UNKNOWN;
st->expected_spares = -1;
if (mse->metadata_version &&
@@ -785,8 +799,8 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist,
"external:", 9) == 0 &&
is_subarray(mse->metadata_version+9)) {
char *sl;
- strcpy(st->parent_devnm,
- mse->metadata_version+10);
+ snprintf(st->parent_devnm, MD_NAME_MAX,
+ "%s", mse->metadata_version + 10);
sl = strchr(st->parent_devnm, '/');
*sl = 0;
} else
@@ -1051,6 +1065,24 @@ static void link_containers_with_subarrays(struct state *list)
}
}
+/**
+ * free_statelist() - Frees statelist.
+ * @statelist: statelist to free
+ */
+static void free_statelist(struct state *statelist)
+{
+ struct state *tmp = NULL;
+
+ while (statelist) {
+ if (statelist->spare_group)
+ free(statelist->spare_group);
+
+ tmp = statelist;
+ statelist = statelist->next;
+ free(tmp);
+ }
+}
+
#ifndef NO_LIBUDEV
/* function: check_udev_activity
* Description: Function waits for udev to finish
diff --git a/Query.c b/Query.c
index 23fbf8a..adcd231 100644
--- a/Query.c
+++ b/Query.c
@@ -93,7 +93,7 @@ int Query(char *dev)
else {
printf("%s: %s %s %d devices, %d spare%s. Use mdadm --detail for more detail.\n",
dev, human_size_brief(larray_size,IEC),
- map_num(pers, level), raid_disks,
+ map_num_s(pers, level), raid_disks,
spare_disks, spare_disks == 1 ? "" : "s");
}
st = guess_super(fd);
@@ -131,7 +131,7 @@ int Query(char *dev)
dev,
info.disk.number, info.array.raid_disks,
activity,
- map_num(pers, info.array.level),
+ map_num_s(pers, info.array.level),
mddev);
if (st->ss == &super0)
put_md_name(mddev);
diff --git a/ReadMe.c b/ReadMe.c
index 8139976..bd8d50d 100644
--- a/ReadMe.c
+++ b/ReadMe.c
@@ -81,11 +81,12 @@ char Version[] = "mdadm - v" VERSION " - " VERS_DATE EXTRAVERSION "\n";
* found, it is started.
*/
-char short_options[]="-ABCDEFGIQhVXYWZ:vqbc:i:l:p:m:r:n:x:u:c:d:z:U:N:safRSow1tye:k";
+char short_options[]="-ABCDEFGIQhVXYWZ:vqbc:i:l:p:m:n:x:u:c:d:z:U:N:sarfRSow1tye:k:";
+char short_monitor_options[]="-ABCDEFGIQhVXYWZ:vqbc:i:l:p:m:r:n:x:u:c:d:z:U:N:safRSow1tye:k:";
char short_bitmap_options[]=
- "-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:r:n:x:u:c:d:z:U:N:sarfRSow1tye:k:";
+ "-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:n:x:u:c:d:z:U:N:sarfRSow1tye:k:";
char short_bitmap_auto_options[]=
- "-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:r:n:x:u:c:d:z:U:N:sa:rfRSow1tye:k:";
+ "-ABCDEFGIQhVXYWZ:vqb:c:i:l:p:m:n:x:u:c:d:z:U:N:sa:rfRSow1tye:k:";
struct option long_options[] = {
{"manage", 0, 0, ManageOpt},
@@ -146,7 +147,6 @@ struct option long_options[] = {
{"nofailfast",0, 0, NoFailFast},
{"re-add", 0, 0, ReAdd},
{"homehost", 1, 0, HomeHost},
- {"symlinks", 1, 0, Symlinks},
{"data-offset",1, 0, DataOffset},
{"nodes",1, 0, Nodes}, /* also for --assemble */
{"home-cluster",1, 0, ClusterName},
@@ -477,7 +477,7 @@ char Help_assemble[] =
;
char Help_manage[] =
-"Usage: mdadm arraydevice options component devices...\n"
+"Usage: mdadm [mode] arraydevice [options] <component devices...>\n"
"\n"
"This usage is for managing the component devices within an array.\n"
"The --manage option is not needed and is assumed if the first argument\n"
@@ -613,7 +613,6 @@ char Help_incr[] =
;
char Help_config[] =
-"The /etc/mdadm.conf config file:\n\n"
" The config file contains, apart from blank lines and comment lines that\n"
" start with a hash(#), array lines, device lines, and various\n"
" configuration lines.\n"
@@ -636,10 +635,12 @@ char Help_config[] =
" than a device must match all of them to be considered.\n"
"\n"
" Other configuration lines include:\n"
-" mailaddr, mailfrom, program used for --monitor mode\n"
-" create, auto used when creating device names in /dev\n"
-" homehost, policy, part-policy used to guide policy in various\n"
-" situations\n"
+" mailaddr, mailfrom, program, monitordelay used for --monitor mode\n"
+" create, auto used when creating device names in /dev\n"
+" homehost, homecluster, policy, part-policy used to guide policy in various\n"
+" situations\n"
+"\n"
+"For more details see mdadm.conf(5).\n"
"\n"
;
@@ -654,3 +655,34 @@ char *mode_help[mode_count] = {
[GROW] = Help_grow,
[INCREMENTAL] = Help_incr,
};
+
+/**
+ * fprint_update_options() - Print valid update options depending on the mode.
+ * @outf: File (output stream)
+ * @update_mode: Used to distinguish update and update_subarray
+ */
+void fprint_update_options(FILE *outf, enum update_opt update_mode)
+{
+ int counter = UOPT_NAME, breakpoint = UOPT_HELP;
+ mapping_t *map = update_options;
+
+ if (!outf)
+ return;
+ if (update_mode == UOPT_SUBARRAY_ONLY) {
+ breakpoint = UOPT_SUBARRAY_ONLY;
+ fprintf(outf, "Valid --update options for update-subarray are:\n\t");
+ } else
+ fprintf(outf, "Valid --update options are:\n\t");
+ while (map->num) {
+ if (map->num >= breakpoint)
+ break;
+ fprintf(outf, "'%s', ", map->name);
+ if (counter % 5 == 0)
+ fprintf(outf, "\n\t");
+ counter++;
+ map++;
+ }
+ if ((counter - 1) % 5)
+ fprintf(outf, "\n");
+ fprintf(outf, "\r");
+}
diff --git a/config.c b/config.c
index 9c72545..eeedd0c 100644
--- a/config.c
+++ b/config.c
@@ -119,6 +119,34 @@ int match_keyword(char *word)
return -1;
}
+/**
+ * ident_init() - Set defaults.
+ * @ident: ident pointer, not NULL.
+ */
+inline void ident_init(struct mddev_ident *ident)
+{
+ assert(ident);
+
+ ident->assembled = false;
+ ident->autof = 0;
+ ident->bitmap_fd = -1;
+ ident->bitmap_file = NULL;
+ ident->container = NULL;
+ ident->devices = NULL;
+ ident->devname = NULL;
+ ident->level = UnSet;
+ ident->member = NULL;
+ ident->name[0] = 0;
+ ident->next = NULL;
+ ident->raid_disks = UnSet;
+ ident->spare_group = NULL;
+ ident->spare_disks = 0;
+ ident->st = NULL;
+ ident->super_minor = UnSet;
+ ident->uuid[0] = 0;
+ ident->uuid_set = 0;
+}
+
struct conf_dev {
struct conf_dev *next;
char *name;
@@ -194,7 +222,6 @@ struct mddev_dev *load_containers(void)
struct createinfo createinfo = {
.autof = 2, /* by default, create devices with standard names */
- .symlinks = 1,
.names = 0, /* By default, stick with numbered md devices. */
.bblist = 1, /* Use a bad block list by default */
#ifdef DEBIAN
@@ -310,11 +337,7 @@ static void createline(char *line)
if (!createinfo.supertype)
pr_err("metadata format %s unknown, ignoring\n",
w+9);
- } else if (strncasecmp(w, "symlinks=yes", 12) == 0)
- createinfo.symlinks = 1;
- else if (strncasecmp(w, "symlinks=no", 11) == 0)
- createinfo.symlinks = 0;
- else if (strncasecmp(w, "names=yes", 12) == 0)
+ } else if (strncasecmp(w, "names=yes", 12) == 0)
createinfo.names = 1;
else if (strncasecmp(w, "names=no", 11) == 0)
createinfo.names = 0;
@@ -368,22 +391,7 @@ void arrayline(char *line)
struct mddev_ident mis;
struct mddev_ident *mi;
- mis.uuid_set = 0;
- mis.super_minor = UnSet;
- mis.level = UnSet;
- mis.raid_disks = UnSet;
- mis.spare_disks = 0;
- mis.devices = NULL;
- mis.devname = NULL;
- mis.spare_group = NULL;
- mis.autof = 0;
- mis.next = NULL;
- mis.st = NULL;
- mis.bitmap_fd = -1;
- mis.bitmap_file = NULL;
- mis.name[0] = 0;
- mis.container = NULL;
- mis.member = NULL;
+ ident_init(&mis);
for (w = dl_next(line); w != line; w = dl_next(w)) {
if (w[0] == '/' || strchr(w, '=') == NULL) {
diff --git a/lib.c b/lib.c
index 7e3e3d4..e395b28 100644
--- a/lib.c
+++ b/lib.c
@@ -164,6 +164,18 @@ char *stat2devnm(struct stat *st)
return devid2devnm(st->st_rdev);
}
+bool stat_is_md_dev(struct stat *st)
+{
+ if ((S_IFMT & st->st_mode) != S_IFBLK)
+ return false;
+ if (major(st->st_rdev) == MD_MAJOR)
+ return true;
+ if (major(st->st_rdev) == (unsigned)get_mdp_major())
+ return true;
+
+ return false;
+}
+
char *fd2devnm(int fd)
{
struct stat stb;
diff --git a/managemon.c b/managemon.c
index bb7334c..a7bfa8f 100644
--- a/managemon.c
+++ b/managemon.c
@@ -106,7 +106,6 @@
#include "mdmon.h"
#include <sys/syscall.h>
#include <sys/socket.h>
-#include <signal.h>
static void close_aa(struct active_array *aa)
{
@@ -208,7 +207,7 @@ static void replace_array(struct supertype *container,
remove_old();
while (pending_discard) {
while (discard_this == NULL)
- sleep(1);
+ sleep_for(1, 0, true);
remove_old();
}
pending_discard = old;
@@ -569,7 +568,7 @@ static void manage_member(struct mdstat_ent *mdstat,
updates = NULL;
while (update_queue_pending || update_queue) {
check_update_queue(container);
- usleep(15*1000);
+ sleep_for(0, MSEC_TO_NSEC(15), true);
}
replace_array(container, a, newa);
if (sysfs_set_str(&a->info, NULL,
@@ -823,7 +822,7 @@ static void handle_message(struct supertype *container, struct metadata_update *
if (msg->len <= 0)
while (update_queue_pending || update_queue) {
check_update_queue(container);
- usleep(15*1000);
+ sleep_for(0, MSEC_TO_NSEC(15), true);
}
if (msg->len == 0) { /* ping_monitor */
@@ -837,7 +836,7 @@ static void handle_message(struct supertype *container, struct metadata_update *
wakeup_monitor();
while (monitor_loop_cnt - cnt < 0)
- usleep(10 * 1000);
+ sleep_for(0, MSEC_TO_NSEC(10), true);
} else if (msg->len == -1) { /* ping_manager */
struct mdstat_ent *mdstat = mdstat_read(1, 0);
diff --git a/maps.c b/maps.c
index a4fd279..b586679 100644
--- a/maps.c
+++ b/maps.c
@@ -165,7 +165,62 @@ mapping_t sysfs_array_states[] = {
{ "broken", ARRAY_BROKEN },
{ NULL, ARRAY_UNKNOWN_STATE }
};
+/**
+ * mapping_t update_options - stores supported update options.
+ */
+mapping_t update_options[] = {
+ { "name", UOPT_NAME },
+ { "ppl", UOPT_PPL },
+ { "no-ppl", UOPT_NO_PPL },
+ { "bitmap", UOPT_BITMAP },
+ { "no-bitmap", UOPT_NO_BITMAP },
+ { "sparc2.2", UOPT_SPARC22 },
+ { "super-minor", UOPT_SUPER_MINOR },
+ { "summaries", UOPT_SUMMARIES },
+ { "resync", UOPT_RESYNC },
+ { "uuid", UOPT_UUID },
+ { "homehost", UOPT_HOMEHOST },
+ { "home-cluster", UOPT_HOME_CLUSTER },
+ { "nodes", UOPT_NODES },
+ { "devicesize", UOPT_DEVICESIZE },
+ { "bbl", UOPT_BBL },
+ { "no-bbl", UOPT_NO_BBL },
+ { "force-no-bbl", UOPT_FORCE_NO_BBL },
+ { "metadata", UOPT_METADATA },
+ { "revert-reshape", UOPT_REVERT_RESHAPE },
+ { "layout-original", UOPT_LAYOUT_ORIGINAL },
+ { "layout-alternate", UOPT_LAYOUT_ALTERNATE },
+ { "layout-unspecified", UOPT_LAYOUT_UNSPECIFIED },
+ { "byteorder", UOPT_BYTEORDER },
+ { "help", UOPT_HELP },
+ { "?", UOPT_HELP },
+ { NULL, UOPT_UNDEFINED}
+};
+/**
+ * map_num_s() - Safer alternative of map_num() function.
+ * @map: map to search.
+ * @num: key to match.
+ *
+ * Shall be used only if key existence is quaranted.
+ *
+ * Return: Pointer to name of the element.
+ */
+char *map_num_s(mapping_t *map, int num)
+{
+ char *ret = map_num(map, num);
+
+ assert(ret);
+ return ret;
+}
+
+/**
+ * map_num() - get element name by key.
+ * @map: map to search.
+ * @num: key to match.
+ *
+ * Return: Pointer to name of the element or NULL.
+ */
char *map_num(mapping_t *map, int num)
{
while (map->name) {
diff --git a/mdadm.8.in b/mdadm.8.in
index be902db..64f71ed 100644
--- a/mdadm.8.in
+++ b/mdadm.8.in
@@ -158,7 +158,7 @@ adding new spares and removing faulty devices.
.B Misc
This is an 'everything else' mode that supports operations on active
arrays, operations on component devices such as erasing old superblocks, and
-information gathering operations.
+information-gathering operations.
.\"This mode allows operations on independent devices such as examine MD
.\"superblocks, erasing old superblocks and stopping active arrays.
@@ -231,12 +231,12 @@ mode to be assumed.
.TP
.BR \-h ", " \-\-help
-Display general help message or, after one of the above options, a
+Display a general help message or, after one of the above options, a
mode-specific help message.
.TP
.B \-\-help\-options
-Display more detailed help about command line parsing and some commonly
+Display more detailed help about command-line parsing and some commonly
used options.
.TP
@@ -266,14 +266,11 @@ the exact meaning of this option in different contexts.
.TP
.BR \-c ", " \-\-config=
-Specify the config file or directory. Default is to use
-.B /etc/mdadm.conf
-and
-.BR /etc/mdadm.conf.d ,
-or if those are missing then
-.B /etc/mdadm/mdadm.conf
-and
-.BR /etc/mdadm/mdadm.conf.d .
+Specify the config file or directory. If not specified, the default config file
+and default conf.d directory will be used. See
+.BR mdadm.conf (5)
+for more details.
+
If the config file given is
.B "partitions"
then nothing will be read, but
@@ -382,7 +379,7 @@ When creating an array, the
.B homehost
will be recorded in the metadata. For version-1 superblocks, it will
be prefixed to the array name. For version-0.90 superblocks, part of
-the SHA1 hash of the hostname will be stored in the later half of the
+the SHA1 hash of the hostname will be stored in the latter half of the
UUID.
When reporting information about an array, any array which is tagged
@@ -391,7 +388,7 @@ for the given homehost will be reported as such.
When using Auto-Assemble, only arrays tagged for the given homehost
will be allowed to use 'local' names (i.e. not ending in '_' followed
by a digit string). See below under
-.BR "Auto Assembly" .
+.BR "Auto-Assembly" .
The special name "\fBany\fP" can be used as a wild card. If an array
is created with
@@ -406,7 +403,7 @@ When
.I mdadm
needs to print the name for a device it normally finds the name in
.B /dev
-which refers to the device and is shortest. When a path component is
+which refers to the device and is the shortest. When a path component is
given with
.B \-\-prefer
.I mdadm
@@ -459,7 +456,8 @@ number of spare devices.
.TP
.BR \-z ", " \-\-size=
-Amount (in Kilobytes) of space to use from each drive in RAID levels 1/4/5/6.
+Amount (in Kilobytes) of space to use from each drive in RAID levels 1/4/5/6/10
+and for RAID 0 on external metadata.
This must be a multiple of the chunk size, and must leave about 128Kb
of space at the end of the drive for the RAID superblock.
If this is not specified
@@ -478,10 +476,19 @@ To guard against this it can be useful to set the initial size
slightly smaller than the smaller device with the aim that it will
still be larger than any replacement.
+This option can be used with
+.B \-\-create
+for determining the initial size of an array. For external metadata,
+it can be used on a volume, but not on a container itself.
+Setting the initial size of
+.B RAID 0
+array is only valid for external metadata.
+
This value can be set with
.B \-\-grow
-for RAID level 1/4/5/6 though
+for RAID level 1/4/5/6/10 though
DDF arrays may not be able to support this.
+RAID 0 array size cannot be changed.
If the array was created with a size smaller than the currently
active drives, the extra space can be accessed using
.BR \-\-grow .
@@ -501,11 +508,6 @@ problems the array can be made bigger again with no loss with another
.B "\-\-grow \-\-size="
command.
-This value cannot be used when creating a
-.B CONTAINER
-such as with DDF and IMSM metadata, though it perfectly valid when
-creating an array inside a container.
-
.TP
.BR \-Z ", " \-\-array\-size=
This is only meaningful with
@@ -543,20 +545,20 @@ Clustered arrays do not support this parameter yet.
.TP
.BR \-c ", " \-\-chunk=
-Specify chunk size of kilobytes. The default when creating an
+Specify chunk size in kilobytes. The default when creating an
array is 512KB. To ensure compatibility with earlier versions, the
default when building an array with no persistent metadata is 64KB.
This is only meaningful for RAID0, RAID4, RAID5, RAID6, and RAID10.
RAID4, RAID5, RAID6, and RAID10 require the chunk size to be a power
-of 2. In any case it must be a multiple of 4KB.
+of 2, with minimal chunk size being 4KB.
A suffix of 'K', 'M', 'G' or 'T' can be given to indicate Kilobytes,
Megabytes, Gigabytes or Terabytes respectively.
.TP
.BR \-\-rounding=
-Specify rounding factor for a Linear array. The size of each
+Specify the rounding factor for a Linear array. The size of each
component will be rounded down to a multiple of this size.
This is a synonym for
.B \-\-chunk
@@ -653,7 +655,8 @@ option to set subsequent failure modes.
and "flush" will clear any persistent faults.
The layout options for RAID10 are one of 'n', 'o' or 'f' followed
-by a small number. The default is 'n2'. The supported options are:
+by a small number signifying the number of copies of each datablock.
+The default is 'n2'. The supported options are:
.I 'n'
signals 'near' copies. Multiple copies of one data block are at
@@ -671,7 +674,7 @@ signals 'far' copies
(multiple copies have very different offsets).
See md(4) for more detail about 'near', 'offset', and 'far'.
-The number is the number of copies of each datablock. 2 is normal, 3
+As for the number of copies of each data block, 2 is normal, 3
can be useful. This number can be at most equal to the number of
devices in the array. It does not need to divide evenly into that
number (e.g. it is perfectly legal to have an 'n2' layout for an array
@@ -682,7 +685,7 @@ A bug introduced in Linux 3.14 means that RAID0 arrays
started using a different layout. This could lead to
data corruption. Since Linux 5.4 (and various stable releases that received
backports), the kernel will not accept such an array unless
-a layout is explictly set. It can be set to
+a layout is explicitly set. It can be set to
.RB ' original '
or
.RB ' alternate '.
@@ -758,13 +761,13 @@ or by selecting a different consistency policy with
.TP
.BR \-\-bitmap\-chunk=
-Set the chunksize of the bitmap. Each bit corresponds to that many
+Set the chunk size of the bitmap. Each bit corresponds to that many
Kilobytes of storage.
-When using a file based bitmap, the default is to use the smallest
-size that is at-least 4 and requires no more than 2^21 chunks.
+When using a file-based bitmap, the default is to use the smallest
+size that is at least 4 and requires no more than 2^21 chunks.
When using an
.B internal
-bitmap, the chunksize defaults to 64Meg, or larger if necessary to
+bitmap, the chunk size defaults to 64Meg, or larger if necessary to
fit the bitmap into the available space.
A suffix of 'K', 'M', 'G' or 'T' can be given to indicate Kilobytes,
@@ -838,7 +841,7 @@ can be used with that command to avoid the automatic resync.
.BR \-\-backup\-file=
This is needed when
.B \-\-grow
-is used to increase the number of raid-devices in a RAID5 or RAID6 if
+is used to increase the number of raid devices in a RAID5 or RAID6 if
there are no spare devices available, or to shrink, change RAID level
or layout. See the GROW MODE section below on RAID\-DEVICES CHANGES.
The file must be stored on a separate device, not on the RAID array
@@ -877,7 +880,7 @@ When creating an array,
.B \-\-data\-offset
can be specified as
.BR variable .
-In the case each member device is expected to have a offset appended
+In the case each member device is expected to have an offset appended
to the name, separated by a colon. This makes it possible to recreate
exactly an array which has varying data offsets (as can happen when
different versions of
@@ -941,7 +944,7 @@ Insist that
.I mdadm
accept the geometry and layout specified without question. Normally
.I mdadm
-will not allow creation of an array with only one device, and will try
+will not allow the creation of an array with only one device, and will try
to create a RAID5 array with one missing drive (as this makes the
initial resync work faster). With
.BR \-\-force ,
@@ -1002,7 +1005,7 @@ number added, e.g.
If the md device name is in a 'standard' format as described in DEVICE
NAMES, then it will be created, if necessary, with the appropriate
device number based on that name. If the device name is not in one of these
-formats, then a unused device number will be allocated. The device
+formats, then an unused device number will be allocated. The device
number will be considered unused if there is no active array for that
number, and there is no entry in /dev for that number and with a
non-standard name. Names that are not in 'standard' format are only
@@ -1030,30 +1033,25 @@ then
.B \-\-add
can be used to add some extra devices to be included in the array.
In most cases this is not needed as the extra devices can be added as
-spares first, and then the number of raid-disks can be changed.
-However for RAID0, it is not possible to add spares. So to increase
+spares first, and then the number of raid disks can be changed.
+However, for RAID0 it is not possible to add spares. So to increase
the number of devices in a RAID0, it is necessary to set the new
number of devices, and to add the new devices, in the same command.
.TP
.BR \-\-nodes
-Only works when the array is for clustered environment. It specifies
+Only works when the array is created for a clustered environment. It specifies
the maximum number of nodes in the cluster that will use this device
simultaneously. If not specified, this defaults to 4.
.TP
.BR \-\-write-journal
Specify journal device for the RAID-4/5/6 array. The journal device
-should be a SSD with reasonable lifetime.
-
-.TP
-.BR \-\-symlinks
-Auto creation of symlinks in /dev to /dev/md, option --symlinks must
-be 'no' or 'yes' and work with --create and --build.
+should be an SSD with a reasonable lifetime.
.TP
.BR \-k ", " \-\-consistency\-policy=
-Specify how the array maintains consistency in case of unexpected shutdown.
+Specify how the array maintains consistency in the case of an unexpected shutdown.
Only relevant for RAID levels with redundancy.
Currently supported options are:
.RS
@@ -1061,7 +1059,7 @@ Currently supported options are:
.TP
.B resync
Full resync is performed and all redundancy is regenerated when the array is
-started after unclean shutdown.
+started after an unclean shutdown.
.TP
.B bitmap
@@ -1070,8 +1068,8 @@ Resync assisted by a write-intent bitmap. Implicitly selected when using
.TP
.B journal
-For RAID levels 4/5/6, journal device is used to log transactions and replay
-after unclean shutdown. Implicitly selected when using
+For RAID levels 4/5/6, the journal device is used to log transactions and replay
+after an unclean shutdown. Implicitly selected when using
.BR \-\-write\-journal .
.TP
@@ -1240,7 +1238,7 @@ This can be useful if
reports a different "Preferred Minor" to
.BR \-\-detail .
In some cases this update will be performed automatically
-by the kernel driver. In particular the update happens automatically
+by the kernel driver. In particular, the update happens automatically
at the first write to an array with redundancy (RAID level 1 or
greater) on a 2.6 (or later) kernel.
@@ -1280,7 +1278,7 @@ For version-1 superblocks, this involves updating the name.
The
.B home\-cluster
option will change the cluster name as recorded in the superblock and
-bitmap. This option only works for clustered environment.
+bitmap. This option only works for a clustered environment.
The
.B resync
@@ -1393,20 +1391,16 @@ This option should be used with great caution.
.TP
.BR \-\-freeze\-reshape
-Option is intended to be used in start-up scripts during initrd boot phase.
-When array under reshape is assembled during initrd phase, this option
-stops reshape after reshape critical section is being restored. This happens
-before file system pivot operation and avoids loss of file system context.
+This option is intended to be used in start-up scripts during the initrd boot phase.
+When the array under reshape is assembled during the initrd phase, this option
+stops the reshape after the reshape-critical section has been restored. This happens
+before the file system pivot operation and avoids loss of filesystem context.
Losing file system context would cause reshape to be broken.
Reshape can be continued later using the
.B \-\-continue
option for the grow command.
-.TP
-.BR \-\-symlinks
-See this option under Create and Build options.
-
.SH For Manage mode:
.TP
@@ -1444,9 +1438,9 @@ re\-add a device that was previously removed from an array.
If the metadata on the device reports that it is a member of the
array, and the slot that it used is still vacant, then the device will
be added back to the array in the same position. This will normally
-cause the data for that device to be recovered. However based on the
+cause the data for that device to be recovered. However, based on the
event count on the device, the recovery may only require sections that
-are flagged a write-intent bitmap to be recovered or may not require
+are flagged by a write-intent bitmap to be recovered or may not require
any recovery at all.
When used on an array that has no metadata (i.e. it was built with
@@ -1454,13 +1448,12 @@ When used on an array that has no metadata (i.e. it was built with
it will be assumed that bitmap-based recovery is enough to make the
device fully consistent with the array.
-When used with v1.x metadata,
.B \-\-re\-add
-can be accompanied by
+can also be accompanied by
.BR \-\-update=devicesize ,
.BR \-\-update=bbl ", or"
.BR \-\-update=no\-bbl .
-See the description of these option when used in Assemble mode for an
+See descriptions of these options when used in Assemble mode for an
explanation of their use.
If the device name given is
@@ -1487,7 +1480,7 @@ Add a device as a spare. This is similar to
except that it does not attempt
.B \-\-re\-add
first. The device will be added as a spare even if it looks like it
-could be an recent member of the array.
+could be a recent member of the array.
.TP
.BR \-r ", " \-\-remove
@@ -1504,12 +1497,12 @@ and names like
.B set-A
can be given to
.BR \-\-remove .
-The first causes all failed device to be removed. The second causes
+The first causes all failed devices to be removed. The second causes
any device which is no longer connected to the system (i.e an 'open'
returns
.BR ENXIO )
to be removed.
-The third will remove a set as describe below under
+The third will remove a set as described below under
.BR \-\-fail .
.TP
@@ -1526,7 +1519,7 @@ For RAID10 arrays where the number of copies evenly divides the number
of devices, the devices can be conceptually divided into sets where
each set contains a single complete copy of the data on the array.
Sometimes a RAID10 array will be configured so that these sets are on
-separate controllers. In this case all the devices in one set can be
+separate controllers. In this case, all the devices in one set can be
failed by giving a name like
.B set\-A
or
@@ -1556,9 +1549,9 @@ This can follow a list of
.B \-\-replace
devices. The devices listed after
.B \-\-with
-will be preferentially used to replace the devices listed after
+will preferentially be used to replace the devices listed after
.BR \-\-replace .
-These device must already be spare devices in the array.
+These devices must already be spare devices in the array.
.TP
.BR \-\-write\-mostly
@@ -1581,8 +1574,8 @@ the device is found or <slot>:missing in case the device is not found.
.TP
.BR \-\-add-journal
-Add journal to an existing array, or recreate journal for RAID-4/5/6 array
-that lost a journal device. To avoid interrupting on-going write opertions,
+Add a journal to an existing array, or recreate journal for a RAID-4/5/6 array
+that lost a journal device. To avoid interrupting ongoing write operations,
.B \-\-add-journal
only works for array in Read-Only state.
@@ -1638,9 +1631,9 @@ Print details of one or more md devices.
.TP
.BR \-\-detail\-platform
Print details of the platform's RAID capabilities (firmware / hardware
-topology) for a given metadata format. If used without argument, mdadm
+topology) for a given metadata format. If used without an argument, mdadm
will scan all controllers looking for their capabilities. Otherwise, mdadm
-will only look at the controller specified by the argument in form of an
+will only look at the controller specified by the argument in the form of an
absolute filepath or a link, e.g.
.IR /sys/devices/pci0000:00/0000:00:1f.2 .
@@ -1749,8 +1742,8 @@ the block where the superblock would be is overwritten even if it
doesn't appear to be valid.
.B Note:
-Be careful to call \-\-zero\-superblock with clustered raid, make sure
-array isn't used or assembled in other cluster node before execute it.
+Be careful when calling \-\-zero\-superblock with clustered raid. Make sure
+the array isn't used or assembled in another cluster node before executing it.
.TP
.B \-\-kill\-subarray=
@@ -1797,7 +1790,7 @@ For each md device given, or each device in /proc/mdstat if
is given, arrange for the array to be marked clean as soon as possible.
.I mdadm
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 dirty-clean transitions at shutdown. No action is taken
if safe-mode handling is disabled.
@@ -1837,7 +1830,7 @@ uses to help track which arrays are currently being assembled.
.TP
.BR \-\-run ", " \-R
-Run any array assembled as soon as a minimal number of devices are
+Run any array assembled as soon as a minimal number of devices is
available, rather than waiting until all expected devices are present.
.TP
@@ -1867,7 +1860,7 @@ Only used with \-\-fail. The 'path' given will be recorded so that if
a new device appears at the same location it can be automatically
added to the same array. This allows the failed device to be
automatically replaced by a new device without metadata if it appears
-at specified path. This option is normally only set by a
+at specified path. This option is normally only set by an
.I udev
script.
@@ -1968,7 +1961,7 @@ Usage:
.PP
This usage assembles one or more RAID arrays from pre-existing components.
For each array, mdadm needs to know the md device, the identity of the
-array, and a number of component-devices. These can be found in a number of ways.
+array, and the number of component devices. These can be found in a number of ways.
In the first usage example (without the
.BR \-\-scan )
@@ -2008,11 +2001,9 @@ The config file is only used if explicitly named with
.B \-\-config
or requested with (a possibly implicit)
.BR \-\-scan .
-In the later case,
-.B /etc/mdadm.conf
-or
-.B /etc/mdadm/mdadm.conf
-is used.
+In the latter case, the default config file is used. See
+.BR mdadm.conf (5)
+for more details.
If
.B \-\-scan
@@ -2048,14 +2039,14 @@ detects that udev is not configured, it will create the devices in
.B /dev
itself.
-In Linux kernels prior to version 2.6.28 there were two distinctly
-different types of md devices that could be created: one that could be
+In Linux kernels prior to version 2.6.28 there were two distinct
+types of md devices that could be created: one that could be
partitioned using standard partitioning tools and one that could not.
-Since 2.6.28 that distinction is no longer relevant as both type of
+Since 2.6.28 that distinction is no longer relevant as both types of
devices can be partitioned.
.I mdadm
will normally create the type that originally could not be partitioned
-as it has a well defined major number (9).
+as it has a well-defined major number (9).
Prior to 2.6.28, it is important that mdadm chooses the correct type
of array device to use. This can be controlled with the
@@ -2075,7 +2066,7 @@ can also be given in the configuration file as a word starting
.B auto=
on the ARRAY line for the relevant array.
-.SS Auto Assembly
+.SS Auto-Assembly
When
.B \-\-assemble
is used with
@@ -2131,11 +2122,11 @@ See
.IR mdadm.conf (5)
for further details.
-Note: Auto assembly cannot be used for assembling and activating some
+Note: Auto-assembly cannot be used for assembling and activating some
arrays which are undergoing reshape. In particular as the
.B backup\-file
-cannot be given, any reshape which requires a backup-file to continue
-cannot be started by auto assembly. An array which is growing to more
+cannot be given, any reshape which requires a backup file to continue
+cannot be started by auto-assembly. An array which is growing to more
devices and has passed the critical section can be assembled using
auto-assembly.
@@ -2242,7 +2233,7 @@ When creating a partition based array, using
.I mdadm
with version-1.x metadata, the partition type should be set to
.B 0xDA
-(non fs-data). This type selection allows for greater precision since
+(non fs-data). This type of selection allows for greater precision since
using any other [RAID auto-detect (0xFD) or a GNU/Linux partition (0x83)],
might create problems in the event of array recovery through a live cdrom.
@@ -2258,7 +2249,7 @@ when creating a v0.90 array will silently override any
setting.
.\"If the
.\".B \-\-size
-.\"option is given, it is not necessary to list any component-devices in this command.
+.\"option is given, it is not necessary to list any component devices in this command.
.\"They can be added later, before a
.\".B \-\-run.
.\"If no
@@ -2272,7 +2263,7 @@ requested with the
.B \-\-bitmap
option or a different consistency policy is selected with the
.B \-\-consistency\-policy
-option. In any case space for a bitmap will be reserved so that one
+option. In any case, space for a bitmap will be reserved so that one
can be added later with
.BR "\-\-grow \-\-bitmap=internal" .
@@ -2322,7 +2313,7 @@ will firstly mark
as faulty in
.B /dev/md0
and will then remove it from the array and finally add it back
-in as a spare. However only one md array can be affected by a single
+in as a spare. However, only one md array can be affected by a single
command.
When a device is added to an active array, mdadm checks to see if it
@@ -2467,14 +2458,14 @@ config file to be examined.
If the device contains RAID metadata, a file will be created in the
.I directory
and the metadata will be written to it. The file will be the same
-size as the device and have the metadata written in the file at the
-same locate that it exists in the device. However the file will be "sparse" so
+size as the device and will have the metadata written at the
+same location as it exists in the device. However, the file will be "sparse" so
that only those blocks containing metadata will be allocated. The
total space used will be small.
-The file name used in the
+The filename used in the
.I directory
-will be the base name of the device. Further if any links appear in
+will be the base name of the device. Further, if any links appear in
.I /dev/disk/by-id
which point to the device, then hard links to the file will be created
in
@@ -2557,13 +2548,33 @@ Usage:
.I options... devices...
.PP
-This usage causes
+Monitor option can work in two modes:
+.IP \(bu 4
+system wide mode, follow all md devices based on
+.B /proc/mdstat,
+.IP \(bu 4
+follow only specified MD devices in command line.
+.PP
+
+.B \-\-scan -
+indicates system wide mode. Option causes the
+.I monitor
+to track all md devices that appear in
+.B /proc/mdstat.
+If it is not set, then at least one
+.B device
+must be specified.
+
+Monitor usage causes
.I mdadm
to periodically poll a number of md arrays and to report on any events
noticed.
-.I mdadm
-will never exit once it decides that there are arrays to be checked,
-so it should normally be run in the background.
+
+In both modes,
+.I monitor
+will work as long as there is an active array with redundancy and it is defined to follow (for
+.B \-\-scan
+every array is followed).
As well as reporting events,
.I mdadm
@@ -2574,15 +2585,6 @@ or
.B domain
and if the destination array has a failed drive but no spares.
-If any devices are listed on the command line,
-.I mdadm
-will only monitor those devices. Otherwise all arrays listed in the
-configuration file will be monitored. Further, if
-.B \-\-scan
-is given, then any other md devices that appear in
-.B /proc/mdstat
-will also be monitored.
-
The result of monitoring the arrays is the generation of events.
These events are passed to a separate program (if specified) and may
be mailed to a given E-mail address.
@@ -2595,16 +2597,34 @@ device if relevant (such as a component device that has failed).
If
.B \-\-scan
-is given, then a program or an E-mail address must be specified on the
-command line or in the config file. If neither are available, then
+is given, then a
+.B program
+or an
+.B e-mail
+address must be specified on the
+command line or in the config file. If neither are available, then
.I mdadm
will not monitor anything.
-Without
-.B \-\-scan,
-.I mdadm
-will continue monitoring as long as something was found to monitor. If
-no program or email is given, then each event is reported to
-.BR stdout .
+For devices given directly in command line, without
+.B program
+or
+.B email
+specified, each event is reported to
+.BR stdout.
+
+Note: For systems where
+.If mdadm monitor
+is configured via systemd,
+.B mdmonitor(mdmonitor.service)
+should be configured. The service is designed to be primary solution for array monitoring,
+it is configured to work in system wide mode.
+It is automatically started and stopped according to current state and types of MD arrays in system.
+The service may require additional configuration, like
+.B e-mail
+or
+.B delay.
+That should be done in
+.B mdadm.conf.
The different events are:
@@ -2633,10 +2653,10 @@ check, repair). (syslog priority: Warning)
.BI Rebuild NN
Where
.I NN
-is a two-digit number (ie. 05, 48). This indicates that rebuild
-has passed that many percent of the total. The events are generated
-with fixed increment since 0. Increment size may be specified with
-a commandline option (default is 20). (syslog priority: Warning)
+is a two-digit number (eg. 05, 48). This indicates that the rebuild
+has reached that percentage of the total. The events are generated
+at a fixed increment from 0. The increment size may be specified with
+a command-line option (the default is 20). (syslog priority: Warning)
.TP
.B RebuildFinished
@@ -2744,8 +2764,8 @@ When
detects that an array in a spare group has fewer active
devices than necessary for the complete array, and has no spare
devices, it will look for another array in the same spare group that
-has a full complement of working drive and a spare. It will then
-attempt to remove the spare from the second drive and add it to the
+has a full complement of working drives and a spare. It will then
+attempt to remove the spare from the second array and add it to the
first.
If the removal succeeds but the adding fails, then it is added back to
the original array.
@@ -2759,10 +2779,8 @@ and then follow similar steps as above if a matching spare is found.
.SH GROW MODE
The GROW mode is used for changing the size or shape of an active
array.
-For this to work, the kernel must support the necessary change.
-Various types of growth are being added during 2.6 development.
-Currently the supported changes include
+During the kernel 2.6 era the following changes were added:
.IP \(bu 4
change the "size" attribute for RAID1, RAID4, RAID5 and RAID6.
.IP \(bu 4
@@ -2805,8 +2823,8 @@ use more than half of a spare device for backup space.
.SS SIZE CHANGES
Normally when an array is built the "size" is taken from the smallest
-of the drives. If all the small drives in an arrays are, one at a
-time, removed and replaced with larger drives, then you could have an
+of the drives. If all the small drives in an arrays are, over time,
+removed and replaced with larger drives, then you could have an
array of large drives with only a small amount used. In this
situation, changing the "size" with "GROW" mode will allow the extra
space to start being used. If the size is increased in this way, a
@@ -2821,7 +2839,7 @@ after growing, or to reduce its size
.B prior
to shrinking the array.
-Also the size of an array cannot be changed while it has an active
+Also, the size of an array cannot be changed while it has an active
bitmap. If an array has a bitmap, it must be removed before the size
can be changed. Once the change is complete a new bitmap can be created.
@@ -2901,7 +2919,7 @@ long time. A
is required. If the array is not simultaneously being grown or
shrunk, so that the array size will remain the same - for example,
reshaping a 3-drive RAID5 into a 4-drive RAID6 - the backup file will
-be used not just for a "cricital section" but throughout the reshape
+be used not just for a "critical section" but throughout the reshape
operation, as described below under LAYOUT CHANGES.
.SS CHUNK-SIZE AND LAYOUT CHANGES
@@ -2919,7 +2937,7 @@ slowly.
If the reshape is interrupted for any reason, this backup file must be
made available to
.B "mdadm --assemble"
-so the array can be reassembled. Consequently the file cannot be
+so the array can be reassembled. Consequently, the file cannot be
stored on the device being reshaped.
@@ -3339,18 +3357,17 @@ uses this to find arrays when
is given in Misc mode, and to monitor array reconstruction
on Monitor mode.
-.SS /etc/mdadm.conf
+.SS {CONFFILE} (or {CONFFILE2})
-The config file lists which devices may be scanned to see if
-they contain MD super block, and gives identifying information
-(e.g. UUID) about known MD arrays. See
+Default config file. See
.BR mdadm.conf (5)
for more details.
-.SS /etc/mdadm.conf.d
+.SS {CONFFILE}.d (or {CONFFILE2}.d)
-A directory containing configuration files which are read in lexical
-order.
+Default directory containing configuration files. See
+.BR mdadm.conf (5)
+for more details.
.SS {MAP_PATH}
When
diff --git a/mdadm.c b/mdadm.c
index 26299b2..57e8e6f 100644
--- a/mdadm.c
+++ b/mdadm.c
@@ -49,7 +49,6 @@ int main(int argc, char *argv[])
int i;
unsigned long long array_size = 0;
- unsigned long long data_offset = INVALID_SECTORS;
struct mddev_ident ident;
char *configfile = NULL;
int devmode = 0;
@@ -59,7 +58,6 @@ int main(int argc, char *argv[])
struct mddev_dev *dv;
mdu_array_info_t array;
int devs_found = 0;
- char *symlinks = NULL;
int grow_continue = 0;
/* autof indicates whether and how to create device node.
* bottom 3 bits are style. Rest (when shifted) are number of parts
@@ -80,6 +78,7 @@ int main(int argc, char *argv[])
.layout = UnSet,
.bitmap_chunk = UnSet,
.consistency_policy = CONSISTENCY_POLICY_UNKNOWN,
+ .data_offset = INVALID_SECTORS,
};
char sys_hostname[256];
@@ -101,32 +100,20 @@ int main(int argc, char *argv[])
char *dump_directory = NULL;
int print_help = 0;
- FILE *outf;
+ FILE *outf = NULL;
int mdfd = -1;
int locked = 0;
srandom(time(0) ^ getpid());
- ident.uuid_set = 0;
- ident.level = UnSet;
- ident.raid_disks = UnSet;
- ident.super_minor = UnSet;
- ident.devices = 0;
- ident.spare_group = NULL;
- ident.autof = 0;
- ident.st = NULL;
- ident.bitmap_fd = -1;
- ident.bitmap_file = NULL;
- ident.name[0] = 0;
- ident.container = NULL;
- ident.member = NULL;
-
if (get_linux_version() < 2006015) {
pr_err("This version of mdadm does not support kernels older than 2.6.15\n");
exit(1);
}
+ ident_init(&ident);
+
while ((option_index = -1),
(opt = getopt_long(argc, argv, shortopt, long_options,
&option_index)) != -1) {
@@ -227,6 +214,7 @@ int main(int argc, char *argv[])
shortopt = short_bitmap_auto_options;
break;
case 'F': newmode = MONITOR;
+ shortopt = short_monitor_options;
break;
case 'G': newmode = GROW;
shortopt = short_bitmap_options;
@@ -280,8 +268,8 @@ int main(int argc, char *argv[])
else
fprintf(stderr, "-%c", opt);
fprintf(stderr, " would set mdadm mode to \"%s\", but it is already set to \"%s\".\n",
- map_num(modes, newmode),
- map_num(modes, mode));
+ map_num_s(modes, newmode),
+ map_num_s(modes, mode));
exit(2);
} else if (!mode && newmode) {
mode = newmode;
@@ -479,15 +467,15 @@ int main(int argc, char *argv[])
case O(CREATE,DataOffset):
case O(GROW,DataOffset):
- if (data_offset != INVALID_SECTORS) {
+ if (s.data_offset != INVALID_SECTORS) {
pr_err("data-offset may only be specified one. Second value is %s.\n", optarg);
exit(2);
}
if (mode == CREATE && strcmp(optarg, "variable") == 0)
- data_offset = VARIABLE_OFFSET;
+ s.data_offset = VARIABLE_OFFSET;
else
- data_offset = parse_size(optarg);
- if (data_offset == INVALID_SECTORS) {
+ s.data_offset = parse_size(optarg);
+ if (s.data_offset == INVALID_SECTORS) {
pr_err("invalid data-offset: %s\n",
optarg);
exit(2);
@@ -544,7 +532,7 @@ int main(int argc, char *argv[])
switch(s.level) {
default:
pr_err("layout not meaningful for %s arrays.\n",
- map_num(pers, s.level));
+ map_num_s(pers, s.level));
exit(2);
case UnSet:
pr_err("raid level must be given before layout.\n");
@@ -662,13 +650,6 @@ int main(int argc, char *argv[])
case O(ASSEMBLE,Auto): /* auto-creation of device node */
c.autof = parse_auto(optarg, "--auto flag", 0);
continue;
-
- case O(CREATE,Symlinks):
- case O(BUILD,Symlinks):
- case O(ASSEMBLE,Symlinks): /* auto creation of symlinks in /dev to /dev/md */
- symlinks = optarg;
- continue;
-
case O(BUILD,'f'): /* force honouring '-n 1' */
case O(BUILD,Force): /* force honouring '-n 1' */
case O(GROW,'f'): /* ditto */
@@ -742,93 +723,50 @@ int main(int argc, char *argv[])
continue;
case O(ASSEMBLE,'U'): /* update the superblock */
- case O(MISC,'U'):
+ case O(MISC,'U'): {
+ enum update_opt print_mode = UOPT_HELP;
+ const char *error_addon = "update option";
+
if (c.update) {
pr_err("Can only update one aspect of superblock, both %s and %s given.\n",
- c.update, optarg);
+ map_num(update_options, c.update), optarg);
exit(2);
}
if (mode == MISC && !c.subarray) {
pr_err("Only subarrays can be updated in misc mode\n");
exit(2);
}
- c.update = optarg;
- if (strcmp(c.update, "sparc2.2") == 0)
- continue;
- if (strcmp(c.update, "super-minor") == 0)
- continue;
- if (strcmp(c.update, "summaries") == 0)
- continue;
- if (strcmp(c.update, "resync") == 0)
- continue;
- if (strcmp(c.update, "uuid") == 0)
- continue;
- if (strcmp(c.update, "name") == 0)
- continue;
- if (strcmp(c.update, "homehost") == 0)
- continue;
- if (strcmp(c.update, "home-cluster") == 0)
- continue;
- if (strcmp(c.update, "nodes") == 0)
- continue;
- if (strcmp(c.update, "devicesize") == 0)
- continue;
- if (strcmp(c.update, "bitmap") == 0)
- continue;
- if (strcmp(c.update, "no-bitmap") == 0)
- continue;
- if (strcmp(c.update, "bbl") == 0)
- continue;
- if (strcmp(c.update, "no-bbl") == 0)
- continue;
- if (strcmp(c.update, "force-no-bbl") == 0)
- continue;
- if (strcmp(c.update, "ppl") == 0)
- continue;
- if (strcmp(c.update, "no-ppl") == 0)
- continue;
- if (strcmp(c.update, "metadata") == 0)
- continue;
- if (strcmp(c.update, "revert-reshape") == 0)
- continue;
- if (strcmp(c.update, "layout-original") == 0 ||
- strcmp(c.update, "layout-alternate") == 0 ||
- strcmp(c.update, "layout-unspecified") == 0)
- continue;
- if (strcmp(c.update, "byteorder") == 0) {
+
+ c.update = map_name(update_options, optarg);
+
+ if (devmode == UpdateSubarray) {
+ print_mode = UOPT_SUBARRAY_ONLY;
+ error_addon = "update-subarray option";
+
+ if (c.update > UOPT_SUBARRAY_ONLY && c.update < UOPT_HELP)
+ c.update = UOPT_UNDEFINED;
+ }
+
+ switch (c.update) {
+ case UOPT_UNDEFINED:
+ pr_err("'--update=%s' is invalid %s. ",
+ optarg, error_addon);
+ outf = stderr;
+ case UOPT_HELP:
+ if (!outf)
+ outf = stdout;
+ fprint_update_options(outf, print_mode);
+ exit(outf == stdout ? 0 : 2);
+ case UOPT_BYTEORDER:
if (ss) {
pr_err("must not set metadata type with --update=byteorder.\n");
exit(2);
}
- for(i = 0; !ss && superlist[i]; i++)
- ss = superlist[i]->match_metadata_desc(
- "0.swap");
- if (!ss) {
- pr_err("INTERNAL ERROR cannot find 0.swap\n");
- exit(2);
- }
-
- continue;
+ default:
+ break;
}
- if (strcmp(c.update,"?") == 0 ||
- strcmp(c.update, "help") == 0) {
- outf = stdout;
- fprintf(outf, "%s: ", Name);
- } else {
- outf = stderr;
- fprintf(outf,
- "%s: '--update=%s' is invalid. ",
- Name, c.update);
- }
- fprintf(outf, "Valid --update options are:\n"
- " 'sparc2.2', 'super-minor', 'uuid', 'name', 'nodes', 'resync',\n"
- " 'summaries', 'homehost', 'home-cluster', 'byteorder', 'devicesize',\n"
- " 'bitmap', 'no-bitmap', 'metadata', 'revert-reshape'\n"
- " 'bbl', 'no-bbl', 'force-no-bbl', 'ppl', 'no-ppl'\n"
- " 'layout-original', 'layout-alternate', 'layout-unspecified'\n"
- );
- exit(outf == stdout ? 0 : 2);
-
+ continue;
+ }
case O(MANAGE,'U'):
/* update=devicesize is allowed with --re-add */
if (devmode != 'A') {
@@ -837,14 +775,14 @@ int main(int argc, char *argv[])
}
if (c.update) {
pr_err("Can only update one aspect of superblock, both %s and %s given.\n",
- c.update, optarg);
+ map_num(update_options, c.update), optarg);
exit(2);
}
- c.update = optarg;
- if (strcmp(c.update, "devicesize") != 0 &&
- strcmp(c.update, "bbl") != 0 &&
- strcmp(c.update, "force-no-bbl") != 0 &&
- strcmp(c.update, "no-bbl") != 0) {
+ c.update = map_name(update_options, optarg);
+ if (c.update != UOPT_DEVICESIZE &&
+ c.update != UOPT_BBL &&
+ c.update != UOPT_NO_BBL &&
+ c.update != UOPT_FORCE_NO_BBL) {
pr_err("only 'devicesize', 'bbl', 'no-bbl', and 'force-no-bbl' can be updated with --re-add\n");
exit(2);
}
@@ -1200,8 +1138,9 @@ int main(int argc, char *argv[])
case O(BUILD, WriteBehind):
case O(CREATE, WriteBehind):
s.write_behind = DEFAULT_MAX_WRITE_BEHIND;
- if (parse_num(&s.write_behind, optarg) != 0 ||
- s.write_behind < 0 || s.write_behind > 16383) {
+ if (optarg &&
+ (parse_num(&s.write_behind, optarg) != 0 ||
+ s.write_behind < 0 || s.write_behind > 16383)) {
pr_err("Invalid value for maximum outstanding write-behind writes: %s.\n\tMust be between 0 and 16383.\n",
optarg);
exit(2);
@@ -1248,10 +1187,10 @@ int main(int argc, char *argv[])
if (option_index > 0)
pr_err(":option --%s not valid in %s mode\n",
long_options[option_index].name,
- map_num(modes, mode));
+ map_num_s(modes, mode));
else
pr_err("option -%c not valid in %s mode\n",
- opt, map_num(modes, mode));
+ opt, map_num_s(modes, mode));
exit(2);
}
@@ -1276,7 +1215,7 @@ int main(int argc, char *argv[])
if (s.consistency_policy != CONSISTENCY_POLICY_UNKNOWN &&
s.consistency_policy != CONSISTENCY_POLICY_JOURNAL) {
pr_err("--write-journal is not supported with consistency policy: %s\n",
- map_num(consistency_policies, s.consistency_policy));
+ map_num_s(consistency_policies, s.consistency_policy));
exit(2);
}
}
@@ -1285,12 +1224,12 @@ int main(int argc, char *argv[])
s.consistency_policy != CONSISTENCY_POLICY_UNKNOWN) {
if (s.level <= 0) {
pr_err("--consistency-policy not meaningful with level %s.\n",
- map_num(pers, s.level));
+ map_num_s(pers, s.level));
exit(2);
} else if (s.consistency_policy == CONSISTENCY_POLICY_JOURNAL &&
!s.journaldisks) {
pr_err("--write-journal is required for consistency policy: %s\n",
- map_num(consistency_policies, s.consistency_policy));
+ map_num_s(consistency_policies, s.consistency_policy));
exit(2);
} else if (s.consistency_policy == CONSISTENCY_POLICY_PPL &&
s.level != 5) {
@@ -1300,14 +1239,14 @@ int main(int argc, char *argv[])
(!s.bitmap_file ||
strcmp(s.bitmap_file, "none") == 0)) {
pr_err("--bitmap is required for consistency policy: %s\n",
- map_num(consistency_policies, s.consistency_policy));
+ map_num_s(consistency_policies, s.consistency_policy));
exit(2);
} else if (s.bitmap_file &&
strcmp(s.bitmap_file, "none") != 0 &&
s.consistency_policy != CONSISTENCY_POLICY_BITMAP &&
s.consistency_policy != CONSISTENCY_POLICY_JOURNAL) {
pr_err("--bitmap is not compatible with consistency policy: %s\n",
- map_num(consistency_policies, s.consistency_policy));
+ map_num_s(consistency_policies, s.consistency_policy));
exit(2);
}
}
@@ -1323,18 +1262,6 @@ int main(int argc, char *argv[])
exit(2);
}
- if (symlinks) {
- struct createinfo *ci = conf_get_create_info();
-
- if (strcasecmp(symlinks, "yes") == 0)
- ci->symlinks = 1;
- else if (strcasecmp(symlinks, "no") == 0)
- ci->symlinks = 0;
- else {
- pr_err("option --symlinks must be 'no' or 'yes'\n");
- exit(2);
- }
- }
/* Ok, got the option parsing out of the way
* hopefully it's mostly right but there might be some stuff
* missing
@@ -1347,6 +1274,9 @@ int main(int argc, char *argv[])
if (mode == MANAGE || mode == BUILD || mode == CREATE ||
mode == GROW || (mode == ASSEMBLE && ! c.scan)) {
+ struct stat stb;
+ int ret;
+
if (devs_found < 1) {
pr_err("an md device must be given in this mode\n");
exit(2);
@@ -1359,6 +1289,12 @@ int main(int argc, char *argv[])
mdfd = open_mddev(devlist->devname, 1);
if (mdfd < 0)
exit(1);
+
+ ret = fstat(mdfd, &stb);
+ if (ret) {
+ pr_err("fstat failed on %s.\n", devlist->devname);
+ exit(1);
+ }
} else {
char *bname = basename(devlist->devname);
@@ -1366,30 +1302,21 @@ int main(int argc, char *argv[])
pr_err("Name %s is too long.\n", devlist->devname);
exit(1);
}
- /* non-existent device is OK */
- mdfd = open_mddev(devlist->devname, 0);
- }
- if (mdfd == -2) {
- pr_err("device %s exists but is not an md array.\n", devlist->devname);
- exit(1);
- }
- if ((int)ident.super_minor == -2) {
- struct stat stb;
- if (mdfd < 0) {
+
+ ret = stat(devlist->devname, &stb);
+ if (ident.super_minor == -2 && ret != 0) {
pr_err("--super-minor=dev given, and listed device %s doesn't exist.\n",
- devlist->devname);
+ devlist->devname);
+ exit(1);
+ }
+
+ if (!ret && !stat_is_md_dev(&stb)) {
+ pr_err("device %s exists but is not an md array.\n", devlist->devname);
exit(1);
}
- fstat(mdfd, &stb);
- ident.super_minor = minor(stb.st_rdev);
- }
- if (mdfd >= 0 && mode != MANAGE && mode != GROW) {
- /* We don't really want this open yet, we just might
- * have wanted to check some things
- */
- close(mdfd);
- mdfd = -1;
}
+ if (ident.super_minor == -2)
+ ident.super_minor = minor(stb.st_rdev);
}
if (s.raiddisks) {
@@ -1429,12 +1356,12 @@ int main(int argc, char *argv[])
}
}
- if (c.update && strcmp(c.update, "nodes") == 0 && c.nodes == 0) {
+ if (c.update && c.update == UOPT_NODES && c.nodes == 0) {
pr_err("Please specify nodes number with --nodes\n");
exit(1);
}
- if (c.backup_file && data_offset != INVALID_SECTORS) {
+ if (c.backup_file && s.data_offset != INVALID_SECTORS) {
pr_err("--backup-file and --data-offset are incompatible\n");
exit(2);
}
@@ -1474,10 +1401,10 @@ int main(int argc, char *argv[])
/* readonly, add/remove, readwrite, runstop */
if (c.readonly > 0)
rv = Manage_ro(devlist->devname, mdfd, c.readonly);
- if (!rv && devs_found>1)
+ if (!rv && devs_found > 1)
rv = Manage_subdevs(devlist->devname, mdfd,
- devlist->next, c.verbose, c.test,
- c.update, c.force);
+ devlist->next, c.verbose,
+ c.test, c.update, c.force);
if (!rv && c.readonly < 0)
rv = Manage_ro(devlist->devname, mdfd, c.readonly);
if (!rv && c.runstop > 0)
@@ -1605,8 +1532,7 @@ int main(int argc, char *argv[])
rv = Create(ss, devlist->devname,
ident.name, ident.uuid_set ? ident.uuid : NULL,
- devs_found-1, devlist->next,
- &s, &c, data_offset);
+ devs_found - 1, devlist->next, &s, &c);
break;
case MISC:
if (devmode == 'E') {
@@ -1724,10 +1650,9 @@ int main(int argc, char *argv[])
c.verbose);
else if (s.size > 0 || s.raiddisks || s.layout_str ||
s.chunk != 0 || s.level != UnSet ||
- data_offset != INVALID_SECTORS) {
+ s.data_offset != INVALID_SECTORS) {
rv = Grow_reshape(devlist->devname, mdfd,
- devlist->next,
- data_offset, &c, &s);
+ devlist->next, &c, &s);
} else if (s.consistency_policy != CONSISTENCY_POLICY_UNKNOWN) {
rv = Grow_consistency_policy(devlist->devname, mdfd, &c, &s);
} else if (array_size == 0)
@@ -1999,7 +1924,7 @@ static int misc_list(struct mddev_dev *devlist,
rv |= Kill_subarray(dv->devname, c->subarray, c->verbose);
continue;
case UpdateSubarray:
- if (c->update == NULL) {
+ if (!c->update) {
pr_err("-U/--update must be specified with --update-subarray\n");
rv |= 1;
continue;
diff --git a/mdadm.conf.5 b/mdadm.conf.5.in
index 74a21c5..bc2295c 100644
--- a/mdadm.conf.5
+++ b/mdadm.conf.5.in
@@ -8,7 +8,7 @@
.SH NAME
mdadm.conf \- configuration for management of Software RAID with mdadm
.SH SYNOPSIS
-/etc/mdadm.conf
+{CONFFILE}
.SH DESCRIPTION
.PP
.I mdadm
@@ -88,7 +88,8 @@ but only the major and minor device numbers. It scans
.I /dev
to find the name that matches the numbers.
-If no DEVICE line is present, then "DEVICE partitions containers" is assumed.
+If no DEVICE line is present in any config file,
+then "DEVICE partitions containers" is assumed.
For example:
.IP
@@ -272,6 +273,10 @@ catenated with spaces to form the address.
Note that this value cannot be set via the
.I mdadm
commandline. It is only settable via the config file.
+There should only be one
+.B MAILADDR
+line and it should have only one address. Any subsequent addresses
+are silently ignored.
.TP
.B PROGRAM
@@ -286,7 +291,8 @@ device.
There should only be one
.B program
-line and it should be give only one program.
+line and it should be given only one program. Any subsequent programs
+are silently ignored.
.TP
@@ -295,7 +301,14 @@ The
.B create
line gives default values to be used when creating arrays, new members
of arrays, and device entries for arrays.
-These include:
+
+There should only be one
+.B create
+line. Any subsequent lines will override the previous settings.
+
+Keywords used in the
+.I CREATE
+line and supported values are:
.RS 4
.TP
@@ -326,21 +339,6 @@ The name of the metadata format to use if none is explicitly given.
This can be useful to impose a system-wide default of version-1 superblocks.
.TP
-.B symlinks=no
-Normally when creating devices in
-.B /dev/md/
-.I mdadm
-will create a matching symlink from
-.B /dev/
-with a name starting
-.B md
-or
-.BR md_ .
-Give
-.B symlinks=no
-to suppress this symlink creation.
-
-.TP
.B names=yes
Since Linux 2.6.29 it has been possible to create
.B md
@@ -426,6 +424,23 @@ from any possible local name. e.g.
.B /dev/md/1_1
or
.BR /dev/md/home_0 .
+
+.TP
+.B HOMECLUSTER
+The
+.B homcluster
+line gives a default value for the
+.B \-\-homecluster=
+option to mdadm. It specifies the cluster name for the md device.
+The md device can be assembled only on the cluster which matches
+the name specified. If
+.B homcluster
+is not provided, mdadm tries to detect the cluster name automatically.
+
+There should only be one
+.B homecluster
+line. Any subsequent lines will be silently ignored.
+
.TP
.B AUTO
A list of names of metadata format can be given, each preceded by a
@@ -475,8 +490,8 @@ The known metadata types are
.B AUTO
should be given at most once. Subsequent lines are silently ignored.
-Thus an earlier config file in a config directory will over-ride
-the setting in a later config file.
+Thus a later config file in a config directory will not overwrite
+the setting in an earlier config file.
.TP
.B POLICY
@@ -594,6 +609,7 @@ The
line lists custom values of MD device's sysfs attributes which will be
stored in sysfs after the array is assembled. Multiple lines are allowed and each
line has to contain the uuid or the name of the device to which it relates.
+Lines are applied in reverse order.
.RS 4
.TP
.B uuid=
@@ -621,7 +637,46 @@ is running in
.B \-\-monitor
mode.
.B \-d/\-\-delay
-command line argument takes precedence over the config file
+command line argument takes precedence over the config file.
+
+If multiple
+.B MINITORDELAY
+lines are provided, only first non-zero value is considered.
+
+.SH FILES
+
+.SS {CONFFILE}
+
+The default config file location, used when
+.I mdadm
+is running without --config option.
+
+.SS {CONFFILE}.d
+
+The default directory with config files. Used when
+.I mdadm
+is running without --config option, after successful reading of the
+.B {CONFFILE}
+default config file. Files in that directory
+are read in lexical order.
+
+
+.SS {CONFFILE2}
+
+Alternative config file that is read, when
+.I mdadm
+is running without --config option and the
+.B {CONFFILE}
+default config file was not opened successfully.
+
+.SS {CONFFILE2}.d
+
+The alternative directory with config files. Used when
+.I mdadm
+is runninng without --config option, after reading the
+.B {CONFFILE2}
+alternative config file whether it was successful or not. Files in
+that directory are read in lexical order.
.SH EXAMPLE
DEVICE /dev/sd[bcdjkl]1
diff --git a/mdadm.h b/mdadm.h
index c7268a7..13f8b4c 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -33,8 +33,10 @@ extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence));
# endif
#endif
+#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
@@ -46,6 +48,7 @@ extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence));
#include <string.h>
#include <syslog.h>
#include <stdbool.h>
+#include <signal.h>
/* Newer glibc requires sys/sysmacros.h directly for makedev() */
#include <sys/sysmacros.h>
#ifdef __dietlibc__
@@ -393,7 +396,6 @@ struct createinfo {
int gid;
int autof;
int mode;
- int symlinks;
int names;
int bblist;
struct supertype *supertype;
@@ -418,6 +420,7 @@ enum mode {
};
extern char short_options[];
+extern char short_monitor_options[];
extern char short_bitmap_options[];
extern char short_bitmap_auto_options[];
extern struct option long_options[];
@@ -440,7 +443,6 @@ enum special_options {
BackupFile,
HomeHost,
AutoHomeHost,
- Symlinks,
AutoDetect,
Waitclean,
DetailPlatform,
@@ -495,6 +497,51 @@ enum special_options {
ConsistencyPolicy,
};
+enum update_opt {
+ UOPT_NAME = 1,
+ UOPT_PPL,
+ UOPT_NO_PPL,
+ UOPT_BITMAP,
+ UOPT_NO_BITMAP,
+ UOPT_SUBARRAY_ONLY,
+ UOPT_SPARC22,
+ UOPT_SUPER_MINOR,
+ UOPT_SUMMARIES,
+ UOPT_RESYNC,
+ UOPT_UUID,
+ UOPT_HOMEHOST,
+ UOPT_HOME_CLUSTER,
+ UOPT_NODES,
+ UOPT_DEVICESIZE,
+ UOPT_BBL,
+ UOPT_NO_BBL,
+ UOPT_FORCE_NO_BBL,
+ UOPT_METADATA,
+ UOPT_REVERT_RESHAPE,
+ UOPT_LAYOUT_ORIGINAL,
+ UOPT_LAYOUT_ALTERNATE,
+ UOPT_LAYOUT_UNSPECIFIED,
+ UOPT_BYTEORDER,
+ UOPT_HELP,
+ UOPT_USER_ONLY,
+ /*
+ * Code specific options, cannot be set by the user
+ */
+ UOPT_SPEC_FORCE_ONE,
+ UOPT_SPEC_FORCE_ARRAY,
+ UOPT_SPEC_ASSEMBLE,
+ UOPT_SPEC_LINEAR_GROW_NEW,
+ UOPT_SPEC_LINEAR_GROW_UPDATE,
+ UOPT_SPEC__RESHAPE_PROGRESS,
+ UOPT_SPEC_WRITEMOSTLY,
+ UOPT_SPEC_READWRITE,
+ UOPT_SPEC_FAILFAST,
+ UOPT_SPEC_NOFAILFAST,
+ UOPT_SPEC_REVERT_RESHAPE_NOBACKUP,
+ UOPT_UNDEFINED
+};
+extern void fprint_update_options(FILE *outf, enum update_opt update_mode);
+
enum prefix_standard {
JEDEC,
IEC
@@ -569,7 +616,7 @@ struct context {
int export;
int test;
char *subarray;
- char *update;
+ enum update_opt update;
int scan;
int SparcAdjust;
int autof;
@@ -595,6 +642,7 @@ struct shape {
int assume_clean;
int write_behind;
unsigned long long size;
+ unsigned long long data_offset;
int consistency_policy;
};
@@ -769,12 +817,12 @@ extern int restore_stripes(int *dest, unsigned long long *offsets,
#endif
#define SYSLOG_FACILITY LOG_DAEMON
-
+extern char *map_num_s(mapping_t *map, int num);
extern char *map_num(mapping_t *map, int num);
extern int map_name(mapping_t *map, char *name);
extern mapping_t r0layout[], r5layout[], r6layout[],
pers[], modes[], faultylayout[];
-extern mapping_t consistency_policies[], sysfs_array_states[];
+extern mapping_t consistency_policies[], sysfs_array_states[], update_options[];
extern char *map_dev_preferred(int major, int minor, int create,
char *prefer);
@@ -796,6 +844,17 @@ static inline int is_fd_valid(int fd)
}
/**
+ * is_level456() - check whether given level is between inclusive 4 and 6.
+ * @level: level to check.
+ *
+ * Return: true if condition is met, false otherwise
+ */
+static inline bool is_level456(int level)
+{
+ return (level >= 4 && level <= 6);
+}
+
+/**
* close_fd() - verify, close and unset file descriptor.
* @fd: pointer to file descriptor.
*
@@ -952,7 +1011,7 @@ extern struct superswitch {
* it will resume going in the opposite direction.
*/
int (*update_super)(struct supertype *st, struct mdinfo *info,
- char *update,
+ enum update_opt update,
char *devname, int verbose,
int uuid_set, char *homehost);
@@ -1078,9 +1137,15 @@ extern struct superswitch {
/* Permit subarray's to be deleted from inactive containers */
int (*kill_subarray)(struct supertype *st,
char *subarray_id); /* optional */
- /* Permit subarray's to be modified */
+ /**
+ * update_subarray() - Permit subarray to be modified.
+ * @st: Supertype.
+ * @subarray: Subarray name.
+ * @update: Update option.
+ * @ident: Optional identifiers.
+ */
int (*update_subarray)(struct supertype *st, char *subarray,
- char *update, struct mddev_ident *ident); /* optional */
+ enum update_opt update, struct mddev_ident *ident);
/* Check if reshape is supported for this external format.
* st is obtained from super_by_fd() where st->subarray[0] is
* initialized to indicate if reshape is being performed at the
@@ -1413,14 +1478,13 @@ extern int Manage_stop(char *devname, int fd, int quiet,
int will_retry);
extern int Manage_subdevs(char *devname, int fd,
struct mddev_dev *devlist, int verbose, int test,
- char *update, int force);
+ enum update_opt update, int force);
extern int autodetect(void);
extern int Grow_Add_device(char *devname, int fd, char *newdev);
extern int Grow_addbitmap(char *devname, int fd,
struct context *c, struct shape *s);
extern int Grow_reshape(char *devname, int fd,
struct mddev_dev *devlist,
- unsigned long long data_offset,
struct context *c, struct shape *s);
extern int Grow_restart(struct supertype *st, struct mdinfo *info,
int *fdlist, int cnt, char *backup_file, int verbose);
@@ -1451,8 +1515,7 @@ extern int Create(struct supertype *st, char *mddev,
char *name, int *uuid,
int subdevs, struct mddev_dev *devlist,
struct shape *s,
- struct context *c,
- unsigned long long data_offset);
+ struct context *c);
extern int Detail(char *dev, struct context *c);
extern int Detail_Platform(struct superswitch *ss, int scan, int verbose, int export, char *controller_path);
@@ -1469,7 +1532,7 @@ extern int Monitor(struct mddev_dev *devlist,
extern int Kill(char *dev, struct supertype *st, int force, int verbose, int noexcl);
extern int Kill_subarray(char *dev, char *subarray, int verbose);
-extern int Update_subarray(char *dev, char *subarray, char *update, struct mddev_ident *ident, int quiet);
+extern int Update_subarray(char *dev, char *subarray, enum update_opt update, struct mddev_ident *ident, int quiet);
extern int Wait(char *dev);
extern int WaitClean(char *dev, int verbose);
extern int SetAction(char *dev, char *action);
@@ -1511,6 +1574,7 @@ extern int get_linux_version(void);
extern int mdadm_version(char *version);
extern unsigned long long parse_size(char *size);
extern int parse_uuid(char *str, int uuid[4]);
+int default_layout(struct supertype *st, int level, int verbose);
extern int is_near_layout_10(int layout);
extern int parse_layout_10(char *layout);
extern int parse_layout_faulty(char *layout);
@@ -1528,6 +1592,7 @@ extern int stat_is_blkdev(char *devname, dev_t *rdev);
extern bool is_dev_alive(char *path);
extern int get_mdp_major(void);
extern int get_maj_min(char *dev, int *major, int *minor);
+extern bool is_bit_set(int *val, unsigned char index);
extern int dev_open(char *dev, int flags);
extern int open_dev(char *devnm);
extern void reopen_mddev(int mdfd);
@@ -1540,6 +1605,8 @@ extern void enable_fds(int devices);
extern void manage_fork_fds(int close_all);
extern int continue_via_systemd(char *devnm, char *service_name);
+extern void ident_init(struct mddev_ident *ident);
+
extern int parse_auto(char *str, char *msg, int config);
extern struct mddev_ident *conf_get_ident(char *dev);
extern struct mddev_dev *conf_get_devs(void);
@@ -1634,6 +1701,7 @@ extern int create_mddev(char *dev, char *name, int autof, int trustworthy,
#define FOREIGN 2
#define METADATA 3
extern int open_mddev(char *dev, int report_errors);
+extern int is_mddev(char *dev);
extern int open_container(int fd);
extern int metadata_container_matches(char *metadata, char *devnm);
extern int metadata_subdev_matches(char *metadata, char *devnm);
@@ -1660,6 +1728,7 @@ void *super1_make_v0(struct supertype *st, struct mdinfo *info, mdp_super_t *sb0
extern char *stat2kname(struct stat *st);
extern char *fd2kname(int fd);
extern char *stat2devnm(struct stat *st);
+bool stat_is_md_dev(struct stat *st);
extern char *fd2devnm(int fd);
extern void udev_block(char *devnm);
extern void udev_unblock(void);
@@ -1705,6 +1774,10 @@ extern int cluster_get_dlmlock(void);
extern int cluster_release_dlmlock(void);
extern void set_dlm_hooks(void);
+#define MSEC_TO_NSEC(msec) ((msec) * 1000000)
+#define USEC_TO_NSEC(usec) ((usec) * 1000)
+extern void sleep_for(unsigned int sec, long nsec, bool wake_after_interrupt);
+
#define _ROUND_UP(val, base) (((val) + (base) - 1) & ~(base - 1))
#define ROUND_UP(val, base) _ROUND_UP(val, (typeof(val))(base))
#define ROUND_UP_PTR(ptr, base) ((typeof(ptr)) \
@@ -1729,6 +1802,27 @@ static inline char *to_subarray(struct mdstat_ent *ent, char *container)
return &ent->metadata_version[10+strlen(container)+1];
}
+/**
+ * signal_s() - Wrapper for sigaction() with signal()-like interface.
+ * @sig: The signal to set the signal handler to.
+ * @handler: The signal handler.
+ *
+ * Return: previous handler or SIG_ERR on failure.
+ */
+static inline sighandler_t signal_s(int sig, sighandler_t handler)
+{
+ struct sigaction new_act;
+ struct sigaction old_act;
+
+ new_act.sa_handler = handler;
+ new_act.sa_flags = 0;
+
+ if (sigaction(sig, &new_act, &old_act) == 0)
+ return old_act.sa_handler;
+
+ return SIG_ERR;
+}
+
#ifdef DEBUG
#define dprintf(fmt, arg...) \
fprintf(stderr, "%s: %s: "fmt, Name, __func__, ##arg)
@@ -1740,8 +1834,7 @@ static inline char *to_subarray(struct mdstat_ent *ent, char *container)
#define dprintf_cont(fmt, arg...) \
({ if (0) fprintf(stderr, fmt, ##arg); 0; })
#endif
-#include <assert.h>
-#include <stdarg.h>
+
static inline int xasprintf(char **strp, const char *fmt, ...) {
va_list ap;
int ret;
@@ -1885,3 +1978,17 @@ enum r0layout {
* This is true for native and DDF, IMSM allows 16.
*/
#define MD_NAME_MAX 32
+
+/**
+ * is_container() - check if @level is &LEVEL_CONTAINER
+ * @level: level value
+ *
+ * return:
+ * 1 if level is equal to &LEVEL_CONTAINER, 0 otherwise.
+ */
+static inline int is_container(const int level)
+{
+ if (level == LEVEL_CONTAINER)
+ return 1;
+ return 0;
+}
diff --git a/mdmon.c b/mdmon.c
index c71e62c..60ba318 100644
--- a/mdmon.c
+++ b/mdmon.c
@@ -56,7 +56,6 @@
#include <errno.h>
#include <string.h>
#include <fcntl.h>
-#include <signal.h>
#include <dirent.h>
#ifdef USE_PTHREADS
#include <pthread.h>
@@ -100,7 +99,7 @@ static int clone_monitor(struct supertype *container)
if (rc)
return rc;
while (mon_tid == -1)
- usleep(10);
+ sleep_for(0, USEC_TO_NSEC(10), true);
pthread_attr_destroy(&attr);
mgr_tid = syscall(SYS_gettid);
@@ -210,7 +209,7 @@ static void try_kill_monitor(pid_t pid, char *devname, int sock)
rv = kill(pid, SIGUSR1);
if (rv < 0)
break;
- usleep(200000);
+ sleep_for(0, MSEC_TO_NSEC(200), true);
}
}
@@ -289,6 +288,15 @@ void usage(void)
exit(2);
}
+static bool is_duplicate_opt(const int opt, const int set_val, const char *long_name)
+{
+ if (opt == set_val) {
+ pr_err("--%s option duplicated!\n", long_name);
+ return true;
+ }
+ return false;
+}
+
static int mdmon(char *devnm, int must_fork, int takeover);
int main(int argc, char *argv[])
@@ -300,6 +308,7 @@ int main(int argc, char *argv[])
int all = 0;
int takeover = 0;
int dofork = 1;
+ bool help = false;
static struct option options[] = {
{"all", 0, NULL, 'a'},
{"takeover", 0, NULL, 't'},
@@ -309,51 +318,67 @@ int main(int argc, char *argv[])
{NULL, 0, NULL, 0}
};
- if (in_initrd()) {
- /*
- * set first char of argv[0] to @. This is used by
- * systemd to signal that the task was launched from
- * initrd/initramfs and should be preserved during shutdown
- */
- argv[0][0] = '@';
- }
-
while ((opt = getopt_long(argc, argv, "thaF", options, NULL)) != -1) {
switch (opt) {
case 'a':
+ if (is_duplicate_opt(all, 1, "all"))
+ exit(1);
container_name = argv[optind-1];
all = 1;
break;
case 't':
+ if (is_duplicate_opt(takeover, 1, "takeover"))
+ exit(1);
takeover = 1;
break;
case 'F':
+ if (is_duplicate_opt(dofork, 0, "foreground"))
+ exit(1);
dofork = 0;
break;
case OffRootOpt:
+ if (is_duplicate_opt(argv[0][0], '@', "offroot"))
+ exit(1);
argv[0][0] = '@';
break;
case 'h':
+ if (is_duplicate_opt(help, true, "help"))
+ exit(1);
+ help = true;
+ break;
default:
usage();
break;
}
}
- if (all == 0 && container_name == NULL) {
- if (argv[optind])
- container_name = argv[optind];
+
+ if (in_initrd()) {
+ /*
+ * set first char of argv[0] to @. This is used by
+ * systemd to signal that the task was launched from
+ * initrd/initramfs and should be preserved during shutdown
+ */
+ argv[0][0] = '@';
}
- if (container_name == NULL)
- usage();
+ if (all == 0 && container_name == NULL) {
+ if (argv[optind]) {
+ container_name = get_md_name(argv[optind]);
+ if (!container_name)
+ return 1;
+ }
+ }
- if (argc - optind > 1)
+ if (container_name == NULL || argc - optind > 1)
usage();
if (strcmp(container_name, "/proc/mdstat") == 0)
all = 1;
+ if (help)
+ usage();
+
if (all) {
struct mdstat_ent *mdstat, *e;
int container_len = strlen(container_name);
@@ -377,21 +402,17 @@ int main(int argc, char *argv[])
free_mdstat(mdstat);
return status;
- } else if (strncmp(container_name, "md", 2) == 0) {
- int id = devnm2devid(container_name);
- if (id)
- devnm = container_name;
} else {
- struct stat st;
+ int mdfd = open_mddev(container_name, 0);
+ devnm = fd2devnm(mdfd);
- if (stat(container_name, &st) == 0)
- devnm = xstrdup(stat2devnm(&st));
+ close(mdfd);
}
if (!devnm) {
pr_err("%s is not a valid md device name\n",
container_name);
- exit(1);
+ return 1;
}
return mdmon(devnm, dofork && do_fork(), takeover);
}
diff --git a/mdopen.c b/mdopen.c
index 245be53..d18c931 100644
--- a/mdopen.c
+++ b/mdopen.c
@@ -475,6 +475,23 @@ int open_mddev(char *dev, int report_errors)
return mdfd;
}
+/**
+ * is_mddev() - check that file name passed is an md device.
+ * @dev: file name that has to be checked.
+ * Return: 1 if file passed is an md device, 0 if not.
+ */
+int is_mddev(char *dev)
+{
+ int fd = open_mddev(dev, 1);
+
+ if (fd >= 0) {
+ close(fd);
+ return 1;
+ }
+
+ return 0;
+}
+
char *find_free_devnm(int use_partitions)
{
static char devnm[32];
diff --git a/monitor.c b/monitor.c
index e0d3be6..820a93d 100644
--- a/monitor.c
+++ b/monitor.c
@@ -22,7 +22,6 @@
#include "mdmon.h"
#include <sys/syscall.h>
#include <sys/select.h>
-#include <signal.h>
static char *array_states[] = {
"clear", "inactive", "suspended", "readonly", "read-auto",
@@ -312,6 +311,9 @@ static int check_for_cleared_bb(struct active_array *a, struct mdinfo *mdi)
struct md_bb *bb;
int i;
+ if (!ss->get_bad_blocks)
+ return -1;
+
/*
* Get a list of bad blocks for an array, then read list of
* acknowledged bad blocks from kernel and compare it against metadata
diff --git a/platform-intel.c b/platform-intel.c
index 5a8729e..757f0b1 100644
--- a/platform-intel.c
+++ b/platform-intel.c
@@ -512,7 +512,8 @@ static const struct imsm_orom *find_imsm_hba_orom(struct sys_dev *hba)
#define AHCI_PROP "RstSataV"
#define AHCI_SSATA_PROP "RstsSatV"
#define AHCI_TSATA_PROP "RsttSatV"
-#define VMD_PROP "RstUefiV"
+#define VROC_VMD_PROP "RstUefiV"
+#define RST_VMD_PROP "RstVmdV"
#define VENDOR_GUID \
EFI_GUID(0x193dfefa, 0xa445, 0x4302, 0x99, 0xd8, 0xef, 0x3a, 0xad, 0x1a, 0x04, 0xc6)
@@ -605,6 +606,7 @@ const struct imsm_orom *find_imsm_efi(struct sys_dev *hba)
struct orom_entry *ret;
static const char * const sata_efivars[] = {AHCI_PROP, AHCI_SSATA_PROP,
AHCI_TSATA_PROP};
+ static const char * const vmd_efivars[] = {VROC_VMD_PROP, RST_VMD_PROP};
unsigned long i;
if (check_env("IMSM_TEST_AHCI_EFI") || check_env("IMSM_TEST_SCU_EFI"))
@@ -636,10 +638,16 @@ const struct imsm_orom *find_imsm_efi(struct sys_dev *hba)
break;
case SYS_DEV_VMD:
- if (!read_efi_variable(&orom, sizeof(orom), VMD_PROP,
- VENDOR_GUID))
- break;
- return NULL;
+ for (i = 0; i < ARRAY_SIZE(vmd_efivars); i++) {
+ if (!read_efi_variable(&orom, sizeof(orom),
+ vmd_efivars[i], VENDOR_GUID))
+ break;
+ }
+
+ if (i == ARRAY_SIZE(vmd_efivars))
+ return NULL;
+
+ break;
default:
return NULL;
}
diff --git a/probe_roms.c b/probe_roms.c
index 7ea04c7..94c80c2 100644
--- a/probe_roms.c
+++ b/probe_roms.c
@@ -22,7 +22,6 @@
#include "probe_roms.h"
#include "mdadm.h"
#include <unistd.h>
-#include <signal.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
@@ -69,7 +68,8 @@ static int probe_address16(const __u16 *ptr, __u16 *val)
void probe_roms_exit(void)
{
- signal(SIGBUS, SIG_DFL);
+ signal_s(SIGBUS, SIG_DFL);
+
if (rom_fd >= 0) {
close(rom_fd);
rom_fd = -1;
@@ -98,7 +98,7 @@ int probe_roms_init(unsigned long align)
if (roms_init())
return -1;
- if (signal(SIGBUS, sigbus) == SIG_ERR)
+ if (signal_s(SIGBUS, sigbus) == SIG_ERR)
rc = -1;
if (rc == 0) {
fd = open("/dev/mem", O_RDONLY);
diff --git a/raid6check.c b/raid6check.c
index a8e6005..9947776 100644
--- a/raid6check.c
+++ b/raid6check.c
@@ -24,7 +24,6 @@
#include "mdadm.h"
#include <stdint.h>
-#include <signal.h>
#include <sys/mman.h>
#define CHECK_PAGE_BITS (12)
@@ -130,30 +129,36 @@ void raid6_stats(int *disk, int *results, int raid_disks, int chunk_size)
}
int lock_stripe(struct mdinfo *info, unsigned long long start,
- int chunk_size, int data_disks, sighandler_t *sig) {
+ int chunk_size, int data_disks, sighandler_t *sig)
+{
int rv;
+
+ sig[0] = signal_s(SIGTERM, SIG_IGN);
+ sig[1] = signal_s(SIGINT, SIG_IGN);
+ sig[2] = signal_s(SIGQUIT, SIG_IGN);
+
+ if (sig[0] == SIG_ERR || sig[1] == SIG_ERR || sig[2] == SIG_ERR)
+ return 1;
+
if(mlockall(MCL_CURRENT | MCL_FUTURE) != 0) {
return 2;
}
- sig[0] = signal(SIGTERM, SIG_IGN);
- sig[1] = signal(SIGINT, SIG_IGN);
- sig[2] = signal(SIGQUIT, SIG_IGN);
-
rv = sysfs_set_num(info, NULL, "suspend_lo", start * chunk_size * data_disks);
rv |= sysfs_set_num(info, NULL, "suspend_hi", (start + 1) * chunk_size * data_disks);
return rv * 256;
}
-int unlock_all_stripes(struct mdinfo *info, sighandler_t *sig) {
+int unlock_all_stripes(struct mdinfo *info, sighandler_t *sig)
+{
int rv;
rv = sysfs_set_num(info, NULL, "suspend_lo", 0x7FFFFFFFFFFFFFFFULL);
rv |= sysfs_set_num(info, NULL, "suspend_hi", 0);
rv |= sysfs_set_num(info, NULL, "suspend_lo", 0);
- signal(SIGQUIT, sig[2]);
- signal(SIGINT, sig[1]);
- signal(SIGTERM, sig[0]);
+ signal_s(SIGQUIT, sig[2]);
+ signal_s(SIGINT, sig[1]);
+ signal_s(SIGTERM, sig[0]);
if(munlockall() != 0)
return 3;
diff --git a/super-ddf.c b/super-ddf.c
index 3f304cd..309812d 100644
--- a/super-ddf.c
+++ b/super-ddf.c
@@ -503,13 +503,6 @@ struct ddf_super {
static int load_super_ddf_all(struct supertype *st, int fd,
void **sbp, char *devname);
static int get_svd_state(const struct ddf_super *, const struct vcl *);
-static int
-validate_geometry_ddf_container(struct supertype *st,
- int level, int layout, int raiddisks,
- int chunk, unsigned long long size,
- unsigned long long data_offset,
- char *dev, unsigned long long *freesize,
- int verbose);
static int validate_geometry_ddf_bvd(struct supertype *st,
int level, int layout, int raiddisks,
@@ -1477,13 +1470,13 @@ static void examine_vds(struct ddf_super *sb)
printf("\n");
printf(" unit[%d] : %d\n", i, be16_to_cpu(ve->unit));
printf(" state[%d] : %s, %s%s\n", i,
- map_num(ddf_state, ve->state & 7),
+ map_num_s(ddf_state, ve->state & 7),
(ve->state & DDF_state_morphing) ? "Morphing, ": "",
(ve->state & DDF_state_inconsistent)? "Not Consistent" : "Consistent");
printf(" init state[%d] : %s\n", i,
- map_num(ddf_init_state, ve->init_state&DDF_initstate_mask));
+ map_num_s(ddf_init_state, ve->init_state & DDF_initstate_mask));
printf(" access[%d] : %s\n", i,
- map_num(ddf_access, (ve->init_state & DDF_access_mask) >> 6));
+ map_num_s(ddf_access, (ve->init_state & DDF_access_mask) >> 6));
printf(" Name[%d] : %.16s\n", i, ve->name);
examine_vd(i, sb, ve->guid);
}
@@ -2146,75 +2139,6 @@ static void getinfo_super_ddf_bvd(struct supertype *st, struct mdinfo *info, cha
}
}
-static int update_super_ddf(struct supertype *st, struct mdinfo *info,
- char *update,
- char *devname, int verbose,
- int uuid_set, char *homehost)
-{
- /* For 'assemble' and 'force' we need to return non-zero if any
- * change was made. For others, the return value is ignored.
- * Update options are:
- * force-one : This device looks a bit old but needs to be included,
- * update age info appropriately.
- * assemble: clear any 'faulty' flag to allow this device to
- * be assembled.
- * force-array: Array is degraded but being forced, mark it clean
- * if that will be needed to assemble it.
- *
- * newdev: not used ????
- * grow: Array has gained a new device - this is currently for
- * linear only
- * resync: mark as dirty so a resync will happen.
- * uuid: Change the uuid of the array to match what is given
- * homehost: update the recorded homehost
- * name: update the name - preserving the homehost
- * _reshape_progress: record new reshape_progress position.
- *
- * Following are not relevant for this version:
- * sparc2.2 : update from old dodgey metadata
- * super-minor: change the preferred_minor number
- * summaries: update redundant counters.
- */
- int rv = 0;
-// struct ddf_super *ddf = st->sb;
-// struct vd_config *vd = find_vdcr(ddf, info->container_member);
-// struct virtual_entry *ve = find_ve(ddf);
-
- /* we don't need to handle "force-*" or "assemble" as
- * there is no need to 'trick' the kernel. When the metadata is
- * first updated to activate the array, all the implied modifications
- * will just happen.
- */
-
- if (strcmp(update, "grow") == 0) {
- /* FIXME */
- } else if (strcmp(update, "resync") == 0) {
-// info->resync_checkpoint = 0;
- } else if (strcmp(update, "homehost") == 0) {
- /* homehost is stored in controller->vendor_data,
- * or it is when we are the vendor
- */
-// if (info->vendor_is_local)
-// strcpy(ddf->controller.vendor_data, homehost);
- rv = -1;
- } else if (strcmp(update, "name") == 0) {
- /* name is stored in virtual_entry->name */
-// memset(ve->name, ' ', 16);
-// strncpy(ve->name, info->name, 16);
- rv = -1;
- } else if (strcmp(update, "_reshape_progress") == 0) {
- /* We don't support reshape yet */
- } else if (strcmp(update, "assemble") == 0 ) {
- /* Do nothing, just succeed */
- rv = 0;
- } else
- rv = -1;
-
-// update_all_csum(ddf);
-
- return rv;
-}
-
static void make_header_guid(char *guid)
{
be32 stamp;
@@ -3322,6 +3246,42 @@ static int reserve_space(struct supertype *st, int raiddisks,
return 1;
}
+static int
+validate_geometry_ddf_container(struct supertype *st,
+ int level, int raiddisks,
+ unsigned long long data_offset,
+ char *dev, unsigned long long *freesize,
+ int verbose)
+{
+ int fd;
+ unsigned long long ldsize;
+
+ if (!is_container(level))
+ return 0;
+ if (!dev)
+ return 1;
+
+ fd = dev_open(dev, O_RDONLY|O_EXCL);
+ if (fd < 0) {
+ if (verbose)
+ pr_err("ddf: Cannot open %s: %s\n",
+ dev, strerror(errno));
+ return 0;
+ }
+ if (!get_dev_size(fd, dev, &ldsize)) {
+ close(fd);
+ return 0;
+ }
+ close(fd);
+ if (freesize) {
+ *freesize = avail_size_ddf(st, ldsize >> 9, INVALID_SECTORS);
+ if (*freesize == 0)
+ return 0;
+ }
+
+ return 1;
+}
+
static int validate_geometry_ddf(struct supertype *st,
int level, int layout, int raiddisks,
int *chunk, unsigned long long size,
@@ -3340,20 +3300,18 @@ static int validate_geometry_ddf(struct supertype *st,
* If given BVDs, we make an SVD, changing all the GUIDs in the process.
*/
- if (*chunk == UnSet)
- *chunk = DEFAULT_CHUNK;
-
if (level == LEVEL_NONE)
level = LEVEL_CONTAINER;
- if (level == LEVEL_CONTAINER) {
+ if (is_container(level)) {
/* Must be a fresh device to add to a container */
- return validate_geometry_ddf_container(st, level, layout,
- raiddisks, *chunk,
- size, data_offset, dev,
- freesize,
- verbose);
+ return validate_geometry_ddf_container(st, level, raiddisks,
+ data_offset, dev,
+ freesize, verbose);
}
+ if (*chunk == UnSet)
+ *chunk = DEFAULT_CHUNK;
+
if (!dev) {
mdu_array_info_t array = {
.level = level,
@@ -3449,43 +3407,6 @@ static int validate_geometry_ddf(struct supertype *st,
return 1;
}
-static int
-validate_geometry_ddf_container(struct supertype *st,
- int level, int layout, int raiddisks,
- int chunk, unsigned long long size,
- unsigned long long data_offset,
- char *dev, unsigned long long *freesize,
- int verbose)
-{
- int fd;
- unsigned long long ldsize;
-
- if (level != LEVEL_CONTAINER)
- return 0;
- if (!dev)
- return 1;
-
- fd = dev_open(dev, O_RDONLY|O_EXCL);
- if (fd < 0) {
- if (verbose)
- pr_err("ddf: Cannot open %s: %s\n",
- dev, strerror(errno));
- return 0;
- }
- if (!get_dev_size(fd, dev, &ldsize)) {
- close(fd);
- return 0;
- }
- close(fd);
- if (freesize) {
- *freesize = avail_size_ddf(st, ldsize >> 9, INVALID_SECTORS);
- if (*freesize == 0)
- return 0;
- }
-
- return 1;
-}
-
static int validate_geometry_ddf_bvd(struct supertype *st,
int level, int layout, int raiddisks,
int *chunk, unsigned long long size,
@@ -3498,7 +3419,7 @@ static int validate_geometry_ddf_bvd(struct supertype *st,
struct dl *dl;
unsigned long long maxsize;
/* ddf/bvd supports lots of things, but not containers */
- if (level == LEVEL_CONTAINER) {
+ if (is_container(level)) {
if (verbose)
pr_err("DDF cannot create a container within an container\n");
return 0;
@@ -5125,13 +5046,16 @@ static struct mdinfo *ddf_activate_spare(struct active_array *a,
*/
vc = find_vdcr(ddf, a->info.container_member, rv->disk.raid_disk,
&n_bvd, &vcl);
- if (vc == NULL)
+ if (vc == NULL) {
+ free(rv);
return NULL;
+ }
mu = xmalloc(sizeof(*mu));
if (posix_memalign(&mu->space, 512, sizeof(struct vcl)) != 0) {
free(mu);
- mu = NULL;
+ free(rv);
+ return NULL;
}
mu->len = ddf->conf_rec_len * 512 * vcl->conf.sec_elmnt_count;
@@ -5161,6 +5085,8 @@ static struct mdinfo *ddf_activate_spare(struct active_array *a,
pr_err("BUG: can't find disk %d (%d/%d)\n",
di->disk.raid_disk,
di->disk.major, di->disk.minor);
+ free(mu);
+ free(rv);
return NULL;
}
vc->phys_refnum[i_prim] = ddf->phys->entries[dl->pdnum].refnum;
@@ -5216,7 +5142,6 @@ struct superswitch super_ddf = {
.match_home = match_home_ddf,
.uuid_from_super= uuid_from_super_ddf,
.getinfo_super = getinfo_super_ddf,
- .update_super = update_super_ddf,
.avail_size = avail_size_ddf,
diff --git a/super-intel.c b/super-intel.c
index d5fad10..89fac62 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -366,6 +366,18 @@ struct migr_record {
};
ASSERT_SIZE(migr_record, 128)
+/**
+ * enum imsm_status - internal IMSM return values representation.
+ * @STATUS_OK: function succeeded.
+ * @STATUS_ERROR: General error ocurred (not specified).
+ *
+ * Typedefed to imsm_status_t.
+ */
+typedef enum imsm_status {
+ IMSM_STATUS_ERROR = -1,
+ IMSM_STATUS_OK = 0,
+} imsm_status_t;
+
struct md_list {
/* usage marker:
* 1: load metadata
@@ -851,6 +863,21 @@ static struct disk_info *get_disk_info(struct imsm_update_create_array *update)
return inf;
}
+/**
+ * __get_imsm_dev() - Get device with index from imsm_super.
+ * @mpb: &imsm_super pointer, not NULL.
+ * @index: Device index.
+ *
+ * Function works as non-NULL, aborting in such a case,
+ * when NULL would be returned.
+ *
+ * Device index should be in range 0 up to num_raid_devs.
+ * Function assumes the index was already verified.
+ * Index must be valid, otherwise abort() is called.
+ *
+ * Return: Pointer to corresponding imsm_dev.
+ *
+ */
static struct imsm_dev *__get_imsm_dev(struct imsm_super *mpb, __u8 index)
{
int offset;
@@ -858,30 +885,47 @@ static struct imsm_dev *__get_imsm_dev(struct imsm_super *mpb, __u8 index)
void *_mpb = mpb;
if (index >= mpb->num_raid_devs)
- return NULL;
+ goto error;
/* devices start after all disks */
offset = ((void *) &mpb->disk[mpb->num_disks]) - _mpb;
- for (i = 0; i <= index; i++)
+ for (i = 0; i <= index; i++, offset += sizeof_imsm_dev(_mpb + offset, 0))
if (i == index)
return _mpb + offset;
- else
- offset += sizeof_imsm_dev(_mpb + offset, 0);
-
- return NULL;
+error:
+ pr_err("cannot find imsm_dev with index %u in imsm_super\n", index);
+ abort();
}
+/**
+ * get_imsm_dev() - Get device with index from intel_super.
+ * @super: &intel_super pointer, not NULL.
+ * @index: Device index.
+ *
+ * Function works as non-NULL, aborting in such a case,
+ * when NULL would be returned.
+ *
+ * Device index should be in range 0 up to num_raid_devs.
+ * Function assumes the index was already verified.
+ * Index must be valid, otherwise abort() is called.
+ *
+ * Return: Pointer to corresponding imsm_dev.
+ *
+ */
static struct imsm_dev *get_imsm_dev(struct intel_super *super, __u8 index)
{
struct intel_dev *dv;
if (index >= super->anchor->num_raid_devs)
- return NULL;
+ goto error;
+
for (dv = super->devlist; dv; dv = dv->next)
if (dv->index == index)
return dv->dev;
- return NULL;
+error:
+ pr_err("cannot find imsm_dev with index %u in intel_super\n", index);
+ abort();
}
static inline unsigned long long __le48_to_cpu(const struct bbm_log_block_addr
@@ -1151,7 +1195,7 @@ static void set_imsm_ord_tbl_ent(struct imsm_map *map, int slot, __u32 ord)
map->disk_ord_tbl[slot] = __cpu_to_le32(ord);
}
-static int get_imsm_disk_slot(struct imsm_map *map, unsigned idx)
+static int get_imsm_disk_slot(struct imsm_map *map, const unsigned int idx)
{
int slot;
__u32 ord;
@@ -1162,7 +1206,7 @@ static int get_imsm_disk_slot(struct imsm_map *map, unsigned idx)
return slot;
}
- return -1;
+ return IMSM_STATUS_ERROR;
}
static int get_imsm_raid_level(struct imsm_map *map)
@@ -1177,6 +1221,23 @@ static int get_imsm_raid_level(struct imsm_map *map)
return map->raid_level;
}
+/**
+ * get_disk_slot_in_dev() - retrieve disk slot from &imsm_dev.
+ * @super: &intel_super pointer, not NULL.
+ * @dev_idx: imsm device index.
+ * @idx: disk index.
+ *
+ * Return: Slot on success, IMSM_STATUS_ERROR otherwise.
+ */
+static int get_disk_slot_in_dev(struct intel_super *super, const __u8 dev_idx,
+ const unsigned int idx)
+{
+ struct imsm_dev *dev = get_imsm_dev(super, dev_idx);
+ struct imsm_map *map = get_imsm_map(dev, MAP_0);
+
+ return get_imsm_disk_slot(map, idx);
+}
+
static int cmp_extent(const void *av, const void *bv)
{
const struct extent *a = av;
@@ -1193,13 +1254,9 @@ static int count_memberships(struct dl *dl, struct intel_super *super)
int memberships = 0;
int i;
- for (i = 0; i < super->anchor->num_raid_devs; i++) {
- struct imsm_dev *dev = get_imsm_dev(super, i);
- struct imsm_map *map = get_imsm_map(dev, MAP_0);
-
- if (get_imsm_disk_slot(map, dl->index) >= 0)
+ for (i = 0; i < super->anchor->num_raid_devs; i++)
+ if (get_disk_slot_in_dev(super, i, dl->index) >= 0)
memberships++;
- }
return memberships;
}
@@ -1909,6 +1966,7 @@ void examine_migr_rec_imsm(struct intel_super *super)
/* first map under migration */
map = get_imsm_map(dev, MAP_0);
+
if (map)
slot = get_imsm_disk_slot(map, super->disks->index);
if (map == NULL || slot > 1 || slot < 0) {
@@ -3835,8 +3893,8 @@ struct mdinfo *getinfo_super_disks_imsm(struct supertype *st)
}
static int update_super_imsm(struct supertype *st, struct mdinfo *info,
- char *update, char *devname, int verbose,
- int uuid_set, char *homehost)
+ enum update_opt update, char *devname,
+ int verbose, int uuid_set, char *homehost)
{
/* For 'assemble' and 'force' we need to return non-zero if any
* change was made. For others, the return value is ignored.
@@ -3872,7 +3930,8 @@ static int update_super_imsm(struct supertype *st, struct mdinfo *info,
mpb = super->anchor;
- if (strcmp(update, "uuid") == 0) {
+ switch (update) {
+ case UOPT_UUID:
/* We take this to mean that the family_num should be updated.
* However that is much smaller than the uuid so we cannot really
* allow an explicit uuid to be given. And it is hard to reliably
@@ -3896,10 +3955,14 @@ static int update_super_imsm(struct supertype *st, struct mdinfo *info,
}
if (rv == 0)
mpb->orig_family_num = info->uuid[0];
- } else if (strcmp(update, "assemble") == 0)
+ break;
+ case UOPT_SPEC_ASSEMBLE:
rv = 0;
- else
+ break;
+ default:
rv = -1;
+ break;
+ }
/* successful update? recompute checksum */
if (rv == 0)
@@ -4364,8 +4427,7 @@ int check_mpb_migr_compatibility(struct intel_super *super)
for (i = 0; i < super->anchor->num_raid_devs; i++) {
struct imsm_dev *dev_iter = __get_imsm_dev(super->anchor, i);
- if (dev_iter &&
- dev_iter->vol.migr_state == 1 &&
+ if (dev_iter->vol.migr_state == 1 &&
dev_iter->vol.migr_type == MIGR_GEN_MIGR) {
/* This device is migrating */
map0 = get_imsm_map(dev_iter, MAP_0);
@@ -4514,8 +4576,6 @@ static void clear_hi(struct intel_super *super)
}
for (i = 0; i < mpb->num_raid_devs; ++i) {
struct imsm_dev *dev = get_imsm_dev(super, i);
- if (!dev)
- return;
for (n = 0; n < 2; ++n) {
struct imsm_map *map = get_imsm_map(dev, n);
if (!map)
@@ -5220,7 +5280,7 @@ static int get_super_block(struct intel_super **super_list, char *devnm, char *d
/* retry the load if we might have raced against mdmon */
if (err == 3 && devnm && mdmon_running(devnm))
for (retry = 0; retry < 3; retry++) {
- usleep(3000);
+ sleep_for(0, MSEC_TO_NSEC(3), true);
err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
if (err != 3)
break;
@@ -5322,7 +5382,7 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
if (mdstat && mdmon_running(mdstat->devnm) && getpid() != mdmon_pid(mdstat->devnm)) {
for (retry = 0; retry < 3; retry++) {
- usleep(3000);
+ sleep_for(0, MSEC_TO_NSEC(3), true);
rv = load_and_parse_mpb(fd, super, devname, 0);
if (rv != 3)
break;
@@ -5625,7 +5685,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
free(dev);
free(dv);
pr_err("imsm does not support consistency policy %s\n",
- map_num(consistency_policies, s->consistency_policy));
+ map_num_s(consistency_policies, s->consistency_policy));
return 0;
}
@@ -5734,6 +5794,10 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
struct imsm_map *map;
struct dl *dl, *df;
int slot;
+ int autolayout = 0;
+
+ if (!is_fd_valid(fd))
+ autolayout = 1;
dev = get_imsm_dev(super, super->current_vol);
map = get_imsm_map(dev, MAP_0);
@@ -5744,25 +5808,32 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
return 1;
}
- if (!is_fd_valid(fd)) {
- /* we're doing autolayout so grab the pre-marked (in
- * validate_geometry) raid_disk
- */
- for (dl = super->disks; dl; dl = dl->next)
+ for (dl = super->disks; dl ; dl = dl->next) {
+ if (autolayout) {
if (dl->raiddisk == dk->raid_disk)
break;
- } else {
- for (dl = super->disks; dl ; dl = dl->next)
- if (dl->major == dk->major &&
- dl->minor == dk->minor)
- break;
+ } else if (dl->major == dk->major && dl->minor == dk->minor)
+ break;
}
if (!dl) {
- pr_err("%s is not a member of the same container\n", devname);
+ if (!autolayout)
+ pr_err("%s is not a member of the same container.\n",
+ devname);
return 1;
}
+ if (!autolayout && super->current_vol > 0) {
+ int _slot = get_disk_slot_in_dev(super, 0, dl->index);
+
+ if (_slot != dk->raid_disk) {
+ pr_err("Member %s is in %d slot for the first volume, but is in %d slot for a new volume.\n",
+ dl->devname, _slot, dk->raid_disk);
+ pr_err("Raid members are in different order than for the first volume, aborting.\n");
+ return 1;
+ }
+ }
+
if (mpb->num_disks == 0)
if (!get_dev_sector_size(dl->fd, dl->devname,
&super->sector_size))
@@ -5836,7 +5907,7 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
struct imsm_dev *_dev = __get_imsm_dev(mpb, 0);
_disk = __get_imsm_disk(mpb, dl->index);
- if (!_dev || !_disk) {
+ if (!_disk) {
pr_err("BUG mpb setup error\n");
return 1;
}
@@ -6171,10 +6242,10 @@ static int write_super_imsm(struct supertype *st, int doclose)
for (i = 0; i < mpb->num_raid_devs; i++) {
struct imsm_dev *dev = __get_imsm_dev(mpb, i);
struct imsm_dev *dev2 = get_imsm_dev(super, i);
- if (dev && dev2) {
- imsm_copy_dev(dev, dev2);
- mpb_size += sizeof_imsm_dev(dev, 0);
- }
+
+ imsm_copy_dev(dev, dev2);
+ mpb_size += sizeof_imsm_dev(dev, 0);
+
if (is_gen_migration(dev2))
clear_migration_record = 0;
}
@@ -6467,7 +6538,7 @@ static int validate_ppl_imsm(struct supertype *st, struct mdinfo *info,
if (mdmon_running(st->container_devnm))
st->update_tail = &st->updates;
- if (st->ss->update_subarray(st, subarray, "ppl", NULL)) {
+ if (st->ss->update_subarray(st, subarray, UOPT_PPL, NULL)) {
pr_err("Failed to update subarray %s\n",
subarray);
} else {
@@ -6661,7 +6732,7 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
struct intel_super *super = NULL;
int rv = 0;
- if (level != LEVEL_CONTAINER)
+ if (!is_container(level))
return 0;
if (!dev)
return 1;
@@ -7467,11 +7538,27 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
return 1;
}
-static int imsm_get_free_size(struct supertype *st, int raiddisks,
- unsigned long long size, int chunk,
- unsigned long long *freesize)
+/**
+ * imsm_get_free_size() - get the biggest, common free space from members.
+ * @super: &intel_super pointer, not NULL.
+ * @raiddisks: number of raid disks.
+ * @size: requested size, could be 0 (means max size).
+ * @chunk: requested chunk.
+ * @freesize: pointer for returned size value.
+ *
+ * Return: &IMSM_STATUS_OK or &IMSM_STATUS_ERROR.
+ *
+ * @freesize is set to meaningful value, this can be @size, or calculated
+ * max free size.
+ * super->create_offset value is modified and set appropriately in
+ * merge_extends() for further creation.
+ */
+static imsm_status_t imsm_get_free_size(struct intel_super *super,
+ const int raiddisks,
+ unsigned long long size,
+ const int chunk,
+ unsigned long long *freesize)
{
- struct intel_super *super = st->sb;
struct imsm_super *mpb = super->anchor;
struct dl *dl;
int i;
@@ -7515,12 +7602,10 @@ static int imsm_get_free_size(struct supertype *st, int raiddisks,
/* chunk is in K */
minsize = chunk * 2;
- if (cnt < raiddisks ||
- (super->orom && used && used != raiddisks) ||
- maxsize < minsize ||
- maxsize == 0) {
+ if (cnt < raiddisks || (super->orom && used && used != raiddisks) ||
+ maxsize < minsize || maxsize == 0) {
pr_err("not enough devices with space to create array.\n");
- return 0; /* No enough free spaces large enough */
+ return IMSM_STATUS_ERROR;
}
if (size == 0) {
@@ -7533,37 +7618,69 @@ static int imsm_get_free_size(struct supertype *st, int raiddisks,
}
if (mpb->num_raid_devs > 0 && size && size != maxsize)
pr_err("attempting to create a second volume with size less then remaining space.\n");
- cnt = 0;
- for (dl = super->disks; dl; dl = dl->next)
- if (dl->e)
- dl->raiddisk = cnt++;
-
*freesize = size;
dprintf("imsm: imsm_get_free_size() returns : %llu\n", size);
- return 1;
+ return IMSM_STATUS_OK;
}
-static int reserve_space(struct supertype *st, int raiddisks,
- unsigned long long size, int chunk,
- unsigned long long *freesize)
+/**
+ * autolayout_imsm() - automatically layout a new volume.
+ * @super: &intel_super pointer, not NULL.
+ * @raiddisks: number of raid disks.
+ * @size: requested size, could be 0 (means max size).
+ * @chunk: requested chunk.
+ * @freesize: pointer for returned size value.
+ *
+ * We are being asked to automatically layout a new volume based on the current
+ * contents of the container. If the parameters can be satisfied autolayout_imsm
+ * will record the disks, start offset, and will return size of the volume to
+ * be created. See imsm_get_free_size() for details.
+ * add_to_super() and getinfo_super() detect when autolayout is in progress.
+ * If first volume exists, slots are set consistently to it.
+ *
+ * Return: &IMSM_STATUS_OK on success, &IMSM_STATUS_ERROR otherwise.
+ *
+ * Disks are marked for creation via dl->raiddisk.
+ */
+static imsm_status_t autolayout_imsm(struct intel_super *super,
+ const int raiddisks,
+ unsigned long long size, const int chunk,
+ unsigned long long *freesize)
{
- struct intel_super *super = st->sb;
- struct dl *dl;
- int cnt;
- int rv = 0;
+ int curr_slot = 0;
+ struct dl *disk;
+ int vol_cnt = super->anchor->num_raid_devs;
+ imsm_status_t rv;
- rv = imsm_get_free_size(st, raiddisks, size, chunk, freesize);
- if (rv) {
- cnt = 0;
- for (dl = super->disks; dl; dl = dl->next)
- if (dl->e)
- dl->raiddisk = cnt++;
- rv = 1;
+ rv = imsm_get_free_size(super, raiddisks, size, chunk, freesize);
+ if (rv != IMSM_STATUS_OK)
+ return IMSM_STATUS_ERROR;
+
+ for (disk = super->disks; disk; disk = disk->next) {
+ if (!disk->e)
+ continue;
+
+ if (curr_slot == raiddisks)
+ break;
+
+ if (vol_cnt == 0) {
+ disk->raiddisk = curr_slot;
+ } else {
+ int _slot = get_disk_slot_in_dev(super, 0, disk->index);
+
+ if (_slot == -1) {
+ pr_err("Disk %s is not used in first volume, aborting\n",
+ disk->devname);
+ return IMSM_STATUS_ERROR;
+ }
+ disk->raiddisk = _slot;
+ }
+ curr_slot++;
}
- return rv;
+ return IMSM_STATUS_OK;
}
static int validate_geometry_imsm(struct supertype *st, int level, int layout,
@@ -7580,7 +7697,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
* if given unused devices create a container
* if given given devices in a container create a member volume
*/
- if (level == LEVEL_CONTAINER)
+ if (is_container(level))
/* Must be a fresh device to add to a container */
return validate_geometry_imsm_container(st, level, raiddisks,
data_offset, dev,
@@ -7599,35 +7716,35 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
}
if (!dev) {
- if (st->sb) {
- struct intel_super *super = st->sb;
- if (!validate_geometry_imsm_orom(st->sb, level, layout,
- raiddisks, chunk, size,
- verbose))
+ struct intel_super *super = st->sb;
+
+ /*
+ * Autolayout mode, st->sb must be set.
+ */
+ if (!super) {
+ pr_vrb("superblock must be set for autolayout, aborting\n");
+ return 0;
+ }
+
+ if (!validate_geometry_imsm_orom(st->sb, level, layout,
+ raiddisks, chunk, size,
+ verbose))
+ return 0;
+
+ if (super->orom && freesize) {
+ imsm_status_t rv;
+ int count = count_volumes(super->hba, super->orom->dpa,
+ verbose);
+ if (super->orom->vphba <= count) {
+ pr_vrb("platform does not support more than %d raid volumes.\n",
+ super->orom->vphba);
return 0;
- /* we are being asked to automatically layout a
- * new volume based on the current contents of
- * the container. If the the parameters can be
- * satisfied reserve_space will record the disks,
- * start offset, and size of the volume to be
- * created. add_to_super and getinfo_super
- * detect when autolayout is in progress.
- */
- /* assuming that freesize is always given when array is
- created */
- if (super->orom && freesize) {
- int count;
- count = count_volumes(super->hba,
- super->orom->dpa, verbose);
- if (super->orom->vphba <= count) {
- pr_vrb("platform does not support more than %d raid volumes.\n",
- super->orom->vphba);
- return 0;
- }
}
- if (freesize)
- return reserve_space(st, raiddisks, size,
- *chunk, freesize);
+
+ rv = autolayout_imsm(super, raiddisks, size, *chunk,
+ freesize);
+ if (rv != IMSM_STATUS_OK)
+ return 0;
}
return 1;
}
@@ -7777,36 +7894,39 @@ static int kill_subarray_imsm(struct supertype *st, char *subarray_id)
return 0;
}
-static int get_rwh_policy_from_update(char *update)
+/**
+ * get_rwh_policy_from_update() - Get the rwh policy for update option.
+ * @update: Update option.
+ */
+static int get_rwh_policy_from_update(enum update_opt update)
{
- if (strcmp(update, "ppl") == 0)
+ switch (update) {
+ case UOPT_PPL:
return RWH_MULTIPLE_DISTRIBUTED;
- else if (strcmp(update, "no-ppl") == 0)
+ case UOPT_NO_PPL:
return RWH_MULTIPLE_OFF;
- else if (strcmp(update, "bitmap") == 0)
+ case UOPT_BITMAP:
return RWH_BITMAP;
- else if (strcmp(update, "no-bitmap") == 0)
+ case UOPT_NO_BITMAP:
return RWH_OFF;
- return -1;
+ default:
+ break;
+ }
+ return UOPT_UNDEFINED;
}
static int update_subarray_imsm(struct supertype *st, char *subarray,
- char *update, struct mddev_ident *ident)
+ enum update_opt update, struct mddev_ident *ident)
{
/* update the subarray currently referenced by ->current_vol */
struct intel_super *super = st->sb;
struct imsm_super *mpb = super->anchor;
- if (strcmp(update, "name") == 0) {
+ if (update == UOPT_NAME) {
char *name = ident->name;
char *ep;
int vol;
- if (is_subarray_active(subarray, st->devnm)) {
- pr_err("Unable to update name of active subarray\n");
- return 2;
- }
-
if (!check_name(super, name, 0))
return 2;
@@ -7836,7 +7956,7 @@ static int update_subarray_imsm(struct supertype *st, char *subarray,
}
super->updates_pending++;
}
- } else if (get_rwh_policy_from_update(update) != -1) {
+ } else if (get_rwh_policy_from_update(update) != UOPT_UNDEFINED) {
int new_policy;
char *ep;
int vol = strtoul(subarray, &ep, 10);
@@ -9033,29 +9153,26 @@ static int imsm_rebuild_allowed(struct supertype *cont, int dev_idx, int failed)
__u8 state;
dev2 = get_imsm_dev(cont->sb, dev_idx);
- if (dev2) {
- state = imsm_check_degraded(cont->sb, dev2, failed, MAP_0);
- if (state == IMSM_T_STATE_FAILED) {
- map = get_imsm_map(dev2, MAP_0);
- if (!map)
- return 1;
- for (slot = 0; slot < map->num_members; slot++) {
- /*
- * Check if failed disks are deleted from intel
- * disk list or are marked to be deleted
- */
- idx = get_imsm_disk_idx(dev2, slot, MAP_X);
- idisk = get_imsm_dl_disk(cont->sb, idx);
- /*
- * Do not rebuild the array if failed disks
- * from failed sub-array are not removed from
- * container.
- */
- if (idisk &&
- is_failed(&idisk->disk) &&
- (idisk->action != DISK_REMOVE))
- return 0;
- }
+
+ state = imsm_check_degraded(cont->sb, dev2, failed, MAP_0);
+ if (state == IMSM_T_STATE_FAILED) {
+ map = get_imsm_map(dev2, MAP_0);
+ for (slot = 0; slot < map->num_members; slot++) {
+ /*
+ * Check if failed disks are deleted from intel
+ * disk list or are marked to be deleted
+ */
+ idx = get_imsm_disk_idx(dev2, slot, MAP_X);
+ idisk = get_imsm_dl_disk(cont->sb, idx);
+ /*
+ * Do not rebuild the array if failed disks
+ * from failed sub-array are not removed from
+ * container.
+ */
+ if (idisk &&
+ is_failed(&idisk->disk) &&
+ (idisk->action != DISK_REMOVE))
+ return 0;
}
}
return 1;
@@ -9629,10 +9746,9 @@ static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
/* count arrays using the victim in the metadata */
found = 0;
for (a = active_array; a ; a = a->next) {
- dev = get_imsm_dev(super, a->info.container_member);
- map = get_imsm_map(dev, MAP_0);
+ int dev_idx = a->info.container_member;
- if (get_imsm_disk_slot(map, victim) >= 0)
+ if (get_disk_slot_in_dev(super, dev_idx, victim) >= 0)
found++;
}
@@ -10089,7 +10205,6 @@ static void imsm_process_update(struct supertype *st,
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
@@ -10105,8 +10220,7 @@ static void imsm_process_update(struct supertype *st,
* 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) {
+ if (a || mpb->num_raid_devs == 1 || victim >= super->anchor->num_raid_devs) {
dprintf("failed to delete subarray-%d\n", victim);
break;
}
@@ -10140,7 +10254,7 @@ static void imsm_process_update(struct supertype *st,
if (a->info.container_member == target)
break;
dev = get_imsm_dev(super, u->dev_idx);
- if (a || !dev || !check_name(super, name, 1)) {
+ if (a || !check_name(super, name, 1)) {
dprintf("failed to rename subarray-%d\n", target);
break;
}
@@ -10169,10 +10283,6 @@ static void imsm_process_update(struct supertype *st,
struct imsm_update_rwh_policy *u = (void *)update->buf;
int target = u->dev_idx;
struct imsm_dev *dev = get_imsm_dev(super, target);
- if (!dev) {
- dprintf("could not find subarray-%d\n", target);
- break;
- }
if (dev->rwh_policy != u->new_policy) {
dev->rwh_policy = u->new_policy;
@@ -11397,8 +11507,10 @@ static int imsm_create_metadata_update_for_migration(
{
struct intel_super *super = st->sb;
int update_memory_size;
+ int current_chunk_size;
struct imsm_update_reshape_migration *u;
- struct imsm_dev *dev;
+ struct imsm_dev *dev = get_imsm_dev(super, super->current_vol);
+ struct imsm_map *map = get_imsm_map(dev, MAP_0);
int previous_level = -1;
dprintf("(enter) New Level = %i\n", geo->level);
@@ -11415,23 +11527,15 @@ static int imsm_create_metadata_update_for_migration(
u->new_disks[0] = -1;
u->new_chunksize = -1;
- dev = get_imsm_dev(super, u->subdev);
- if (dev) {
- struct imsm_map *map;
+ current_chunk_size = __le16_to_cpu(map->blocks_per_strip) / 2;
- map = get_imsm_map(dev, MAP_0);
- if (map) {
- int current_chunk_size =
- __le16_to_cpu(map->blocks_per_strip) / 2;
-
- if (geo->chunksize != current_chunk_size) {
- u->new_chunksize = geo->chunksize / 1024;
- dprintf("imsm: chunk size change from %i to %i\n",
- current_chunk_size, u->new_chunksize);
- }
- previous_level = map->raid_level;
- }
+ if (geo->chunksize != current_chunk_size) {
+ u->new_chunksize = geo->chunksize / 1024;
+ dprintf("imsm: chunk size change from %i to %i\n",
+ current_chunk_size, u->new_chunksize);
}
+ previous_level = map->raid_level;
+
if (geo->level == 5 && previous_level == 0) {
struct mdinfo *spares = NULL;
@@ -11499,7 +11603,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
unsigned long long current_size;
unsigned long long free_size;
unsigned long long max_size;
- int rv;
+ imsm_status_t rv;
getinfo_super_imsm_volume(st, &info, NULL);
if (geo->level != info.array.level && geo->level >= 0 &&
@@ -11618,9 +11722,10 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
}
/* check the maximum available size
*/
- rv = imsm_get_free_size(st, dev->vol.map->num_members,
- 0, chunk, &free_size);
- if (rv == 0)
+ rv = imsm_get_free_size(super, dev->vol.map->num_members,
+ 0, chunk, &free_size);
+
+ if (rv != IMSM_STATUS_OK)
/* Cannot find maximum available space
*/
max_size = 0;
@@ -11683,8 +11788,8 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
struct imsm_super *mpb = super->anchor;
if (mpb->num_raid_devs > 1) {
- pr_err("Error. Cannot perform operation on %s- for this operation it MUST be single array in container\n",
- geo->dev_name);
+ pr_err("Error. Cannot perform operation on %s- for this operation "
+ "it MUST be single array in container\n", geo->dev_name);
change = -1;
}
}
@@ -11757,7 +11862,7 @@ static int imsm_fix_size_mismatch(struct supertype *st, int subarray_index)
unsigned long long d_size = imsm_dev_size(dev);
int u_size;
- if (calc_size == d_size || dev->vol.migr_type == MIGR_GEN_MIGR)
+ if (calc_size == d_size)
continue;
/* There is a difference, confirm that imsm_dev_size is
@@ -11772,10 +11877,6 @@ static int imsm_fix_size_mismatch(struct supertype *st, int subarray_index)
geo.size = d_size;
u_size = imsm_create_metadata_update_for_size_change(st, &geo,
&update);
- if (u_size < 1) {
- dprintf("imsm: Cannot prepare size change update\n");
- goto exit;
- }
imsm_update_metadata_locally(st, update, u_size);
if (st->update_tail) {
append_metadata_update(st, update, u_size);
@@ -11783,9 +11884,8 @@ static int imsm_fix_size_mismatch(struct supertype *st, int subarray_index)
st->update_tail = &st->updates;
} else {
imsm_sync_metadata(st);
+ free(update);
}
-
- free(update);
}
ret_val = 0;
exit:
@@ -11992,7 +12092,7 @@ int wait_for_reshape_imsm(struct mdinfo *sra, int ndata)
close(fd);
return 1;
}
- usleep(30000);
+ sleep_for(0, MSEC_TO_NSEC(30), true);
} else
break;
} while (retry--);
@@ -12520,9 +12620,6 @@ static int validate_internal_bitmap_imsm(struct supertype *st)
unsigned long long offset;
struct dl *d;
- if (!dev)
- return -1;
-
if (dev->rwh_policy != RWH_BITMAP)
return 0;
@@ -12568,16 +12665,8 @@ static int add_internal_bitmap_imsm(struct supertype *st, int *chunkp,
return -1;
dev = get_imsm_dev(super, vol_idx);
-
- if (!dev) {
- dprintf("cannot find the device for volume index %d\n",
- vol_idx);
- return -1;
- }
dev->rwh_policy = RWH_BITMAP;
-
*chunkp = calculate_bitmap_chunksize(st, dev);
-
return 0;
}
diff --git a/super0.c b/super0.c
index b79b97a..a7c5f81 100644
--- a/super0.c
+++ b/super0.c
@@ -288,7 +288,7 @@ static void export_examine_super0(struct supertype *st)
{
mdp_super_t *sb = st->sb;
- printf("MD_LEVEL=%s\n", map_num(pers, sb->level));
+ printf("MD_LEVEL=%s\n", map_num_s(pers, sb->level));
printf("MD_DEVICES=%d\n", sb->raid_disks);
if (sb->minor_version >= 90)
printf("MD_UUID=%08x:%08x:%08x:%08x\n",
@@ -491,7 +491,7 @@ static struct mdinfo *container_content0(struct supertype *st, char *subarray)
}
static int update_super0(struct supertype *st, struct mdinfo *info,
- char *update,
+ enum update_opt update,
char *devname, int verbose,
int uuid_set, char *homehost)
{
@@ -503,18 +503,37 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
int uuid[4];
mdp_super_t *sb = st->sb;
- if (strcmp(update, "homehost") == 0 &&
- homehost) {
- /* note that 'homehost' is special as it is really
+ if (update == UOPT_HOMEHOST && homehost) {
+ /*
+ * note that 'homehost' is special as it is really
* a "uuid" update.
*/
uuid_set = 0;
- update = "uuid";
+ update = UOPT_UUID;
info->uuid[0] = sb->set_uuid0;
info->uuid[1] = sb->set_uuid1;
}
- if (strcmp(update, "sparc2.2")==0 ) {
+ switch (update) {
+ case UOPT_UUID:
+ if (!uuid_set && homehost) {
+ char buf[20];
+ memcpy(info->uuid+2,
+ sha1_buffer(homehost, strlen(homehost), buf),
+ 8);
+ }
+ sb->set_uuid0 = info->uuid[0];
+ sb->set_uuid1 = info->uuid[1];
+ sb->set_uuid2 = info->uuid[2];
+ sb->set_uuid3 = info->uuid[3];
+ if (sb->state & (1<<MD_SB_BITMAP_PRESENT)) {
+ struct bitmap_super_s *bm;
+ bm = (struct bitmap_super_s *)(sb+1);
+ uuid_from_super0(st, uuid);
+ memcpy(bm->uuid, uuid, 16);
+ }
+ break;
+ case UOPT_SPARC22: {
/* 2.2 sparc put the events in the wrong place
* So we copy the tail of the superblock
* up 4 bytes before continuing
@@ -527,12 +546,15 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
if (verbose >= 0)
pr_err("adjusting superblock of %s for 2.2/sparc compatibility.\n",
devname);
- } else if (strcmp(update, "super-minor") ==0) {
+ break;
+ }
+ case UOPT_SUPER_MINOR:
sb->md_minor = info->array.md_minor;
if (verbose > 0)
pr_err("updating superblock of %s with minor number %d\n",
devname, info->array.md_minor);
- } else if (strcmp(update, "summaries") == 0) {
+ break;
+ case UOPT_SUMMARIES: {
unsigned int i;
/* set nr_disks, active_disks, working_disks,
* failed_disks, spare_disks based on disks[]
@@ -559,7 +581,9 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
sb->spare_disks++;
} else if (i >= sb->raid_disks && sb->disks[i].number == 0)
sb->disks[i].state = 0;
- } else if (strcmp(update, "force-one")==0) {
+ break;
+ }
+ case UOPT_SPEC_FORCE_ONE: {
/* Not enough devices for a working array, so
* bring this one up-to-date.
*/
@@ -569,7 +593,9 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
if (sb->events_hi != ehi ||
sb->events_lo != elo)
rv = 1;
- } else if (strcmp(update, "force-array")==0) {
+ break;
+ }
+ case UOPT_SPEC_FORCE_ARRAY:
/* degraded array and 'force' requested, so
* maybe need to mark it 'clean'
*/
@@ -579,7 +605,8 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
sb->state |= (1 << MD_SB_CLEAN);
rv = 1;
}
- } else if (strcmp(update, "assemble")==0) {
+ break;
+ case UOPT_SPEC_ASSEMBLE: {
int d = info->disk.number;
int wonly = sb->disks[d].state & (1<<MD_DISK_WRITEMOSTLY);
int failfast = sb->disks[d].state & (1<<MD_DISK_FAILFAST);
@@ -609,7 +636,9 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
sb->reshape_position = info->reshape_progress;
rv = 1;
}
- } else if (strcmp(update, "linear-grow-new") == 0) {
+ break;
+ }
+ case UOPT_SPEC_LINEAR_GROW_NEW:
memset(&sb->disks[info->disk.number], 0, sizeof(sb->disks[0]));
sb->disks[info->disk.number].number = info->disk.number;
sb->disks[info->disk.number].major = info->disk.major;
@@ -617,7 +646,8 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
sb->disks[info->disk.number].raid_disk = info->disk.raid_disk;
sb->disks[info->disk.number].state = info->disk.state;
sb->this_disk = sb->disks[info->disk.number];
- } else if (strcmp(update, "linear-grow-update") == 0) {
+ break;
+ case UOPT_SPEC_LINEAR_GROW_UPDATE:
sb->raid_disks = info->array.raid_disks;
sb->nr_disks = info->array.nr_disks;
sb->active_disks = info->array.active_disks;
@@ -628,29 +658,15 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
sb->disks[info->disk.number].minor = info->disk.minor;
sb->disks[info->disk.number].raid_disk = info->disk.raid_disk;
sb->disks[info->disk.number].state = info->disk.state;
- } else if (strcmp(update, "resync") == 0) {
- /* make sure resync happens */
+ break;
+ case UOPT_RESYNC:
+ /*
+ * make sure resync happens
+ */
sb->state &= ~(1<<MD_SB_CLEAN);
sb->recovery_cp = 0;
- } else if (strcmp(update, "uuid") == 0) {
- if (!uuid_set && homehost) {
- char buf[20];
- char *hash = sha1_buffer(homehost,
- strlen(homehost),
- buf);
- memcpy(info->uuid+2, hash, 8);
- }
- sb->set_uuid0 = info->uuid[0];
- sb->set_uuid1 = info->uuid[1];
- sb->set_uuid2 = info->uuid[2];
- sb->set_uuid3 = info->uuid[3];
- if (sb->state & (1<<MD_SB_BITMAP_PRESENT)) {
- struct bitmap_super_s *bm;
- bm = (struct bitmap_super_s*)(sb+1);
- uuid_from_super0(st, uuid);
- memcpy(bm->uuid, uuid, 16);
- }
- } else if (strcmp(update, "metadata") == 0) {
+ break;
+ case UOPT_METADATA:
/* Create some v1.0 metadata to match ours but make the
* ctime bigger. Also update info->array.*_version.
* We need to arrange that store_super writes out
@@ -670,7 +686,8 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
uuid_from_super0(st, info->uuid);
st->other = super1_make_v0(st, info, st->sb);
}
- } else if (strcmp(update, "revert-reshape") == 0) {
+ break;
+ case UOPT_REVERT_RESHAPE:
rv = -2;
if (sb->minor_version <= 90)
pr_err("No active reshape to revert on %s\n",
@@ -683,7 +700,7 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
int parity = sb->level == 6 ? 2 : 1;
rv = 0;
- if (sb->level >= 4 && sb->level <= 6 &&
+ if (is_level456(sb->level) &&
sb->reshape_position % (
sb->new_chunk/512 *
(sb->raid_disks - sb->delta_disks - parity))) {
@@ -702,16 +719,22 @@ static int update_super0(struct supertype *st, struct mdinfo *info,
sb->new_chunk = sb->chunk_size;
sb->chunk_size = tmp;
}
- } else if (strcmp(update, "no-bitmap") == 0) {
+ break;
+ case UOPT_NO_BITMAP:
sb->state &= ~(1<<MD_SB_BITMAP_PRESENT);
- } else if (strcmp(update, "_reshape_progress")==0)
+ break;
+ case UOPT_SPEC__RESHAPE_PROGRESS:
sb->reshape_position = info->reshape_progress;
- else if (strcmp(update, "writemostly")==0)
+ break;
+ case UOPT_SPEC_WRITEMOSTLY:
sb->state |= (1<<MD_DISK_WRITEMOSTLY);
- else if (strcmp(update, "readwrite")==0)
+ break;
+ case UOPT_SPEC_READWRITE:
sb->state &= ~(1<<MD_DISK_WRITEMOSTLY);
- else
+ break;
+ default:
rv = -1;
+ }
sb->sb_csum = calc_sb0_csum(sb);
return rv;
@@ -1273,7 +1296,7 @@ static int validate_geometry0(struct supertype *st, int level,
if (get_linux_version() < 3001000)
tbmax = 2;
- if (level == LEVEL_CONTAINER) {
+ if (is_container(level)) {
if (verbose)
pr_err("0.90 metadata does not support containers\n");
return 0;
diff --git a/super1.c b/super1.c
index a12a5bc..f702032 100644
--- a/super1.c
+++ b/super1.c
@@ -406,12 +406,18 @@ static void examine_super1(struct supertype *st, char *homehost)
st->ss->getinfo_super(st, &info, NULL);
if (info.space_after != 1 &&
- !(__le32_to_cpu(sb->feature_map) & MD_FEATURE_NEW_OFFSET))
- printf(" Unused Space : before=%llu sectors, after=%llu sectors\n",
- info.space_before, info.space_after);
-
- printf(" State : %s\n",
- (__le64_to_cpu(sb->resync_offset)+1)? "active":"clean");
+ !(__le32_to_cpu(sb->feature_map) & MD_FEATURE_NEW_OFFSET)) {
+ printf(" Unused Space : before=%llu sectors, ",
+ info.space_before);
+ if (info.space_after < INT64_MAX)
+ printf("after=%llu sectors\n", info.space_after);
+ else
+ printf("after=-%llu sectors DEVICE TOO SMALL\n",
+ UINT64_MAX - info.space_after);
+ }
+ printf(" State : %s%s\n",
+ (__le64_to_cpu(sb->resync_offset)+1) ? "active":"clean",
+ (info.space_after > INT64_MAX) ? " TRUNCATED DEVICE" : "");
printf(" Device UUID : ");
for (i=0; i<16; i++) {
if ((i&3)==0 && i != 0)
@@ -671,7 +677,7 @@ static void export_examine_super1(struct supertype *st)
int len = 32;
int layout;
- printf("MD_LEVEL=%s\n", map_num(pers, __le32_to_cpu(sb->level)));
+ printf("MD_LEVEL=%s\n", map_num_s(pers, __le32_to_cpu(sb->level)));
printf("MD_DEVICES=%d\n", __le32_to_cpu(sb->raid_disks));
for (i = 0; i < 32; i++)
if (sb->set_name[i] == '\n' || sb->set_name[i] == '\0') {
@@ -1202,7 +1208,7 @@ static struct mdinfo *container_content1(struct supertype *st, char *subarray)
}
static int update_super1(struct supertype *st, struct mdinfo *info,
- char *update, char *devname, int verbose,
+ enum update_opt update, char *devname, int verbose,
int uuid_set, char *homehost)
{
/* NOTE: for 'assemble' and 'force' we need to return non-zero
@@ -1213,29 +1219,53 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
struct mdp_superblock_1 *sb = st->sb;
bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + MAX_SB_SIZE);
- if (strcmp(update, "homehost") == 0 &&
- homehost) {
- /* Note that 'homehost' is special as it is really
+ if (update == UOPT_HOMEHOST && homehost) {
+ /*
+ * Note that 'homehost' is special as it is really
* a "name" update.
*/
char *c;
- update = "name";
+ update = UOPT_NAME;
c = strchr(sb->set_name, ':');
if (c)
- strncpy(info->name, c+1, 31 - (c-sb->set_name));
+ snprintf(info->name, sizeof(info->name), "%s", c+1);
else
- strncpy(info->name, sb->set_name, 32);
- info->name[32] = 0;
+ snprintf(info->name, sizeof(info->name), "%s", sb->set_name);
}
- if (strcmp(update, "force-one")==0) {
+ switch (update) {
+ case UOPT_NAME: {
+ int namelen;
+
+ if (!info->name[0])
+ snprintf(info->name, sizeof(info->name), "%d", info->array.md_minor);
+ memset(sb->set_name, 0, sizeof(sb->set_name));
+
+ namelen = strnlen(homehost, MD_NAME_MAX) + 1 + strnlen(info->name, MD_NAME_MAX);
+ if (homehost &&
+ strchr(info->name, ':') == NULL &&
+ namelen < MD_NAME_MAX) {
+ strcpy(sb->set_name, homehost);
+ strcat(sb->set_name, ":");
+ strcat(sb->set_name, info->name);
+ } else {
+ namelen = min((int)strnlen(info->name, MD_NAME_MAX),
+ (int)sizeof(sb->set_name) - 1);
+ memcpy(sb->set_name, info->name, namelen);
+ memset(&sb->set_name[namelen], '\0',
+ sizeof(sb->set_name) - namelen);
+ }
+ break;
+ }
+ case UOPT_SPEC_FORCE_ONE:
/* Not enough devices for a working array,
* so bring this one up-to-date
*/
if (sb->events != __cpu_to_le64(info->events))
rv = 1;
sb->events = __cpu_to_le64(info->events);
- } else if (strcmp(update, "force-array")==0) {
+ break;
+ case UOPT_SPEC_FORCE_ARRAY:
/* Degraded array and 'force' requests to
* maybe need to mark it 'clean'.
*/
@@ -1248,7 +1278,8 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
rv = 1;
sb->resync_offset = MaxSector;
}
- } else if (strcmp(update, "assemble")==0) {
+ break;
+ case UOPT_SPEC_ASSEMBLE: {
int d = info->disk.number;
int want;
if (info->disk.state & (1<<MD_DISK_ACTIVE))
@@ -1281,7 +1312,9 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
__cpu_to_le64(info->reshape_progress);
rv = 1;
}
- } else if (strcmp(update, "linear-grow-new") == 0) {
+ break;
+ }
+ case UOPT_SPEC_LINEAR_GROW_NEW: {
int i;
int fd;
int max = __le32_to_cpu(sb->max_dev);
@@ -1324,7 +1357,9 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
ds - __le64_to_cpu(sb->data_offset));
}
}
- } else if (strcmp(update, "linear-grow-update") == 0) {
+ break;
+ }
+ case UOPT_SPEC_LINEAR_GROW_UPDATE: {
int max = __le32_to_cpu(sb->max_dev);
int i = info->disk.number;
if (max > MAX_DEVS || i > MAX_DEVS)
@@ -1336,19 +1371,20 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
sb->raid_disks = __cpu_to_le32(info->array.raid_disks);
sb->dev_roles[info->disk.number] =
__cpu_to_le16(info->disk.raid_disk);
- } else if (strcmp(update, "resync") == 0) {
- /* make sure resync happens */
- sb->resync_offset = 0ULL;
- } else if (strcmp(update, "uuid") == 0) {
+ break;
+ }
+ case UOPT_UUID:
copy_uuid(sb->set_uuid, info->uuid, super1.swapuuid);
if (__le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET)
memcpy(bms->uuid, sb->set_uuid, 16);
- } else if (strcmp(update, "no-bitmap") == 0) {
+ break;
+ case UOPT_NO_BITMAP:
sb->feature_map &= ~__cpu_to_le32(MD_FEATURE_BITMAP_OFFSET);
if (bms->version == BITMAP_MAJOR_CLUSTERED && !IsBitmapDirty(devname))
sb->resync_offset = MaxSector;
- } else if (strcmp(update, "bbl") == 0) {
+ break;
+ case UOPT_BBL: {
/* only possible if there is room after the bitmap, or if
* there is no bitmap
*/
@@ -1377,14 +1413,12 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
bb_offset = bitmap_offset + bm_sectors;
while (bb_offset < (long)sb_offset + 8 + 32*2 &&
bb_offset + 8+8 <= (long)data_offset)
- /* too close to bitmap, and room to grow */
bb_offset += 8;
if (bb_offset + 8 <= (long)data_offset) {
sb->bblog_size = __cpu_to_le16(8);
sb->bblog_offset = __cpu_to_le32(bb_offset);
}
} else {
- /* 1.0 - Put bbl just before super block */
if (bm_sectors && bitmap_offset < 0)
space = -bitmap_offset - bm_sectors;
else
@@ -1395,7 +1429,9 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
sb->bblog_offset = __cpu_to_le32((unsigned)-8);
}
}
- } else if (strcmp(update, "no-bbl") == 0) {
+ break;
+ }
+ case UOPT_NO_BBL:
if (sb->feature_map & __cpu_to_le32(MD_FEATURE_BAD_BLOCKS))
pr_err("Cannot remove active bbl from %s\n",devname);
else {
@@ -1403,12 +1439,14 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
sb->bblog_shift = 0;
sb->bblog_offset = 0;
}
- } else if (strcmp(update, "force-no-bbl") == 0) {
+ break;
+ case UOPT_FORCE_NO_BBL:
sb->feature_map &= ~ __cpu_to_le32(MD_FEATURE_BAD_BLOCKS);
sb->bblog_size = 0;
sb->bblog_shift = 0;
sb->bblog_offset = 0;
- } else if (strcmp(update, "ppl") == 0) {
+ break;
+ case UOPT_PPL: {
unsigned long long sb_offset = __le64_to_cpu(sb->super_offset);
unsigned long long data_offset = __le64_to_cpu(sb->data_offset);
unsigned long long data_size = __le64_to_cpu(sb->data_size);
@@ -1458,37 +1496,26 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
sb->ppl.offset = __cpu_to_le16(offset);
sb->ppl.size = __cpu_to_le16(space);
sb->feature_map |= __cpu_to_le32(MD_FEATURE_PPL);
- } else if (strcmp(update, "no-ppl") == 0) {
+ break;
+ }
+ case UOPT_NO_PPL:
sb->feature_map &= ~__cpu_to_le32(MD_FEATURE_PPL |
MD_FEATURE_MUTLIPLE_PPLS);
- } else if (strcmp(update, "name") == 0) {
- if (info->name[0] == 0)
- sprintf(info->name, "%d", info->array.md_minor);
- memset(sb->set_name, 0, sizeof(sb->set_name));
- if (homehost &&
- strchr(info->name, ':') == NULL &&
- strlen(homehost)+1+strlen(info->name) < 32) {
- strcpy(sb->set_name, homehost);
- strcat(sb->set_name, ":");
- strcat(sb->set_name, info->name);
- } else {
- int namelen;
-
- namelen = min((int)strlen(info->name),
- (int)sizeof(sb->set_name) - 1);
- memcpy(sb->set_name, info->name, namelen);
- memset(&sb->set_name[namelen], '\0',
- sizeof(sb->set_name) - namelen);
- }
- } else if (strcmp(update, "devicesize") == 0 &&
- __le64_to_cpu(sb->super_offset) <
- __le64_to_cpu(sb->data_offset)) {
- /* set data_size to device size less data_offset */
+ break;
+ case UOPT_DEVICESIZE:
+ if (__le64_to_cpu(sb->super_offset) >=
+ __le64_to_cpu(sb->data_offset))
+ break;
+ /*
+ * set data_size to device size less data_offset
+ */
struct misc_dev_info *misc = (struct misc_dev_info*)
(st->sb + MAX_SB_SIZE + BM_SUPER_SIZE);
sb->data_size = __cpu_to_le64(
misc->device_size - __le64_to_cpu(sb->data_offset));
- } else if (strncmp(update, "revert-reshape", 14) == 0) {
+ break;
+ case UOPT_SPEC_REVERT_RESHAPE_NOBACKUP:
+ case UOPT_REVERT_RESHAPE:
rv = -2;
if (!(sb->feature_map &
__cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE)))
@@ -1506,7 +1533,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
* If that couldn't happen, the "-nobackup" version
* will be used.
*/
- if (strcmp(update, "revert-reshape-nobackup") == 0 &&
+ if (update == UOPT_SPEC_REVERT_RESHAPE_NOBACKUP &&
sb->reshape_position == 0 &&
(__le32_to_cpu(sb->delta_disks) > 0 ||
(__le32_to_cpu(sb->delta_disks) == 0 &&
@@ -1530,8 +1557,7 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
* So we reject a revert-reshape unless the
* alignment is good.
*/
- if (__le32_to_cpu(sb->level) >= 4 &&
- __le32_to_cpu(sb->level) <= 6) {
+ if (is_level456(__le32_to_cpu(sb->level))) {
reshape_sectors =
__le64_to_cpu(sb->reshape_position);
reshape_chunk = __le32_to_cpu(sb->new_chunk);
@@ -1570,32 +1596,40 @@ static int update_super1(struct supertype *st, struct mdinfo *info,
}
done:;
}
- } else if (strcmp(update, "_reshape_progress") == 0)
+ break;
+ case UOPT_SPEC__RESHAPE_PROGRESS:
sb->reshape_position = __cpu_to_le64(info->reshape_progress);
- else if (strcmp(update, "writemostly") == 0)
+ break;
+ case UOPT_SPEC_WRITEMOSTLY:
sb->devflags |= WriteMostly1;
- else if (strcmp(update, "readwrite") == 0)
+ break;
+ case UOPT_SPEC_READWRITE:
sb->devflags &= ~WriteMostly1;
- else if (strcmp(update, "failfast") == 0)
+ break;
+ case UOPT_SPEC_FAILFAST:
sb->devflags |= FailFast1;
- else if (strcmp(update, "nofailfast") == 0)
+ break;
+ case UOPT_SPEC_NOFAILFAST:
sb->devflags &= ~FailFast1;
- else if (strcmp(update, "layout-original") == 0 ||
- strcmp(update, "layout-alternate") == 0 ||
- strcmp(update, "layout-unspecified") == 0) {
+ break;
+ case UOPT_LAYOUT_ORIGINAL:
+ case UOPT_LAYOUT_ALTERNATE:
+ case UOPT_LAYOUT_UNSPECIFIED:
if (__le32_to_cpu(sb->level) != 0) {
pr_err("%s: %s only supported for RAID0\n",
- devname?:"", update);
+ devname ?: "", map_num(update_options, update));
rv = -1;
- } else if (strcmp(update, "layout-unspecified") == 0) {
+ } else if (update == UOPT_LAYOUT_UNSPECIFIED) {
sb->feature_map &= ~__cpu_to_le32(MD_FEATURE_RAID0_LAYOUT);
sb->layout = 0;
} else {
sb->feature_map |= __cpu_to_le32(MD_FEATURE_RAID0_LAYOUT);
- sb->layout = __cpu_to_le32(update[7] == 'o' ? 1 : 2);
+ sb->layout = __cpu_to_le32(update == UOPT_LAYOUT_ORIGINAL ? 1 : 2);
}
- } else
+ break;
+ default:
rv = -1;
+ }
sb->sb_csum = calc_sb_1_csum(sb);
@@ -2207,6 +2241,7 @@ static int load_super1(struct supertype *st, int fd, char *devname)
tst.ss = &super1;
for (tst.minor_version = 0; tst.minor_version <= 2;
tst.minor_version++) {
+ tst.ignore_hw_compat = st->ignore_hw_compat;
switch(load_super1(&tst, fd, devname)) {
case 0: super = tst.sb;
if (bestvers == -1 ||
@@ -2313,7 +2348,6 @@ static int load_super1(struct supertype *st, int fd, char *devname)
free(super);
return 2;
}
- st->sb = super;
bsb = (struct bitmap_super_s *)(((char*)super)+MAX_SB_SIZE);
@@ -2323,6 +2357,21 @@ static int load_super1(struct supertype *st, int fd, char *devname)
if (st->data_offset == INVALID_SECTORS)
st->data_offset = __le64_to_cpu(super->data_offset);
+ if (st->minor_version >= 1 &&
+ st->ignore_hw_compat == 0 &&
+ (dsize < (__le64_to_cpu(super->data_offset) +
+ __le64_to_cpu(super->size))
+ ||
+ dsize < (__le64_to_cpu(super->data_offset) +
+ __le64_to_cpu(super->data_size)))) {
+ if (devname)
+ pr_err("Device %s is not large enough for data described in superblock\n",
+ devname);
+ free(super);
+ return 2;
+ }
+ st->sb = super;
+
/* Now check on the bitmap superblock */
if ((__le32_to_cpu(super->feature_map)&MD_FEATURE_BITMAP_OFFSET) == 0)
return 0;
@@ -2674,7 +2723,17 @@ static int write_bitmap1(struct supertype *st, int fd, enum bitmap_update update
}
if (bms->version == BITMAP_MAJOR_CLUSTERED) {
- if (__cpu_to_le32(st->nodes) < bms->nodes) {
+ if (st->nodes == 1) {
+ /* the parameter for nodes is not valid */
+ pr_err("Warning: cluster-md at least needs two nodes\n");
+ return -EINVAL;
+ } else if (st->nodes == 0) {
+ /*
+ * parameter "--nodes" is not specified, (eg, add a disk to
+ * clustered raid)
+ */
+ break;
+ } else if (__cpu_to_le32(st->nodes) < bms->nodes) {
/*
* Since the nodes num is not increased, no
* need to check the space enough or not,
@@ -2800,7 +2859,7 @@ static int validate_geometry1(struct supertype *st, int level,
unsigned long long overhead;
int fd;
- if (level == LEVEL_CONTAINER) {
+ if (is_container(level)) {
if (verbose)
pr_err("1.x metadata does not support containers\n");
return 0;
diff --git a/sysfs.c b/sysfs.c
index 2995713..ca1d888 100644
--- a/sysfs.c
+++ b/sysfs.c
@@ -689,7 +689,7 @@ int sysfs_set_array(struct mdinfo *info, int vers)
if (info->array.level < 0)
return 0; /* FIXME */
rv |= sysfs_set_str(info, NULL, "level",
- map_num(pers, info->array.level));
+ map_num_s(pers, info->array.level));
if (info->reshape_active && info->delta_disks != UnSet)
raid_disks -= info->delta_disks;
rv |= sysfs_set_num(info, NULL, "raid_disks", raid_disks);
@@ -724,9 +724,10 @@ int sysfs_set_array(struct mdinfo *info, int vers)
}
if (info->consistency_policy == CONSISTENCY_POLICY_PPL) {
- if (sysfs_set_str(info, NULL, "consistency_policy",
- map_num(consistency_policies,
- info->consistency_policy))) {
+ char *policy = map_num_s(consistency_policies,
+ info->consistency_policy);
+
+ if (sysfs_set_str(info, NULL, "consistency_policy", policy)) {
pr_err("This kernel does not support PPL. Falling back to consistency-policy=resync.\n");
info->consistency_policy = CONSISTENCY_POLICY_RESYNC;
}
@@ -762,7 +763,7 @@ int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd, int resume)
rv = sysfs_set_num(sra, sd, "offset", sd->data_offset);
rv |= sysfs_set_num(sra, sd, "size", (sd->component_size+1) / 2);
- if (sra->array.level != LEVEL_CONTAINER) {
+ if (!is_container(sra->array.level)) {
if (sra->consistency_policy == CONSISTENCY_POLICY_PPL) {
rv |= sysfs_set_num(sra, sd, "ppl_sector", sd->ppl_sector);
rv |= sysfs_set_num(sra, sd, "ppl_size", sd->ppl_size);
diff --git a/systemd/mdadm-grow-continue@.service b/systemd/mdadm-grow-continue@.service
index 5c667d2..9ccadca 100644
--- a/systemd/mdadm-grow-continue@.service
+++ b/systemd/mdadm-grow-continue@.service
@@ -8,6 +8,7 @@
[Unit]
Description=Manage MD Reshape on /dev/%I
DefaultDependencies=no
+Documentation=man:mdadm(8)
[Service]
ExecStart=BINDIR/mdadm --grow --continue /dev/%I
diff --git a/systemd/mdadm-last-resort@.service b/systemd/mdadm-last-resort@.service
index efeb3f6..e938112 100644
--- a/systemd/mdadm-last-resort@.service
+++ b/systemd/mdadm-last-resort@.service
@@ -2,6 +2,7 @@
Description=Activate md array %I even though degraded
DefaultDependencies=no
ConditionPathExists=!/sys/devices/virtual/block/%i/md/sync_action
+Documentation=man:mdadm(8)
[Service]
Type=oneshot
diff --git a/systemd/mdcheck_continue.service b/systemd/mdcheck_continue.service
index 854317f..f532490 100644
--- a/systemd/mdcheck_continue.service
+++ b/systemd/mdcheck_continue.service
@@ -7,7 +7,8 @@
[Unit]
Description=MD array scrubbing - continuation
-ConditionPathExistsGlob = /var/lib/mdcheck/MD_UUID_*
+ConditionPathExistsGlob=/var/lib/mdcheck/MD_UUID_*
+Documentation=man:mdadm(8)
[Service]
Type=oneshot
diff --git a/systemd/mdcheck_start.service b/systemd/mdcheck_start.service
index 3bb3d13..703a658 100644
--- a/systemd/mdcheck_start.service
+++ b/systemd/mdcheck_start.service
@@ -8,6 +8,7 @@
[Unit]
Description=MD array scrubbing
Wants=mdcheck_continue.timer
+Documentation=man:mdadm(8)
[Service]
Type=oneshot
diff --git a/systemd/mdmon@.service b/systemd/mdmon@.service
index 85a3a7c..cb6482d 100644
--- a/systemd/mdmon@.service
+++ b/systemd/mdmon@.service
@@ -9,6 +9,7 @@
Description=MD Metadata Monitor on /dev/%I
DefaultDependencies=no
Before=initrd-switch-root.target
+Documentation=man:mdmon(8)
[Service]
# mdmon should never complain due to lack of a platform,
diff --git a/systemd/mdmonitor-oneshot.service b/systemd/mdmonitor-oneshot.service
index 373955a..ba86b44 100644
--- a/systemd/mdmonitor-oneshot.service
+++ b/systemd/mdmonitor-oneshot.service
@@ -7,6 +7,7 @@
[Unit]
Description=Reminder for degraded MD arrays
+Documentation=man:mdadm(8)
[Service]
Environment=MDADM_MONITOR_ARGS=--scan
diff --git a/systemd/mdmonitor.service b/systemd/mdmonitor.service
index 46f7b88..9c36478 100644
--- a/systemd/mdmonitor.service
+++ b/systemd/mdmonitor.service
@@ -8,6 +8,7 @@
[Unit]
Description=MD array monitor
DefaultDependencies=no
+Documentation=man:mdadm(8)
[Service]
Environment= MDADM_MONITOR_ARGS=--scan
diff --git a/test b/test
index 711a3c7..61d9ee8 100755
--- a/test
+++ b/test
@@ -10,6 +10,9 @@ devlist=
savelogs=0
exitonerror=1
+ctrl_c_error=0
+skipbroken=0
+loop=1
prefix='[0-9][0-9]'
# use loop devices by default if doesn't specify --dev
@@ -35,6 +38,7 @@ die() {
ctrl_c() {
exitonerror=1
+ ctrl_c_error=1
}
# mdadm always adds --quiet, and we want to see any unexpected messages
@@ -79,8 +83,21 @@ mdadm() {
do_test() {
_script=$1
_basename=`basename $_script`
+ _broken=0
+
if [ -f "$_script" ]
then
+ if [ -f "${_script}.broken" ]; then
+ _broken=1
+ _broken_msg=$(head -n1 "${_script}.broken" | tr -d '\n')
+ if [ "$skipbroken" == "all" ]; then
+ return
+ elif [ "$skipbroken" == "always" ] &&
+ [[ "$_broken_msg" == *always* ]]; then
+ return
+ fi
+ fi
+
rm -f $targetdir/stderr
# this might have been reset: restore the default.
echo 2000 > /proc/sys/dev/raid/speed_limit_max
@@ -97,10 +114,15 @@ do_test() {
else
save_log fail
_fail=1
+ if [ "$_broken" == "1" ]; then
+ echo " (KNOWN BROKEN TEST: $_broken_msg)"
+ fi
fi
[ "$savelogs" == "1" ] &&
mv -f $targetdir/log $logdir/$_basename.log
- [ "$_fail" == "1" -a "$exitonerror" == "1" ] && exit 1
+ [ "$ctrl_c_error" == "1" ] && exit 1
+ [ "$_fail" == "1" -a "$exitonerror" == "1" \
+ -a "$_broken" == "0" ] && exit 1
fi
}
@@ -117,6 +139,9 @@ do_help() {
--logdir=directory Directory to save all logfiles in
--save-logs Usually use with --logdir together
--keep-going | --no-error Don't stop on error, ie. run all tests
+ --loop=N Run tests N times (0 to run forever)
+ --skip-broken Skip tests that are known to be broken
+ --skip-always-broken Skip tests that are known to always fail
--dev=loop|lvm|ram|disk Use loop devices (default), LVM, RAM or disk
--disks= Provide a bunch of physical devices for test
--volgroup=name LVM volume group for LVM test
@@ -211,6 +236,15 @@ parse_args() {
--keep-going | --no-error )
exitonerror=0
;;
+ --loop=* )
+ loop="${i##*=}"
+ ;;
+ --skip-broken )
+ skipbroken=all
+ ;;
+ --skip-always-broken )
+ skipbroken=always
+ ;;
--disable-multipath )
unset MULTIPATH
;;
@@ -263,19 +297,30 @@ main() {
echo "Testing on linux-$(uname -r) kernel"
[ "$savelogs" == "1" ] &&
echo "Saving logs to $logdir"
- if [ "x$TESTLIST" != "x" ]
- then
- for script in ${TESTLIST[@]}
- do
- do_test $testdir/$script
- done
- else
- for script in $testdir/$prefix $testdir/$prefix*[^~]
- do
- do_test $script
- done
- fi
+ while true; do
+ if [ "x$TESTLIST" != "x" ]
+ then
+ for script in ${TESTLIST[@]}
+ do
+ do_test $testdir/$script
+ done
+ else
+ for script in $testdir/$prefix $testdir/$prefix*[^~]
+ do
+ case $script in
+ *.broken) ;;
+ *)
+ do_test $script
+ esac
+ done
+ fi
+
+ let loop=$loop-1
+ if [ "$loop" == "0" ]; then
+ break
+ fi
+ done
exit 0
}
diff --git a/tests/00createnames b/tests/00createnames
new file mode 100644
index 0000000..64b81b9
--- /dev/null
+++ b/tests/00createnames
@@ -0,0 +1,93 @@
+set -x -e
+
+# Test how <devname> and --name= are handled for create mode.
+# We need to check three properties, generated from those parameters:
+# - devnode name
+# - link in /dev/md/ (MD_DEVNAME property from --detail --export)
+# - name in metadata (MD_NAME property from --examine --export)
+
+function _verify() {
+ local DEVNODE_NAME="$1"
+ local WANTED_LINK="$2"
+ local WANTED_NAME="$3"
+
+ local RES="$(mdadm -D --export $DEVNODE_NAME | grep MD_DEVNAME)"
+ if [[ "$?" != "0" ]]; then
+ echo "Cannot get details for $DEVNODE_NAME - unexpected devnode."
+ exit 1
+ fi
+
+ if [[ "$WANTED_LINK" != "empty" ]]; then
+ local EXPECTED="MD_DEVNAME=$WANTED_LINK"
+ if [[ "$RES" != "$EXPECTED" ]]; then
+ echo "$RES doesn't match $EXPECTED."
+ exit 1
+ fi
+ fi
+
+
+ local RES="$(mdadm -E --export $dev0 | grep MD_NAME)"
+ if [[ "$?" != "0" ]]; then
+ echo "Cannot get metadata from $dev0."
+ exit 1
+ fi
+
+ local EXPECTED="MD_NAME=$(hostname):$WANTED_NAME"
+ if [[ "$RES" != "$EXPECTED" ]]; then
+ echo "$RES doesn't match $EXPECTED."
+ exit 1
+ fi
+}
+
+function _create() {
+ local DEVNAME=$1
+ local NAME=$2
+
+ if [[ -z "$NAME" ]]; then
+ mdadm -CR "$DEVNAME" -l0 -n 1 $dev0 --force
+ else
+ mdadm -CR "$DEVNAME" --name="$NAME" -l0 -n 1 $dev0 --force
+ fi
+
+ if [[ "$?" != "0" ]]; then
+ echo "Cannot create device."
+ exit 1
+ fi
+}
+
+# The most trivial case.
+_create "/dev/md/name"
+_verify "/dev/md127" "name" "name"
+mdadm -S "/dev/md127"
+
+_create "name"
+_verify "/dev/md127" "name" "name"
+mdadm -S "/dev/md127"
+
+# Use 'mdX' as name.
+_create "/dev/md/md0"
+_verify "/dev/md127" "md0" "md0"
+mdadm -S "/dev/md127"
+
+_create "md0"
+_verify "/dev/md127" "md0" "md0"
+mdadm -S "/dev/md127"
+
+# <devnode> is used to create MD_DEVNAME but, name is used to create MD_NAME.
+_create "/dev/md/devnode" "name"
+_verify "/dev/md127" "devnode" "name"
+mdadm -S "/dev/md127"
+
+_create "devnode" "name"
+_verify "/dev/md127" "devnode" "name"
+mdadm -S "/dev/md127"
+
+# Devnode points to /dev/ directory. MD_DEVNAME doesn't exist.
+_create "/dev/md0"
+_verify "/dev/md0" "empty" "0"
+mdadm -S "/dev/md0"
+
+# Devnode points to /dev/ directory and name is set.
+_create "/dev/md0" "name"
+_verify "/dev/md0" "empty" "name"
+mdadm -S "/dev/md0"
diff --git a/tests/00raid0 b/tests/00raid0
index 8bc1898..9b8896c 100644
--- a/tests/00raid0
+++ b/tests/00raid0
@@ -6,11 +6,9 @@ check raid0
testdev $md0 3 $mdsize2_l 512
mdadm -S $md0
-# now with version-0.90 superblock
+# verify raid0 with layouts fail for 0.90
mdadm -CR $md0 -e0.90 -l0 -n4 $dev0 $dev1 $dev2 $dev3
-check raid0
-testdev $md0 4 $mdsize0 512
-mdadm -S $md0
+check opposite_result
# now with no superblock
mdadm -B $md0 -l0 -n5 $dev0 $dev1 $dev2 $dev3 $dev4
@@ -22,8 +20,8 @@ mdadm -S $md0
# now same again with different chunk size
for chunk in 4 32 256
do
- mdadm -CR $md0 -e0.90 -l raid0 --chunk $chunk -n3 $dev0 $dev1 $dev2
- check raid0
+ mdadm -CR $md0 -e0.90 -l linear --chunk $chunk -n3 $dev0 $dev1 $dev2
+ check linear
testdev $md0 3 $mdsize0 $chunk
mdadm -S $md0
diff --git a/tests/00readonly b/tests/00readonly
index 28b0fa1..afe243b 100644
--- a/tests/00readonly
+++ b/tests/00readonly
@@ -4,10 +4,15 @@ for metadata in 0.9 1.0 1.1 1.2
do
for level in linear raid0 raid1 raid4 raid5 raid6 raid10
do
+ if [[ $metadata == "0.9" && $level == "raid0" ]];
+ then
+ continue
+ fi
mdadm -CR $md0 -l $level -n 4 --metadata=$metadata \
$dev1 $dev2 $dev3 $dev4 --assume-clean
check nosync
check $level
+ udevadm settle
mdadm -ro $md0
check readonly
state=$(cat /sys/block/md0/md/array_state)
diff --git a/tests/01r5integ.broken b/tests/01r5integ.broken
new file mode 100644
index 0000000..2073763
--- /dev/null
+++ b/tests/01r5integ.broken
@@ -0,0 +1,7 @@
+fails rarely
+
+Fails about 1 in every 30 runs with a sha mismatch error:
+
+ c49ab26e1b01def7874af9b8a6d6d0c29fdfafe6 /dev/md0 does not match
+ 15dc2f73262f811ada53c65e505ceec9cf025cb9 /dev/md0 with /dev/loop3
+ missing
diff --git a/tests/01raid6integ.broken b/tests/01raid6integ.broken
new file mode 100644
index 0000000..1df735f
--- /dev/null
+++ b/tests/01raid6integ.broken
@@ -0,0 +1,7 @@
+fails infrequently
+
+Fails about 1 in 5 with a sha mismatch:
+
+ 8286c2bc045ae2cfe9f8b7ae3a898fa25db6926f /dev/md0 does not match
+ a083a0738b58caab37fd568b91b177035ded37df /dev/md0 with /dev/loop2 and
+ /dev/loop3 missing
diff --git a/tests/02lineargrow b/tests/02lineargrow
index e05c219..595bf9f 100644
--- a/tests/02lineargrow
+++ b/tests/02lineargrow
@@ -20,4 +20,6 @@ do
testdev $md0 3 $sz 1
mdadm -S $md0
+ mdadm --zero /dev/loop2
+ mdadm --zero /dev/loop3
done
diff --git a/tests/03r0assem b/tests/03r0assem
index 6744e32..44df064 100644
--- a/tests/03r0assem
+++ b/tests/03r0assem
@@ -68,9 +68,9 @@ mdadm -S $md2
### Now for version 0...
mdadm --zero-superblock $dev0 $dev1 $dev2
-mdadm -CR $md2 -l0 --metadata=0.90 -n3 $dev0 $dev1 $dev2
-check raid0
-tst="testdev $md2 3 $mdsize0 512"
+mdadm -CR $md2 -llinear --metadata=0.90 -n3 $dev0 $dev1 $dev2
+check linear
+tst="testdev $md2 3 $mdsize0 1"
$tst
uuid=`mdadm -Db $md2 | sed 's/.*UUID=//'`
diff --git a/tests/04r0update b/tests/04r0update
index 73ee3b9..b95efb0 100644
--- a/tests/04r0update
+++ b/tests/04r0update
@@ -1,7 +1,7 @@
# create a raid0, re-assemble with a different super-minor
-mdadm -CR -e 0.90 $md0 -l0 -n3 $dev0 $dev1 $dev2
-testdev $md0 3 $mdsize0 512
+mdadm -CR -e 0.90 $md0 -llinear -n3 $dev0 $dev1 $dev2
+testdev $md0 3 $mdsize0 1
minor1=`mdadm -E $dev0 | sed -n -e 's/.*Preferred Minor : //p'`
mdadm -S /dev/md0
diff --git a/tests/04r5swap.broken b/tests/04r5swap.broken
new file mode 100644
index 0000000..e38987d
--- /dev/null
+++ b/tests/04r5swap.broken
@@ -0,0 +1,7 @@
+always fails
+
+Fails with errors:
+
+ mdadm: /dev/loop0 has no superblock - assembly aborted
+
+ ERROR: no recovery happening
diff --git a/tests/04update-metadata b/tests/04update-metadata
index 232fc1f..2b72a30 100644
--- a/tests/04update-metadata
+++ b/tests/04update-metadata
@@ -8,10 +8,14 @@ set -xe
dlist="$dev0 $dev1 $dev2 $dev3"
-for ls in raid0/4 linear/4 raid1/1 raid5/3 raid6/2
+for ls in linear/4 raid1/1 raid5/3 raid6/2
do
s=${ls#*/} l=${ls%/*}
- mdadm -CR --assume-clean -e 0.90 $md0 --level $l -n 4 -c 64 $dlist
+ if [[ $l == 'raid1' ]]; then
+ mdadm -CR --assume-clean -e 0.90 $md0 --level $l -n 4 $dlist
+ else
+ mdadm -CR --assume-clean -e 0.90 $md0 --level $l -n 4 -c 64 $dlist
+ fi
testdev $md0 $s 19904 64
mdadm -S $md0
mdadm -A $md0 --update=metadata $dlist
diff --git a/tests/07autoassemble.broken b/tests/07autoassemble.broken
new file mode 100644
index 0000000..8be0940
--- /dev/null
+++ b/tests/07autoassemble.broken
@@ -0,0 +1,8 @@
+always fails
+
+Prints lots of messages, but the array doesn't assemble. Error
+possibly related to:
+
+ mdadm: /dev/md/1 is busy - skipping
+ mdadm: no recogniseable superblock on /dev/md/testing:0
+ mdadm: /dev/md/2 is busy - skipping
diff --git a/tests/07autodetect.broken b/tests/07autodetect.broken
new file mode 100644
index 0000000..294954a
--- /dev/null
+++ b/tests/07autodetect.broken
@@ -0,0 +1,5 @@
+always fails
+
+Fails with error:
+
+ ERROR: no resync happening
diff --git a/tests/07changelevelintr.broken b/tests/07changelevelintr.broken
new file mode 100644
index 0000000..284b490
--- /dev/null
+++ b/tests/07changelevelintr.broken
@@ -0,0 +1,9 @@
+always fails
+
+Fails with errors:
+
+ mdadm: this change will reduce the size of the array.
+ use --grow --array-size first to truncate array.
+ e.g. mdadm --grow /dev/md0 --array-size 56832
+
+ ERROR: no reshape happening
diff --git a/tests/07changelevels.broken b/tests/07changelevels.broken
new file mode 100644
index 0000000..9b930d9
--- /dev/null
+++ b/tests/07changelevels.broken
@@ -0,0 +1,9 @@
+always fails
+
+Fails with errors:
+
+ mdadm: /dev/loop0 is smaller than given size. 18976K < 19968K + metadata
+ mdadm: /dev/loop1 is smaller than given size. 18976K < 19968K + metadata
+ mdadm: /dev/loop2 is smaller than given size. 18976K < 19968K + metadata
+
+ ERROR: /dev/md0 isn't a block device.
diff --git a/tests/07reshape5intr.broken b/tests/07reshape5intr.broken
new file mode 100644
index 0000000..efe52a6
--- /dev/null
+++ b/tests/07reshape5intr.broken
@@ -0,0 +1,45 @@
+always fails
+
+This patch, recently added to md-next causes the test to always fail:
+
+7e6ba434cc60 ("md: don't unregister sync_thread with reconfig_mutex
+held")
+
+The new error is simply:
+
+ ERROR: no reshape happening
+
+Before the patch, the error seen is below.
+
+--
+
+fails infrequently
+
+Fails roughly 1 in 4 runs with errors:
+
+ mdadm: Merging with already-assembled /dev/md/0
+ mdadm: cannot re-read metadata from /dev/loop6 - aborting
+
+ ERROR: no reshape happening
+
+Also have seen a random deadlock:
+
+ INFO: task mdadm:109702 blocked for more than 30 seconds.
+ Not tainted 5.18.0-rc3-eid-vmlocalyes-dbg-00095-g3c2b5427979d #2040
+ "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
+ task:mdadm state:D stack: 0 pid:109702 ppid: 1 flags:0x00004000
+ Call Trace:
+ <TASK>
+ __schedule+0x67e/0x13b0
+ schedule+0x82/0x110
+ mddev_suspend+0x2e1/0x330
+ suspend_lo_store+0xbd/0x140
+ md_attr_store+0xcb/0x130
+ sysfs_kf_write+0x89/0xb0
+ kernfs_fop_write_iter+0x202/0x2c0
+ new_sync_write+0x222/0x330
+ vfs_write+0x3bc/0x4d0
+ ksys_write+0xd9/0x180
+ __x64_sys_write+0x43/0x50
+ do_syscall_64+0x3b/0x90
+ entry_SYSCALL_64_after_hwframe+0x44/0xae
diff --git a/tests/07revert-grow.broken b/tests/07revert-grow.broken
new file mode 100644
index 0000000..9b6db86
--- /dev/null
+++ b/tests/07revert-grow.broken
@@ -0,0 +1,31 @@
+always fails
+
+This patch, recently added to md-next causes the test to always fail:
+
+7e6ba434cc60 ("md: don't unregister sync_thread with reconfig_mutex held")
+
+The errors are:
+
+ mdadm: No active reshape to revert on /dev/loop0
+ ERROR: active raid5 not found
+
+Before the patch, the error seen is below.
+
+--
+
+fails rarely
+
+Fails about 1 in every 30 runs with errors:
+
+ mdadm: Merging with already-assembled /dev/md/0
+ mdadm: backup file /tmp/md-backup inaccessible: No such file or directory
+ mdadm: failed to add /dev/loop1 to /dev/md/0: Invalid argument
+ mdadm: failed to add /dev/loop2 to /dev/md/0: Invalid argument
+ mdadm: failed to add /dev/loop3 to /dev/md/0: Invalid argument
+ mdadm: failed to add /dev/loop0 to /dev/md/0: Invalid argument
+ mdadm: /dev/md/0 assembled from 1 drive - need all 5 to start it
+ (use --run to insist).
+
+ grep: /sys/block/md*/md/sync_action: No such file or directory
+
+ ERROR: active raid5 not found
diff --git a/tests/07revert-shrink.broken b/tests/07revert-shrink.broken
new file mode 100644
index 0000000..c33c39e
--- /dev/null
+++ b/tests/07revert-shrink.broken
@@ -0,0 +1,9 @@
+always fails
+
+Fails with errors:
+
+ mdadm: this change will reduce the size of the array.
+ use --grow --array-size first to truncate array.
+ e.g. mdadm --grow /dev/md0 --array-size 53760
+
+ ERROR: active raid5 not found
diff --git a/tests/07testreshape5.broken b/tests/07testreshape5.broken
new file mode 100644
index 0000000..a8ce03e
--- /dev/null
+++ b/tests/07testreshape5.broken
@@ -0,0 +1,12 @@
+always fails
+
+Test seems to run 'test_stripe' at $dir directory, but $dir is never
+set. If $dir is adjusted to $PWD, the test still fails with:
+
+ mdadm: /dev/loop2 is not suitable for this array.
+ mdadm: create aborted
+ ++ return 1
+ ++ cmp -s -n 8192 /dev/md0 /tmp/RandFile
+ ++ echo cmp failed
+ cmp failed
+ ++ exit 2
diff --git a/tests/09imsm-assemble.broken b/tests/09imsm-assemble.broken
new file mode 100644
index 0000000..a6d4d5c
--- /dev/null
+++ b/tests/09imsm-assemble.broken
@@ -0,0 +1,6 @@
+fails infrequently
+
+Fails roughly 1 in 10 runs with errors:
+
+ mdadm: /dev/loop2 is still in use, cannot remove.
+ /dev/loop2 removal from /dev/md/container should have succeeded
diff --git a/tests/09imsm-create-fail-rebuild.broken b/tests/09imsm-create-fail-rebuild.broken
new file mode 100644
index 0000000..40c4b29
--- /dev/null
+++ b/tests/09imsm-create-fail-rebuild.broken
@@ -0,0 +1,5 @@
+always fails
+
+Fails with error:
+
+ **Error**: Array size mismatch - expected 3072, actual 16384
diff --git a/tests/09imsm-overlap b/tests/09imsm-overlap
deleted file mode 100644
index ff5d209..0000000
--- a/tests/09imsm-overlap
+++ /dev/null
@@ -1,28 +0,0 @@
-
-. tests/env-imsm-template
-
-# create raid arrays with varying degress of overlap
-mdadm -CR $container -e imsm -n 6 $dev0 $dev1 $dev2 $dev3 $dev4 $dev5
-imsm_check container 6
-
-size=1024
-level=1
-num_disks=2
-mdadm -CR $member0 $dev0 $dev1 -n $num_disks -l $level -z $size
-mdadm -CR $member1 $dev1 $dev2 -n $num_disks -l $level -z $size
-mdadm -CR $member2 $dev2 $dev3 -n $num_disks -l $level -z $size
-mdadm -CR $member3 $dev3 $dev4 -n $num_disks -l $level -z $size
-mdadm -CR $member4 $dev4 $dev5 -n $num_disks -l $level -z $size
-
-udevadm settle
-
-offset=0
-imsm_check member $member0 $num_disks $level $size 1024 $offset
-offset=$((offset+size+4096))
-imsm_check member $member1 $num_disks $level $size 1024 $offset
-offset=$((offset+size+4096))
-imsm_check member $member2 $num_disks $level $size 1024 $offset
-offset=$((offset+size+4096))
-imsm_check member $member3 $num_disks $level $size 1024 $offset
-offset=$((offset+size+4096))
-imsm_check member $member4 $num_disks $level $size 1024 $offset
diff --git a/tests/09imsm-overlap.broken b/tests/09imsm-overlap.broken
new file mode 100644
index 0000000..e7ccab7
--- /dev/null
+++ b/tests/09imsm-overlap.broken
@@ -0,0 +1,7 @@
+always fails
+
+Fails with errors:
+
+ **Error**: Offset mismatch - expected 15360, actual 0
+ **Error**: Offset mismatch - expected 15360, actual 0
+ /dev/md/vol3 failed check
diff --git a/tests/10ddf-assemble-missing.broken b/tests/10ddf-assemble-missing.broken
new file mode 100644
index 0000000..bfd8d10
--- /dev/null
+++ b/tests/10ddf-assemble-missing.broken
@@ -0,0 +1,6 @@
+always fails
+
+Fails with errors:
+
+ ERROR: /dev/md/vol0 has unexpected state on /dev/loop10
+ ERROR: unexpected number of online disks on /dev/loop10
diff --git a/tests/10ddf-fail-create-race.broken b/tests/10ddf-fail-create-race.broken
new file mode 100644
index 0000000..6c0df02
--- /dev/null
+++ b/tests/10ddf-fail-create-race.broken
@@ -0,0 +1,7 @@
+usually fails
+
+Fails about 9 out of 10 times with many errors:
+
+ mdadm: cannot open MISSING: No such file or directory
+ ERROR: non-degraded array found
+ ERROR: disk 0 not marked as failed in meta data
diff --git a/tests/10ddf-fail-two-spares.broken b/tests/10ddf-fail-two-spares.broken
new file mode 100644
index 0000000..eeea56d
--- /dev/null
+++ b/tests/10ddf-fail-two-spares.broken
@@ -0,0 +1,5 @@
+fails infrequently
+
+Fails roughly 1 in 3 with error:
+
+ ERROR: /dev/md/vol1 should be optimal in meta data
diff --git a/tests/10ddf-incremental-wrong-order.broken b/tests/10ddf-incremental-wrong-order.broken
new file mode 100644
index 0000000..a5af3ba
--- /dev/null
+++ b/tests/10ddf-incremental-wrong-order.broken
@@ -0,0 +1,9 @@
+always fails
+
+Fails with errors:
+ ERROR: sha1sum of /dev/md/vol0 has changed
+ ERROR: /dev/md/vol0 has unexpected state on /dev/loop10
+ ERROR: unexpected number of online disks on /dev/loop10
+ ERROR: /dev/md/vol0 has unexpected state on /dev/loop8
+ ERROR: unexpected number of online disks on /dev/loop8
+ ERROR: sha1sum of /dev/md/vol0 has changed
diff --git a/tests/14imsm-r1_2d-grow-r1_3d.broken b/tests/14imsm-r1_2d-grow-r1_3d.broken
new file mode 100644
index 0000000..4ef1d40
--- /dev/null
+++ b/tests/14imsm-r1_2d-grow-r1_3d.broken
@@ -0,0 +1,5 @@
+always fails
+
+Fails with error:
+
+ mdadm/tests/func.sh: line 325: dvsize/chunk: division by 0 (error token is "chunk")
diff --git a/tests/14imsm-r1_2d-takeover-r0_2d.broken b/tests/14imsm-r1_2d-takeover-r0_2d.broken
new file mode 100644
index 0000000..89cd4e5
--- /dev/null
+++ b/tests/14imsm-r1_2d-takeover-r0_2d.broken
@@ -0,0 +1,6 @@
+always fails
+
+Fails with error:
+
+ tests/func.sh: line 325: dvsize/chunk: division by 0 (error token
+ is "chunk")
diff --git a/tests/18imsm-r10_4d-takeover-r0_2d.broken b/tests/18imsm-r10_4d-takeover-r0_2d.broken
new file mode 100644
index 0000000..a27399f
--- /dev/null
+++ b/tests/18imsm-r10_4d-takeover-r0_2d.broken
@@ -0,0 +1,5 @@
+fails rarely
+
+Fails about 1 run in 100 with message:
+
+ ERROR: size is wrong for /dev/md/vol0: 2 * 5120 (chunk=128) = 20480, not 0
diff --git a/tests/18imsm-r1_2d-takeover-r0_1d.broken b/tests/18imsm-r1_2d-takeover-r0_1d.broken
new file mode 100644
index 0000000..aa1982e
--- /dev/null
+++ b/tests/18imsm-r1_2d-takeover-r0_1d.broken
@@ -0,0 +1,6 @@
+always fails
+
+Fails with error:
+
+ tests/func.sh: line 325: dvsize/chunk: division by 0 (error token
+ is "chunk")
diff --git a/tests/19raid6auto-repair.broken b/tests/19raid6auto-repair.broken
new file mode 100644
index 0000000..e91a142
--- /dev/null
+++ b/tests/19raid6auto-repair.broken
@@ -0,0 +1,5 @@
+always fails
+
+Fails with:
+
+ "should detect errors"
diff --git a/tests/19raid6repair.broken b/tests/19raid6repair.broken
new file mode 100644
index 0000000..e91a142
--- /dev/null
+++ b/tests/19raid6repair.broken
@@ -0,0 +1,5 @@
+always fails
+
+Fails with:
+
+ "should detect errors"
diff --git a/udev-md-raid-arrays.rules b/udev-md-raid-arrays.rules
index 13c9076..2967ace 100644
--- a/udev-md-raid-arrays.rules
+++ b/udev-md-raid-arrays.rules
@@ -3,7 +3,7 @@
SUBSYSTEM!="block", GOTO="md_end"
# handle md arrays
-ACTION!="add|change", GOTO="md_end"
+ACTION=="remove", GOTO="md_end"
KERNEL!="md*", GOTO="md_end"
# partitions have no md/{array_state,metadata_version}, but should not
diff --git a/udev-md-raid-assembly.rules b/udev-md-raid-assembly.rules
index d668cdd..d4a7f0a 100644
--- a/udev-md-raid-assembly.rules
+++ b/udev-md-raid-assembly.rules
@@ -11,6 +11,11 @@ SUBSYSTEM!="block", GOTO="md_inc_end"
ENV{SYSTEMD_READY}=="0", GOTO="md_inc_end"
# handle potential components of arrays (the ones supported by md)
+# For member devices which are md/dm devices, we don't need to
+# handle add event. Because md/dm devices need to do some init jobs.
+# Then the change event happens.
+# When adding md/dm devices, ID_FS_TYPE can only be linux_raid_member
+# after change event happens.
ENV{ID_FS_TYPE}=="linux_raid_member", GOTO="md_inc"
# "noiswmd" on kernel command line stops mdadm from handling
@@ -28,10 +33,14 @@ GOTO="md_inc_end"
LABEL="md_inc"
+# Bare disks are ready when add event happens, the raid can be assembled.
+ACTION=="change", KERNEL!="dm-*|md*", GOTO="md_inc_end"
+
# remember you can limit what gets auto/incrementally assembled by
# mdadm.conf(5)'s 'AUTO' and selectively whitelist using 'ARRAY'
-ACTION=="add|change", IMPORT{program}="BINDIR/mdadm --incremental --export $devnode --offroot $env{DEVLINKS}"
-ACTION=="add|change", ENV{MD_STARTED}=="*unsafe*", ENV{MD_FOREIGN}=="no", ENV{SYSTEMD_WANTS}+="mdadm-last-resort@$env{MD_DEVICE}.timer"
+ACTION!="remove", IMPORT{program}="BINDIR/mdadm --incremental --export $devnode --offroot $env{DEVLINKS}"
+ACTION!="remove", ENV{MD_STARTED}=="*unsafe*", ENV{MD_FOREIGN}=="no", ENV{SYSTEMD_WANTS}+="mdadm-last-resort@$env{MD_DEVICE}.timer"
+
ACTION=="remove", ENV{ID_PATH}=="?*", RUN+="BINDIR/mdadm -If $name --path $env{ID_PATH}"
ACTION=="remove", ENV{ID_PATH}!="?*", RUN+="BINDIR/mdadm -If $name"
diff --git a/udev-md-raid-safe-timeouts.rules b/udev-md-raid-safe-timeouts.rules
index 12bdcaa..2e185ce 100644
--- a/udev-md-raid-safe-timeouts.rules
+++ b/udev-md-raid-safe-timeouts.rules
@@ -50,7 +50,7 @@ ENV{DEVTYPE}!="partition", GOTO="md_timeouts_end"
IMPORT{program}="/sbin/mdadm --examine --export $devnode"
-ACTION=="add|change", \
+ACTION!="remove", \
ENV{ID_FS_TYPE}=="linux_raid_member", \
ENV{MD_LEVEL}=="raid[1-9]*", \
TEST=="/sys/block/$parent/device/timeout", \
diff --git a/util.c b/util.c
index 3d05d07..9cd89fa 100644
--- a/util.c
+++ b/util.c
@@ -35,7 +35,6 @@
#include <poll.h>
#include <ctype.h>
#include <dirent.h>
-#include <signal.h>
#include <dlfcn.h>
@@ -167,7 +166,7 @@ retry:
pr_err("error %d when get PW mode on lock %s\n", errno, str);
/* let's try several times if EAGAIN happened */
if (dlm_lock_res->lksb.sb_status == EAGAIN && retry_count < 10) {
- sleep(10);
+ sleep_for(10, 0, true);
retry_count++;
goto retry;
}
@@ -268,7 +267,7 @@ int md_array_active(int fd)
* GET_ARRAY_INFO doesn't provide access to the proper state
* information, so fallback to a basic check for raid_disks != 0
*/
- ret = ioctl(fd, GET_ARRAY_INFO, &array);
+ ret = md_get_array_info(fd, &array);
}
return !ret;
@@ -969,47 +968,30 @@ dev_t devnm2devid(char *devnm)
return 0;
}
+/**
+ * get_md_name() - Get main dev node of the md device.
+ * @devnm: Md device name or path.
+ *
+ * Function checks if the full name was passed and returns md name
+ * if it is the MD device.
+ *
+ * Return: Main dev node of the md device or NULL if not found.
+ */
char *get_md_name(char *devnm)
{
- /* find /dev/md%d or /dev/md/%d or make a device /dev/.tmp.md%d */
- /* if dev < 0, want /dev/md/d%d or find mdp in /proc/devices ... */
-
- static char devname[50];
+ static char devname[NAME_MAX];
struct stat stb;
- dev_t rdev = devnm2devid(devnm);
- char *dn;
- if (rdev == 0)
- return 0;
- if (strncmp(devnm, "md_", 3) == 0) {
- snprintf(devname, sizeof(devname), "/dev/md/%s",
- devnm + 3);
- if (stat(devname, &stb) == 0 &&
- (S_IFMT&stb.st_mode) == S_IFBLK && (stb.st_rdev == rdev))
- return devname;
- }
- snprintf(devname, sizeof(devname), "/dev/%s", devnm);
- if (stat(devname, &stb) == 0 && (S_IFMT&stb.st_mode) == S_IFBLK &&
- (stb.st_rdev == rdev))
- return devname;
+ if (strncmp(devnm, "/dev/", 5) == 0)
+ snprintf(devname, sizeof(devname), "%s", devnm);
+ else
+ snprintf(devname, sizeof(devname), "/dev/%s", devnm);
- snprintf(devname, sizeof(devname), "/dev/md/%s", devnm+2);
- if (stat(devname, &stb) == 0 && (S_IFMT&stb.st_mode) == S_IFBLK &&
- (stb.st_rdev == rdev))
+ if (!is_mddev(devname))
+ return NULL;
+ if (stat(devname, &stb) == 0 && (S_IFMT&stb.st_mode) == S_IFBLK)
return devname;
- dn = map_dev(major(rdev), minor(rdev), 0);
- if (dn)
- return dn;
- snprintf(devname, sizeof(devname), "/dev/.tmp.%s", devnm);
- if (mknod(devname, S_IFBLK | 0600, rdev) == -1)
- if (errno != EEXIST)
- return NULL;
-
- if (stat(devname, &stb) == 0 && (S_IFMT&stb.st_mode) == S_IFBLK &&
- (stb.st_rdev == rdev))
- return devname;
- unlink(devname);
return NULL;
}
@@ -1028,6 +1010,20 @@ int get_maj_min(char *dev, int *major, int *minor)
*e == 0);
}
+/**
+ * is_bit_set() - get bit value by index.
+ * @val: value.
+ * @index: index of the bit (LSB numbering).
+ *
+ * Return: bit value.
+ */
+bool is_bit_set(int *val, unsigned char index)
+{
+ if ((*val) & (1 << index))
+ return true;
+ return false;
+}
+
int dev_open(char *dev, int flags)
{
/* like 'open', but if 'dev' matches %d:%d, create a temp
@@ -1086,7 +1082,7 @@ int open_dev_excl(char *devnm)
int i;
int flags = O_RDWR;
dev_t devid = devnm2devid(devnm);
- long delay = 1000;
+ unsigned int delay = 1; // miliseconds
sprintf(buf, "%d:%d", major(devid), minor(devid));
for (i = 0; i < 25; i++) {
@@ -1099,8 +1095,8 @@ int open_dev_excl(char *devnm)
}
if (errno != EBUSY)
return fd;
- usleep(delay);
- if (delay < 200000)
+ sleep_for(0, MSEC_TO_NSEC(delay), true);
+ if (delay < 200)
delay *= 2;
}
return -1;
@@ -1124,7 +1120,7 @@ void wait_for(char *dev, int fd)
{
int i;
struct stat stb_want;
- long delay = 1000;
+ unsigned int delay = 1; // miliseconds
if (fstat(fd, &stb_want) != 0 ||
(stb_want.st_mode & S_IFMT) != S_IFBLK)
@@ -1136,8 +1132,8 @@ void wait_for(char *dev, int fd)
(stb.st_mode & S_IFMT) == S_IFBLK &&
(stb.st_rdev == stb_want.st_rdev))
return;
- usleep(delay);
- if (delay < 200000)
+ sleep_for(0, MSEC_TO_NSEC(delay), true);
+ if (delay < 200)
delay *= 2;
}
if (i == 25)
@@ -1822,7 +1818,7 @@ int hot_remove_disk(int mdfd, unsigned long dev, int force)
while ((ret = ioctl(mdfd, HOT_REMOVE_DISK, dev)) == -1 &&
errno == EBUSY &&
cnt-- > 0)
- usleep(10000);
+ sleep_for(0, MSEC_TO_NSEC(10), true);
return ret;
}
@@ -1835,7 +1831,7 @@ int sys_hot_remove_disk(int statefd, int force)
while ((ret = write(statefd, "remove", 6)) == -1 &&
errno == EBUSY &&
cnt-- > 0)
- usleep(10000);
+ sleep_for(0, MSEC_TO_NSEC(10), true);
return ret == 6 ? 0 : -1;
}
@@ -2376,3 +2372,27 @@ out:
close(fd_zero);
return ret;
}
+
+/**
+ * sleep_for() - Sleeps for specified time.
+ * @sec: Seconds to sleep for.
+ * @nsec: Nanoseconds to sleep for, has to be less than one second.
+ * @wake_after_interrupt: If set, wake up if interrupted.
+ *
+ * Function immediately returns if error different than EINTR occurs.
+ */
+void sleep_for(unsigned int sec, long nsec, bool wake_after_interrupt)
+{
+ struct timespec delay = {.tv_sec = sec, .tv_nsec = nsec};
+
+ assert(nsec < MSEC_TO_NSEC(1000));
+
+ do {
+ errno = 0;
+ nanosleep(&delay, &delay);
+ if (errno != 0 && errno != EINTR) {
+ pr_err("Error sleeping for %us %ldns: %s\n", sec, nsec, strerror(errno));
+ return;
+ }
+ } while (!wake_after_interrupt && errno == EINTR);
+}