1
0
Fork 0

Merging upstream version 4.2+20231026.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-14 06:32:02 +01:00
parent bb079da599
commit a701b01644
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
30 changed files with 956 additions and 423 deletions

View file

@ -428,8 +428,6 @@ static int select_devices(struct mddev_dev *devlist,
/* make sure we finished the loop */
tmpdev = NULL;
free(st);
st = NULL;
goto loop;
} else {
content = *contentp;
@ -1992,12 +1990,10 @@ int assemble_container_content(struct supertype *st, int mdfd,
return 1;
}
if (strcmp(sra->text_version, content->text_version) != 0) {
if (content->array.major_version == -1 &&
content->array.minor_version == -2 &&
c->readonly &&
content->text_version[0] == '/')
content->text_version[0] = '-';
/* Fill sysfs properties only if they are not set. Determine it by checking text_version
* and ignoring special character on the first place.
*/
if (strcmp(sra->text_version + 1, content->text_version + 1) != 0) {
if (sysfs_set_array(content, 9003) != 0) {
sysfs_free(sra);
return 1;

21
Build.c
View file

@ -24,8 +24,8 @@
#include "mdadm.h"
int Build(char *mddev, struct mddev_dev *devlist,
struct shape *s, struct context *c)
int Build(struct mddev_ident *ident, struct mddev_dev *devlist, struct shape *s,
struct context *c)
{
/* Build a linear or raid0 arrays without superblocks
* We cannot really do any checks, we just do it.
@ -75,13 +75,12 @@ int Build(char *mddev, struct mddev_dev *devlist,
/* We need to create the device. It can have no name. */
map_lock(&map);
mdfd = create_mddev(mddev, NULL, c->autof, LOCAL,
mdfd = create_mddev(ident->devname, NULL, c->autof, LOCAL,
chosen_name, 0);
if (mdfd < 0) {
map_unlock(&map);
return 1;
}
mddev = chosen_name;
map_update(&map, fd2devnm(mdfd), "none", uuid, chosen_name);
map_unlock(&map);
@ -93,7 +92,7 @@ int Build(char *mddev, struct mddev_dev *devlist,
array.nr_disks = s->raiddisks;
array.raid_disks = s->raiddisks;
array.md_minor = 0;
if (fstat_is_blkdev(mdfd, mddev, &rdev))
if (fstat_is_blkdev(mdfd, chosen_name, &rdev))
array.md_minor = minor(rdev);
array.not_persistent = 1;
array.state = 0; /* not clean, but no errors */
@ -108,8 +107,7 @@ int Build(char *mddev, struct mddev_dev *devlist,
array.chunk_size = s->chunk*1024;
array.layout = s->layout;
if (md_set_array_info(mdfd, &array)) {
pr_err("md_set_array_info() failed for %s: %s\n",
mddev, strerror(errno));
pr_err("md_set_array_info() failed for %s: %s\n", chosen_name, strerror(errno));
goto abort;
}
@ -178,8 +176,8 @@ int Build(char *mddev, struct mddev_dev *devlist,
}
if (bitmap_fd >= 0) {
if (ioctl(mdfd, SET_BITMAP_FILE, bitmap_fd) < 0) {
pr_err("Cannot set bitmap file for %s: %s\n",
mddev, strerror(errno));
pr_err("Cannot set bitmap file for %s: %s\n", chosen_name,
strerror(errno));
goto abort;
}
}
@ -193,9 +191,8 @@ int Build(char *mddev, struct mddev_dev *devlist,
}
if (c->verbose >= 0)
pr_err("array %s built and started.\n",
mddev);
wait_for(mddev, mdfd);
pr_err("array %s built and started.\n", chosen_name);
wait_for(chosen_name, mdfd);
close(mdfd);
return 0;

View file

@ -471,11 +471,8 @@ out:
return ret;
}
int Create(struct supertype *st, char *mddev,
char *name, int *uuid,
int subdevs, struct mddev_dev *devlist,
struct shape *s,
struct context *c)
int Create(struct supertype *st, struct mddev_ident *ident, int subdevs,
struct mddev_dev *devlist, struct shape *s, struct context *c)
{
/*
* Create a new raid array.
@ -497,6 +494,8 @@ int Create(struct supertype *st, char *mddev,
unsigned long long minsize = 0, maxsize = 0;
char *mindisc = NULL;
char *maxdisc = NULL;
char *name = ident->name;
int *uuid = ident->uuid_set == 1 ? ident->uuid : NULL;
int dnum;
struct mddev_dev *dv;
dev_t rdev;
@ -1015,7 +1014,7 @@ int Create(struct supertype *st, char *mddev,
/* We need to create the device */
map_lock(&map);
mdfd = create_mddev(mddev, name, c->autof, LOCAL, chosen_name, 1);
mdfd = create_mddev(ident->devname, ident->name, c->autof, LOCAL, chosen_name, 1);
if (mdfd < 0) {
map_unlock(&map);
return 1;
@ -1032,7 +1031,6 @@ int Create(struct supertype *st, char *mddev,
udev_unblock();
return 1;
}
mddev = chosen_name;
memset(&inf, 0, sizeof(inf));
md_get_array_info(mdfd, &inf);
@ -1050,7 +1048,7 @@ int Create(struct supertype *st, char *mddev,
* with, but it chooses to trust me instead. Sigh
*/
info.array.md_minor = 0;
if (fstat_is_blkdev(mdfd, mddev, &rdev))
if (fstat_is_blkdev(mdfd, chosen_name, &rdev))
info.array.md_minor = minor(rdev);
info.array.not_persistent = 0;
@ -1102,8 +1100,8 @@ int Create(struct supertype *st, char *mddev,
info.array.layout = s->layout;
info.array.chunk_size = s->chunk*1024;
if (name == NULL || *name == 0) {
/* base name on mddev */
if (*name == 0) {
/* base name on devname */
/* /dev/md0 -> 0
* /dev/md_d0 -> d0
* /dev/md_foo -> foo
@ -1113,15 +1111,16 @@ int Create(struct supertype *st, char *mddev,
* /dev/mdhome -> home
*/
/* FIXME compare this with rules in create_mddev */
name = strrchr(mddev, '/');
name = strrchr(chosen_name, '/');
if (name) {
name++;
if (strncmp(name, "md_", 3) == 0 &&
strlen(name) > 3 && (name-mddev) == 5 /* /dev/ */)
strlen(name) > 3 && (name - chosen_name) == 5 /* /dev/ */)
name += 3;
else if (strncmp(name, "md", 2) == 0 &&
strlen(name) > 2 && isdigit(name[2]) &&
(name-mddev) == 5 /* /dev/ */)
(name - chosen_name) == 5 /* /dev/ */)
name += 2;
}
}
@ -1215,8 +1214,7 @@ int Create(struct supertype *st, char *mddev,
}
rv = set_array_info(mdfd, st, &info);
if (rv) {
pr_err("failed to set array info for %s: %s\n",
mddev, strerror(errno));
pr_err("failed to set array info for %s: %s\n", chosen_name, strerror(errno));
goto abort_locked;
}
@ -1237,8 +1235,7 @@ int Create(struct supertype *st, char *mddev,
goto abort_locked;
}
if (ioctl(mdfd, SET_BITMAP_FILE, bitmap_fd) < 0) {
pr_err("Cannot set bitmap file for %s: %s\n",
mddev, strerror(errno));
pr_err("Cannot set bitmap file for %s: %s\n", chosen_name, strerror(errno));
goto abort_locked;
}
}
@ -1254,7 +1251,7 @@ int Create(struct supertype *st, char *mddev,
* create links */
sysfs_uevent(&info, "change");
if (c->verbose >= 0)
pr_err("container %s prepared.\n", mddev);
pr_err("container %s prepared.\n", chosen_name);
wait_for(chosen_name, mdfd);
} else if (c->runstop == 1 || subdevs >= s->raiddisks) {
if (st->ss->external) {
@ -1312,7 +1309,7 @@ int Create(struct supertype *st, char *mddev,
ioctl(mdfd, RESTART_ARRAY_RW, NULL);
}
if (c->verbose >= 0)
pr_info("array %s started.\n", mddev);
pr_info("array %s started.\n", chosen_name);
if (st->ss->external && st->container_devnm[0]) {
if (need_mdmon)
start_mdmon(st->container_devnm);

View file

@ -254,11 +254,9 @@ int Detail(char *dev, struct context *c)
fname_from_uuid(st, info, nbuf, ':');
printf("MD_UUID=%s\n", nbuf + 5);
mp = map_by_uuid(&map, info->uuid);
if (mp && mp->path && strncmp(mp->path, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) {
printf("MD_DEVNAME=");
print_escape(mp->path + DEV_MD_DIR_LEN);
putchar('\n');
}
if (mp && mp->path && strncmp(mp->path, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0)
printf("MD_DEVNAME=%s\n", mp->path + DEV_MD_DIR_LEN);
if (st->ss->export_detail_super)
st->ss->export_detail_super(st);
@ -271,12 +269,9 @@ int Detail(char *dev, struct context *c)
__fname_from_uuid(mp->uuid, 0, nbuf, ':');
printf("MD_UUID=%s\n", nbuf+5);
}
if (mp && mp->path &&
strncmp(mp->path, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) {
printf("MD_DEVNAME=");
print_escape(mp->path + DEV_MD_DIR_LEN);
putchar('\n');
}
if (mp && mp->path && strncmp(mp->path, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0)
printf("MD_DEVNAME=%s\n", mp->path + DEV_MD_DIR_LEN);
map_free(map);
}
if (!c->no_devices && sra) {

View file

@ -1467,17 +1467,6 @@ static int Incremental_container(struct supertype *st, char *devname,
st->ss->getinfo_super(st, &info, NULL);
if ((c->runstop > 0 && info.container_enough >= 0) ||
info.container_enough > 0)
/* pass */;
else {
if (c->export) {
printf("MD_STARTED=no\n");
} else if (c->verbose)
pr_err("not enough devices to start the container\n");
return 0;
}
match = conf_match(st, &info, devname, c->verbose, &rv);
if (match == NULL && rv == 2)
return rv;
@ -1628,54 +1617,18 @@ release:
return rv;
}
static void run_udisks(char *arg1, char *arg2)
{
int pid = fork();
int status;
if (pid == 0) {
manage_fork_fds(1);
execl("/usr/bin/udisks", "udisks", arg1, arg2, NULL);
execl("/bin/udisks", "udisks", arg1, arg2, NULL);
exit(1);
}
while (pid > 0 && wait(&status) != pid)
;
}
static int force_remove(char *devnm, int fd, struct mdinfo *mdi, int verbose)
{
int rv;
int devid = devnm2devid(devnm);
run_udisks("--unmount", map_dev(major(devid), minor(devid), 0));
rv = Manage_stop(devnm, fd, verbose, 1);
if (rv) {
/* At least we can try to trigger a 'remove' */
sysfs_uevent(mdi, "remove");
if (verbose)
pr_err("Fail to stop %s too.\n", devnm);
}
return rv;
}
static void remove_from_member_array(struct mdstat_ent *memb,
struct mddev_dev *devlist, int verbose)
{
int rv;
struct mdinfo mmdi;
int subfd = open_dev(memb->devnm);
if (subfd >= 0) {
rv = Manage_subdevs(memb->devnm, subfd, devlist, verbose,
0, UOPT_UNDEFINED, 0);
if (rv & 2) {
if (sysfs_init(&mmdi, -1, memb->devnm))
pr_err("unable to initialize sysfs for: %s\n",
memb->devnm);
else
force_remove(memb->devnm, subfd, &mmdi,
verbose);
}
/*
* Ignore the return value because it's necessary
* to handle failure condition here.
*/
Manage_subdevs(memb->devnm, subfd, devlist, verbose,
0, UOPT_UNDEFINED, 0);
close(subfd);
}
}
@ -1758,21 +1711,19 @@ int IncrementalRemove(char *devname, char *id_path, int verbose)
}
free_mdstat(mdstat);
} else {
rv |= Manage_subdevs(ent->devnm, mdfd, &devlist,
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.
/*
* This 'I' incremental remove is a try-best effort,
* the failure condition can be safely ignored
* because of the following up 'r' remove.
*/
rv = force_remove(ent->devnm, mdfd, &mdi, verbose);
goto end;
}
Manage_subdevs(ent->devnm, mdfd, &devlist,
verbose, 0, UOPT_UNDEFINED, 0);
}
devlist.disposition = 'r';
rv = Manage_subdevs(ent->devnm, mdfd, &devlist,
verbose, 0, UOPT_UNDEFINED, 0);
end:
close(mdfd);
free_mdstat(ent);
return rv;

View file

@ -30,7 +30,7 @@
# define "CXFLAGS" to give extra flags to CC.
# e.g. make CXFLAGS=-O to optimise
CXFLAGS ?=-O2
CXFLAGS ?=-O2 -D_FORTIFY_SOURCE=2
TCC = tcc
UCLIBC_GCC = $(shell for nm in i386-uclibc-linux-gcc i386-uclibc-gcc; do which $$nm > /dev/null && { echo $$nm ; exit; } ; done; echo false No uclibc found )
#DIET_GCC = diet gcc
@ -50,14 +50,30 @@ ifeq ($(origin CC),default)
CC := $(CROSS_COMPILE)gcc
endif
CXFLAGS ?= -ggdb
CWFLAGS = -Wall -Werror -Wstrict-prototypes -Wextra -Wno-unused-parameter
CWFLAGS ?= -Wall -Werror -Wstrict-prototypes -Wextra -Wno-unused-parameter -Wformat -Wformat-security -Werror=format-security -fstack-protector-strong -fPIE -Warray-bounds
ifdef WARN_UNUSED
CWFLAGS += -Wp,-D_FORTIFY_SOURCE=2 -O3
CWFLAGS += -Wp -O3
endif
FALLTHROUGH := $(shell gcc -v --help 2>&1 | grep "implicit-fallthrough" | wc -l)
ifneq "$(FALLTHROUGH)" "0"
CWFLAGS += -Wimplicit-fallthrough=0
ifeq ($(origin FALLTHROUGH), undefined)
FALLTHROUGH := $(shell gcc -Q --help=warnings 2>&1 | grep "implicit-fallthrough" | wc -l)
ifneq "$(FALLTHROUGH)" "0"
CWFLAGS += -Wimplicit-fallthrough=0
endif
endif
ifeq ($(origin FORMATOVERFLOW), undefined)
FORMATOVERFLOW := $(shell gcc -Q --help=warnings 2>&1 | grep "format-overflow" | wc -l)
ifneq "$(FORMATOVERFLOW)" "0"
CWFLAGS += -Wformat-overflow
endif
endif
ifeq ($(origin STRINGOPOVERFLOW), undefined)
STRINGOPOVERFLOW := $(shell gcc -Q --help=warnings 2>&1 | grep "stringop-overflow" | wc -l)
ifneq "$(STRINGOPOVERFLOW)" "0"
CWFLAGS += -Wstringop-overflow
endif
endif
ifdef DEBIAN
@ -116,10 +132,12 @@ CFLAGS += -DUSE_PTHREADS
MON_LDFLAGS += -pthread
endif
LDFLAGS = -Wl,-z,now,-z,noexecstack
# If you want a static binary, you might uncomment these
# LDFLAGS = -static
# LDFLAGS += -static
# STRIP = -s
LDLIBS = -ldl
LDLIBS = -ldl -pie
# To explicitly disable libudev, set -DNO_LIBUDEV in CXFLAGS
ifeq (, $(findstring -DNO_LIBUDEV, $(CXFLAGS)))
@ -209,14 +227,13 @@ mdadm.Os : $(SRCS) $(INCL)
$(CC) -o mdadm.Os $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -DHAVE_STDINT_H -Os $(SRCS) $(LDLIBS)
mdadm.O2 : $(SRCS) $(INCL) mdmon.O2
$(CC) -o mdadm.O2 $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -DHAVE_STDINT_H -O2 -D_FORTIFY_SOURCE=2 $(SRCS) $(LDLIBS)
$(CC) -o mdadm.O2 $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -DHAVE_STDINT_H -O2 $(SRCS) $(LDLIBS)
mdmon.O2 : $(MON_SRCS) $(INCL) mdmon.h
$(CC) -o mdmon.O2 $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(MON_LDFLAGS) -DHAVE_STDINT_H -O2 -D_FORTIFY_SOURCE=2 $(MON_SRCS) $(LDLIBS)
$(CC) -o mdmon.O2 $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(MON_LDFLAGS) -DHAVE_STDINT_H -O2 $(MON_SRCS) $(LDLIBS)
# use '-z now' to guarantee no dynamic linker interactions with the monitor thread
mdmon : $(MON_OBJS) | check_rundir
$(CC) $(CFLAGS) $(LDFLAGS) $(MON_LDFLAGS) -Wl,-z,now -o mdmon $(MON_OBJS) $(LDLIBS)
$(CC) $(CFLAGS) $(LDFLAGS) $(MON_LDFLAGS) -o mdmon $(MON_OBJS) $(LDLIBS)
msg.o: msg.c msg.h
test_stripe : restripe.c xmalloc.o mdadm.h

View file

@ -704,6 +704,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
struct supertype *dev_st;
int j;
mdu_disk_info_t disc;
struct map_ent *map = NULL;
if (!get_dev_size(tfd, dv->devname, &ldsize)) {
if (dv->disposition == 'M')
@ -907,6 +908,9 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
disc.raid_disk = 0;
}
if (map_lock(&map))
pr_err("failed to get exclusive lock on mapfile when add disk\n");
if (array->not_persistent==0) {
int dfd;
if (dv->disposition == 'j')
@ -918,9 +922,9 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
dfd = dev_open(dv->devname, O_RDWR | O_EXCL|O_DIRECT);
if (tst->ss->add_to_super(tst, &disc, dfd,
dv->devname, INVALID_SECTORS))
return -1;
goto unlock;
if (tst->ss->write_init_super(tst))
return -1;
goto unlock;
} else if (dv->disposition == 'A') {
/* this had better be raid1.
* As we are "--re-add"ing we must find a spare slot
@ -978,14 +982,14 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
pr_err("add failed for %s: could not get exclusive access to container\n",
dv->devname);
tst->ss->free_super(tst);
return -1;
goto unlock;
}
/* Check if metadata handler is able to accept the drive */
if (!tst->ss->validate_geometry(tst, LEVEL_CONTAINER, 0, 1, NULL,
0, 0, dv->devname, NULL, 0, 1)) {
close(container_fd);
return -1;
goto unlock;
}
Kill(dv->devname, NULL, 0, -1, 0);
@ -994,7 +998,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
dv->devname, INVALID_SECTORS)) {
close(dfd);
close(container_fd);
return -1;
goto unlock;
}
if (!mdmon_running(tst->container_devnm))
tst->ss->sync_metadata(tst);
@ -1005,7 +1009,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
dv->devname);
close(container_fd);
tst->ss->free_super(tst);
return -1;
goto unlock;
}
sra->array.level = LEVEL_CONTAINER;
/* Need to set data_offset and component_size */
@ -1020,7 +1024,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
pr_err("add new device to external metadata failed for %s\n", dv->devname);
close(container_fd);
sysfs_free(sra);
return -1;
goto unlock;
}
ping_monitor(devnm);
sysfs_free(sra);
@ -1034,7 +1038,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
else
pr_err("add new device failed for %s as %d: %s\n",
dv->devname, j, strerror(errno));
return -1;
goto unlock;
}
if (dv->disposition == 'j') {
pr_err("Journal added successfully, making %s read-write\n", devname);
@ -1045,7 +1049,11 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
}
if (verbose >= 0)
pr_err("added %s\n", dv->devname);
map_unlock(&map);
return 1;
unlock:
map_unlock(&map);
return -1;
}
int Manage_remove(struct supertype *tst, int fd, struct mddev_dev *dv,

184
config.c
View file

@ -122,7 +122,7 @@ int match_keyword(char *word)
/**
* is_devname_ignore() - check if &devname is a special "<ignore>" keyword.
*/
bool is_devname_ignore(char *devname)
bool is_devname_ignore(const char *devname)
{
static const char keyword[] = "<ignore>";
@ -131,6 +131,34 @@ bool is_devname_ignore(char *devname)
return false;
}
/**
* ident_log() - generate and write message to the user.
* @param_name: name of the property.
* @value: value of the property.
* @reason: meaningful description.
* @cmdline: context dependent actions, see below.
*
* The function is made to provide similar error handling for both config and cmdline. The behavior
* is configurable via @cmdline. Message has following format:
* "Value "@value" cannot be set for @param_name. Reason: @reason."
*
* If cmdline is on:
* - message is written to stderr.
* otherwise:
* - message is written to stdout.
* - "Value ignored" is added at the end of the message.
*/
static void ident_log(const char *param_name, const char *value, const char *reason,
const bool cmdline)
{
if (cmdline == true)
pr_err("Value \"%s\" cannot be set as %s. Reason: %s.\n", value, param_name,
reason);
else
pr_info("Value \"%s\" cannot be set as %s. Reason: %s. Value ignored.\n", value,
param_name, reason);
}
/**
* ident_init() - Set defaults.
* @ident: ident pointer, not NULL.
@ -159,6 +187,127 @@ inline void ident_init(struct mddev_ident *ident)
ident->uuid_set = 0;
}
/**
* _ident_set_devname()- verify devname and set it in &mddev_ident.
* @ident: pointer to &mddev_ident.
* @devname: devname to be set.
* @cmdline: context dependent actions. If set, ignore keyword is not allowed.
*
* @devname can have following forms:
* '<ignore>' keyword (if allowed)
* /dev/md{number}
* /dev/md_d{number} (legacy)
* /dev/md_{name}
* /dev/md/{name}
* {name}
*
* {name} must follow name's criteria and be POSIX compatible.
* If criteria passed, duplicate memory and set devname in @ident.
*
* Return: %MDADM_STATUS_SUCCESS or %MDADM_STATUS_ERROR.
*/
mdadm_status_t _ident_set_devname(struct mddev_ident *ident, const char *devname,
const bool cmdline)
{
assert(ident);
assert(devname);
static const char named_dev_pref[] = DEV_NUM_PREF "_";
static const int named_dev_pref_size = sizeof(named_dev_pref) - 1;
const char *prop_name = "devname";
const char *name;
if (ident->devname) {
ident_log(prop_name, devname, "Already defined", cmdline);
return MDADM_STATUS_ERROR;
}
if (is_devname_ignore(devname) == true) {
if (!cmdline)
goto pass;
ident_log(prop_name, devname, "Special keyword is invalid in this context",
cmdline);
return MDADM_STATUS_ERROR;
}
if (is_devname_md_numbered(devname) == true || is_devname_md_d_numbered(devname) == true)
goto pass;
if (strncmp(devname, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0)
name = devname + DEV_MD_DIR_LEN;
else if (strncmp(devname, named_dev_pref, named_dev_pref_size) == 0)
name = devname + named_dev_pref_size;
else
name = devname;
if (is_name_posix_compatible(name) == false) {
ident_log(prop_name, name, "Not POSIX compatible", cmdline);
return MDADM_STATUS_ERROR;
}
if (is_string_lq(name, MD_NAME_MAX + 1) == false) {
ident_log(prop_name, devname, "Invalid length", cmdline);
return MDADM_STATUS_ERROR;
}
pass:
ident->devname = xstrdup(devname);
return MDADM_STATUS_SUCCESS;
}
/**
* _ident_set_name()- set name in &mddev_ident.
* @ident: pointer to &mddev_ident.
* @name: name to be set.
* @cmdline: context dependent actions.
*
* If criteria passed, set name in @ident.
*
* Return: %MDADM_STATUS_SUCCESS or %MDADM_STATUS_ERROR.
*/
static mdadm_status_t _ident_set_name(struct mddev_ident *ident, const char *name,
const bool cmdline)
{
assert(name);
assert(ident);
const char *prop_name = "name";
if (ident->name[0]) {
ident_log(prop_name, name, "Already defined", cmdline);
return MDADM_STATUS_ERROR;
}
if (is_string_lq(name, MD_NAME_MAX + 1) == false) {
ident_log(prop_name, name, "Too long or empty", cmdline);
return MDADM_STATUS_ERROR;
}
if (is_name_posix_compatible(name) == false) {
ident_log(prop_name, name, "Not POSIX compatible", cmdline);
return MDADM_STATUS_ERROR;
}
snprintf(ident->name, MD_NAME_MAX + 1, "%s", name);
return MDADM_STATUS_SUCCESS;
}
/**
* ident_set_devname()- exported, for cmdline.
*/
mdadm_status_t ident_set_devname(struct mddev_ident *ident, const char *name)
{
return _ident_set_devname(ident, name, true);
}
/**
* ident_set_name()- exported, for cmdline.
*/
mdadm_status_t ident_set_name(struct mddev_ident *ident, const char *name)
{
return _ident_set_name(ident, name, true);
}
struct conf_dev {
struct conf_dev *next;
char *name;
@ -396,29 +545,7 @@ void arrayline(char *line)
for (w = dl_next(line); w != line; w = dl_next(w)) {
if (w[0] == '/' || strchr(w, '=') == NULL) {
/* This names the device, or is '<ignore>'.
* The rules match those in create_mddev.
* 'w' must be:
* /dev/md/{anything}
* /dev/mdNN
* /dev/md_dNN
* <ignore>
* or anything that doesn't start '/' or '<'
*/
if (is_devname_ignore(w) == true ||
strncmp(w, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0 ||
(w[0] != '/' && w[0] != '<') ||
is_devname_md_numbered(w) == true ||
is_devname_md_d_numbered(w) == true) {
/* This is acceptable */;
if (mis.devname)
pr_err("only give one device per ARRAY line: %s and %s\n",
mis.devname, w);
else
mis.devname = w;
}else {
pr_err("%s is an invalid name for an md device - ignored.\n", w);
}
_ident_set_devname(&mis, w, false);
} else if (strncasecmp(w, "uuid=", 5) == 0) {
if (mis.uuid_set)
pr_err("only specify uuid once, %s ignored.\n",
@ -444,14 +571,7 @@ void arrayline(char *line)
mis.super_minor = minor;
}
} else if (strncasecmp(w, "name=", 5) == 0) {
if (mis.name[0])
pr_err("only specify name once, %s ignored.\n",
w);
else if (strlen(w + 5) > 32)
pr_err("name too long, ignoring %s\n", w);
else
strcpy(mis.name, w + 5);
_ident_set_name(&mis, w + 5, false);
} else if (strncasecmp(w, "bitmap=", 7) == 0) {
if (mis.bitmap_file)
pr_err("only specify bitmap file once. %s ignored\n",

76
lib.c
View file

@ -27,6 +27,24 @@
#include <ctype.h>
#include <limits.h>
/**
* is_string_lq() - Check if string length with NULL byte is lower or equal to requested.
* @str: string to check.
* @max_len: max length.
*
* @str length must be bigger than 0 and be lower or equal @max_len, including termination byte.
*/
bool is_string_lq(const char * const str, size_t max_len)
{
assert(str);
size_t _len = strnlen(str, max_len);
if (_len > 0 && _len < max_len)
return true;
return false;
}
bool is_dev_alive(char *path)
{
if (!path)
@ -465,24 +483,50 @@ void print_quoted(char *str)
putchar(q);
}
void print_escape(char *str)
/**
* is_alphanum() - Check if sign is letter or digit.
* @c: char to analyze.
*
* Similar to isalnum() but additional locales are excluded.
*
* Return: %true on success, %false otherwise.
*/
bool is_alphanum(const char c)
{
/* print str, but change space and tab to '_'
* as is suitable for device names
*/
for (; *str; str++) {
switch (*str) {
case ' ':
case '\t':
putchar('_');
break;
case '/':
putchar('-');
break;
default:
putchar(*str);
}
if (isupper(c) || islower(c) || isdigit(c) != 0)
return true;
return false;
}
/**
* is_name_posix_compatible() - Check if name is POSIX compatible.
* @name: name to check.
*
* POSIX portable file name character set contains ASCII letters,
* digits, '_', '.', and '-'. Also forbid leading '-'.
* The length of the name cannot exceed NAME_MAX - 1 (ensure NULL ending).
*
* Return: %true on success, %false otherwise.
*/
bool is_name_posix_compatible(const char * const name)
{
assert(name);
char allowed_symbols[] = "-_.";
const char *n = name;
if (!is_string_lq(name, NAME_MAX))
return false;
if (*n == '-')
return false;
while (*n != '\0') {
if (!is_alphanum(*n) && !strchr(allowed_symbols, *n))
return false;
n++;
}
return true;
}
int check_env(char *name)

View file

@ -364,7 +364,7 @@ Use the Intel(R) Matrix Storage Manager metadata format. This creates a
which is managed in a similar manner to DDF, and is supported by an
option-rom on some platforms:
.IP
.B https://www.intel.com/content/www/us/en/support/products/122484/memory-and-storage/ssd-software/intel-virtual-raid-on-cpu-intel-vroc.html
.B https://www.intel.com/content/www/us/en/support/products/122484
.PP
.RE
@ -932,17 +932,14 @@ option will be ignored.
.BR \-N ", " \-\-name=
Set a
.B name
for the array. This is currently only effective when creating an
array with a version-1 superblock, or an array in a DDF container.
The name is a simple textual string that can be used to identify array
components when assembling. If name is needed but not specified, it
is taken from the basename of the device that is being created.
e.g. when creating
.I /dev/md/home
the
.B name
will default to
.IR home .
for the array. It must be
.BR "POSIX PORTABLE NAME"
compatible and cannot be longer than 32 chars. This is effective when creating an array
with a v1 metadata, or an external array.
If name is needed but not specified, it is taken from the basename of the device
that is being created. See
.BR "DEVICE NAMES"
.TP
.BR \-R ", " \-\-run
@ -1132,8 +1129,10 @@ is much safer.
.TP
.BR \-N ", " \-\-name=
Specify the name of the array to assemble. This must be the name
that was specified when creating the array. It must either match
Specify the name of the array to assemble. It must be
.BR "POSIX PORTABLE NAME"
compatible and cannot be longer than 32 chars. This must be the name
that was specified when creating the array. It must either match
the name stored in the superblock exactly, or it must match
with the current
.I homehost
@ -2179,14 +2178,17 @@ Usage:
.I md-device
.BI \-\-chunk= X
.BI \-\-level= Y
.br
.BI \-\-raid\-devices= Z
.I devices
.PP
This usage will initialise a new md array, associate some devices with
This usage will initialize a new md array, associate some devices with
it, and activate the array.
.I md-device
is a new device. This could be standard name or chosen name. For details see:
.BR "DEVICE NAMES"
The named device will normally not exist when
.I "mdadm \-\-create"
is run, but will be created by
@ -2227,24 +2229,6 @@ array. This feature can be overridden with the
.B \-\-force
option.
When creating an array with version-1 metadata a name for the array is
required.
If this is not given with the
.B \-\-name
option,
.I mdadm
will choose a name based on the last component of the name of the
device being created. So if
.B /dev/md3
is being created, then the name
.B 3
will be chosen.
If
.B /dev/md/home
is being created, then the name
.B home
will be used.
When creating a partition based array, using
.I mdadm
with version-1.x metadata, the partition type should be set to
@ -2429,12 +2413,10 @@ and
The
.B name
option updates the subarray name in the metadata, it may not affect the
device node name or the device node symlink until the subarray is
re\-assembled. If updating
.B name
would change the UUID of an active subarray this operation is blocked,
and the command will end in an error.
option updates the subarray name in the metadata. It must be
.BR "POSIX PORTABLE NAME"
compatible and cannot be longer than 32 chars. If successes, new value will be respected after
next assembly.
The
.B ppl
@ -3395,6 +3377,10 @@ When
.B \-\-incremental
mode is used, this file gets a list of arrays currently being created.
.SH POSIX PORTABLE NAME
A valid name can only consist of characters "A-Za-z0-9.-_".
The name cannot start with a leading "-" and cannot exceed 255 chars.
.SH DEVICE NAMES
.I mdadm
@ -3416,6 +3402,10 @@ can be given, or just the suffix of the second sort of name, such as
.I home
can be given.
In every style, raw name must be compatible with
.BR "POSIX PORTABLE NAME"
and has to be no longer than 32 chars.
When
.I mdadm
chooses device names during auto-assembly or incremental assembly, it

73
mdadm.c
View file

@ -690,20 +690,14 @@ int main(int argc, char *argv[])
case O(CREATE,'N'):
case O(ASSEMBLE,'N'):
case O(MISC,'N'):
if (ident.name[0]) {
pr_err("name cannot be set twice. Second value %s.\n", optarg);
exit(2);
}
if (mode == MISC && !c.subarray) {
pr_err("-N/--name only valid with --update-subarray in misc mode\n");
exit(2);
}
if (strlen(optarg) > 32) {
pr_err("name '%s' is too long, 32 chars max.\n",
optarg);
if (ident_set_name(&ident, optarg) != MDADM_STATUS_SUCCESS)
exit(2);
}
strcpy(ident.name, optarg);
continue;
case O(ASSEMBLE,'m'): /* super-minor for array */
@ -1290,37 +1284,33 @@ int main(int argc, char *argv[])
pr_err("an md device must be given in this mode\n");
exit(2);
}
if (ident_set_devname(&ident, devlist->devname) != MDADM_STATUS_SUCCESS)
exit(1);
if ((int)ident.super_minor == -2 && c.autof) {
pr_err("--super-minor=dev is incompatible with --auto\n");
exit(2);
}
if (mode == MANAGE || mode == GROW) {
mdfd = open_mddev(devlist->devname, 1);
mdfd = open_mddev(ident.devname, 1);
if (mdfd < 0)
exit(1);
ret = fstat(mdfd, &stb);
if (ret) {
pr_err("fstat failed on %s.\n", devlist->devname);
pr_err("fstat failed on %s.\n", ident.devname);
exit(1);
}
} else {
char *bname = basename(devlist->devname);
if (strlen(bname) > MD_NAME_MAX) {
pr_err("Name %s is too long.\n", devlist->devname);
exit(1);
}
ret = stat(devlist->devname, &stb);
ret = stat(ident.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);
ident.devname);
exit(1);
}
if (!ret && !stat_is_md_dev(&stb)) {
pr_err("device %s exists but is not an md array.\n", devlist->devname);
pr_err("device %s exists but is not an md array.\n", ident.devname);
exit(1);
}
}
@ -1408,17 +1398,17 @@ int main(int argc, char *argv[])
case MANAGE:
/* readonly, add/remove, readwrite, runstop */
if (c.readonly > 0)
rv = Manage_ro(devlist->devname, mdfd, c.readonly);
rv = Manage_ro(ident.devname, mdfd, c.readonly);
if (!rv && devs_found > 1)
rv = Manage_subdevs(devlist->devname, mdfd,
rv = Manage_subdevs(ident.devname, mdfd,
devlist->next, c.verbose,
c.test, c.update, c.force);
if (!rv && c.readonly < 0)
rv = Manage_ro(devlist->devname, mdfd, c.readonly);
rv = Manage_ro(ident.devname, mdfd, c.readonly);
if (!rv && c.runstop > 0)
rv = Manage_run(devlist->devname, mdfd, &c);
rv = Manage_run(ident.devname, mdfd, &c);
if (!rv && c.runstop < 0)
rv = Manage_stop(devlist->devname, mdfd, c.verbose, 0);
rv = Manage_stop(ident.devname, mdfd, c.verbose, 0);
break;
case ASSEMBLE:
if (!c.scan && c.runstop == -1) {
@ -1428,22 +1418,19 @@ int main(int argc, char *argv[])
ident.super_minor == UnSet && ident.name[0] == 0 &&
!c.scan) {
/* Only a device has been given, so get details from config file */
struct mddev_ident *array_ident = conf_get_ident(devlist->devname);
struct mddev_ident *array_ident = conf_get_ident(ident.devname);
if (array_ident == NULL) {
pr_err("%s not identified in config file.\n",
devlist->devname);
pr_err("%s not identified in config file.\n", ident.devname);
rv |= 1;
if (mdfd >= 0)
close(mdfd);
} else {
if (array_ident->autof == 0)
array_ident->autof = c.autof;
rv |= Assemble(ss, devlist->devname, array_ident,
NULL, &c);
rv |= Assemble(ss, ident.devname, array_ident, NULL, &c);
}
} else if (!c.scan)
rv = Assemble(ss, devlist->devname, &ident,
devlist->next, &c);
rv = Assemble(ss, ident.devname, &ident, devlist->next, &c);
else if (devs_found > 0) {
if (c.update && devs_found > 1) {
pr_err("can only update a single array at a time\n");
@ -1501,7 +1488,7 @@ int main(int argc, char *argv[])
break;
}
}
rv = Build(devlist->devname, devlist->next, &s, &c);
rv = Build(&ident, devlist->next, &s, &c);
break;
case CREATE:
if (c.delay == 0)
@ -1538,9 +1525,7 @@ int main(int argc, char *argv[])
break;
}
rv = Create(ss, devlist->devname,
ident.name, ident.uuid_set ? ident.uuid : NULL,
devs_found - 1, devlist->next, &s, &c);
rv = Create(ss, &ident, devs_found - 1, devlist->next, &s, &c);
break;
case MISC:
if (devmode == 'E') {
@ -1637,8 +1622,7 @@ int main(int argc, char *argv[])
break;
}
for (dv = devlist->next; dv; dv = dv->next) {
rv = Grow_Add_device(devlist->devname, mdfd,
dv->devname);
rv = Grow_Add_device(ident.devname, mdfd, dv->devname);
if (rv)
break;
}
@ -1651,18 +1635,15 @@ int main(int argc, char *argv[])
}
if (c.delay == 0)
c.delay = DEFAULT_BITMAP_DELAY;
rv = Grow_addbitmap(devlist->devname, mdfd, &c, &s);
rv = Grow_addbitmap(ident.devname, mdfd, &c, &s);
} else if (grow_continue)
rv = Grow_continue_command(devlist->devname,
mdfd, c.backup_file,
c.verbose);
rv = Grow_continue_command(ident.devname, mdfd, c.backup_file, c.verbose);
else if (s.size > 0 || s.raiddisks || s.layout_str ||
s.chunk != 0 || s.level != UnSet ||
s.data_offset != INVALID_SECTORS) {
rv = Grow_reshape(devlist->devname, mdfd,
devlist->next, &c, &s);
rv = Grow_reshape(ident.devname, mdfd, devlist->next, &c, &s);
} else if (s.consistency_policy != CONSISTENCY_POLICY_UNKNOWN) {
rv = Grow_consistency_policy(devlist->devname, mdfd, &c, &s);
rv = Grow_consistency_policy(ident.devname, mdfd, &c, &s);
} else if (array_size == 0)
pr_err("no changes to --grow\n");
break;

View file

@ -717,10 +717,6 @@ ARRAY /dev/md/home UUID=9187a482:5dde19d9:eea3cc4a:d646ab8b
.br
auto=part
.br
# The name of this array contains a space.
.br
ARRAY /dev/md9 name='Data Storage'
.sp
POLICY domain=domain1 metadata=imsm path=pci-0000:00:1f.2-scsi-*
.br
action=spare

39
mdadm.h
View file

@ -294,6 +294,11 @@ static inline void __put_unaligned32(__u32 val, void *p)
#define KIB_TO_BYTES(x) ((x) << 10)
#define SEC_TO_BYTES(x) ((x) << 9)
/**
* This is true for native and DDF, IMSM allows 16.
*/
#define MD_NAME_MAX 32
extern const char Name[];
struct md_bb_entry {
@ -372,9 +377,6 @@ struct mdinfo {
int container_member; /* for assembling external-metatdata arrays
* This is to be used internally by metadata
* handler only */
int container_enough; /* flag external handlers can set to
* indicate that subarrays have not enough (-1),
* enough to start (0), or all expected disks (1) */
char sys_name[32];
struct mdinfo *devs;
struct mdinfo *next;
@ -425,6 +427,12 @@ struct spare_criteria {
unsigned int sector_size;
};
typedef enum mdadm_status {
MDADM_STATUS_SUCCESS = 0,
MDADM_STATUS_ERROR,
MDADM_STATUS_UNDEF,
} mdadm_status_t;
enum mode {
ASSEMBLE=1,
BUILD,
@ -593,7 +601,7 @@ struct mddev_ident {
int uuid_set;
int uuid[4];
char name[33];
char name[MD_NAME_MAX + 1];
int super_minor;
@ -1531,14 +1539,11 @@ extern int Assemble(struct supertype *st, char *mddev,
struct mddev_dev *devlist,
struct context *c);
extern int Build(char *mddev, struct mddev_dev *devlist,
struct shape *s, struct context *c);
extern int Build(struct mddev_ident *ident, struct mddev_dev *devlist, struct shape *s,
struct context *c);
extern int Create(struct supertype *st, char *mddev,
char *name, int *uuid,
int subdevs, struct mddev_dev *devlist,
struct shape *s,
struct context *c);
extern int Create(struct supertype *st, struct mddev_ident *ident, int subdevs,
struct mddev_dev *devlist, struct shape *s, 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);
@ -1609,9 +1614,11 @@ extern int check_raid(int fd, char *name);
extern int check_partitions(int fd, char *dname,
unsigned long long freesize,
unsigned long long size);
extern bool is_name_posix_compatible(const char *path);
extern int fstat_is_blkdev(int fd, char *devname, dev_t *rdev);
extern int stat_is_blkdev(char *devname, dev_t *rdev);
extern bool is_string_lq(const char * const str, size_t max_len);
extern bool is_dev_alive(char *path);
extern int get_mdp_major(void);
extern int get_maj_min(char *dev, int *major, int *minor);
@ -1629,6 +1636,8 @@ extern void manage_fork_fds(int close_all);
extern int continue_via_systemd(char *devnm, char *service_name, char *prefix);
extern void ident_init(struct mddev_ident *ident);
extern mdadm_status_t ident_set_devname(struct mddev_ident *ident, const char *devname);
extern mdadm_status_t ident_set_name(struct mddev_ident *ident, const char *name);
extern int parse_auto(char *str, char *msg, int config);
extern struct mddev_ident *conf_get_ident(char *dev);
@ -1646,11 +1655,10 @@ extern int conf_get_monitor_delay(void);
extern char *conf_line(FILE *file);
extern char *conf_word(FILE *file, int allow_key);
extern void print_quoted(char *str);
extern void print_escape(char *str);
extern int use_udev(void);
extern unsigned long GCD(unsigned long a, unsigned long b);
extern int conf_name_is_free(char *name);
extern bool is_devname_ignore(char *devname);
extern bool is_devname_ignore(const char *devname);
extern bool is_devname_md_numbered(const char *devname);
extern bool is_devname_md_d_numbered(const char *devname);
extern int conf_verify_devnames(struct mddev_ident *array_list);
@ -2005,11 +2013,6 @@ enum r0layout {
/* And another special number needed for --data_offset=variable */
#define VARIABLE_OFFSET 3
/**
* 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

View file

@ -1975,7 +1975,6 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info, char *m
info->array.ctime = DECADE + __be32_to_cpu(*cptr);
info->array.chunk_size = 0;
info->container_enough = 1;
info->disk.major = 0;
info->disk.minor = 0;
@ -1984,12 +1983,14 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info, char *m
info->disk.number = be32_to_cpu(ddf->dlist->disk.refnum);
info->disk.raid_disk = find_phys(ddf, ddf->dlist->disk.refnum);
if (info->disk.raid_disk < 0)
return;
info->data_offset = be64_to_cpu(ddf->phys->
entries[info->disk.raid_disk].
config_size);
info->component_size = ddf->dlist->size - info->data_offset;
if (info->disk.raid_disk >= 0)
pde = ddf->phys->entries + info->disk.raid_disk;
pde = ddf->phys->entries + info->disk.raid_disk;
if (pde &&
!(be16_to_cpu(pde->state) & DDF_Failed) &&
!(be16_to_cpu(pde->state) & DDF_Missing))

View file

@ -3806,7 +3806,6 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
struct intel_super *super = st->sb;
struct imsm_disk *disk;
int map_disks = info->array.raid_disks;
int max_enough = -1;
int i;
struct imsm_super *mpb;
@ -3848,12 +3847,9 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
for (i = 0; i < mpb->num_raid_devs; i++) {
struct imsm_dev *dev = get_imsm_dev(super, i);
int failed, enough, j, missing = 0;
int j = 0;
struct imsm_map *map;
__u8 state;
failed = imsm_count_failed(super, dev, MAP_0);
state = imsm_check_degraded(super, dev, failed, MAP_0);
map = get_imsm_map(dev, MAP_0);
/* any newly missing disks?
@ -3868,36 +3864,10 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
if (!(ord & IMSM_ORD_REBUILD) &&
get_imsm_missing(super, idx)) {
missing = 1;
break;
}
}
if (state == IMSM_T_STATE_FAILED)
enough = -1;
else if (state == IMSM_T_STATE_DEGRADED &&
(state != map->map_state || missing))
enough = 0;
else /* we're normal, or already degraded */
enough = 1;
if (is_gen_migration(dev) && missing) {
/* during general migration we need all disks
* that process is running on.
* No new missing disk is allowed.
*/
max_enough = -1;
enough = -1;
/* no more checks necessary
*/
break;
}
/* in the missing/failed disk case check to see
* if at least one array is runnable
*/
max_enough = max(max_enough, enough);
}
dprintf("enough: %d\n", max_enough);
info->container_enough = max_enough;
if (super->disks) {
__u32 reserved = imsm_reserved_sectors(super, super->disks);
@ -5561,40 +5531,37 @@ static void imsm_update_version_info(struct intel_super *super)
}
}
static int check_name(struct intel_super *super, char *name, int quiet)
/**
* imsm_check_name() - check imsm naming criteria.
* @super: &intel_super pointer, not NULL.
* @name: name to check.
* @verbose: verbose level.
*
* Name must be no longer than &MAX_RAID_SERIAL_LEN and must be unique across volumes.
*
* Returns: &true if @name matches, &false otherwise.
*/
static bool imsm_is_name_allowed(struct intel_super *super, const char * const name,
const int verbose)
{
struct imsm_super *mpb = super->anchor;
char *reason = NULL;
char *start = name;
size_t len = strlen(name);
int i;
if (len > 0) {
while (isspace(start[len - 1]))
start[--len] = 0;
while (*start && isspace(*start))
++start, --len;
memmove(name, start, len + 1);
if (is_string_lq(name, MAX_RAID_SERIAL_LEN + 1) == false) {
pr_vrb("imsm: Name \"%s\" is too long\n", name);
return false;
}
if (len > MAX_RAID_SERIAL_LEN)
reason = "must be 16 characters or less";
else if (len == 0)
reason = "must be a non-empty string";
for (i = 0; i < mpb->num_raid_devs; i++) {
struct imsm_dev *dev = get_imsm_dev(super, i);
if (strncmp((char *) dev->volume, name, MAX_RAID_SERIAL_LEN) == 0) {
reason = "already exists";
break;
pr_vrb("imsm: Name \"%s\" already exists\n", name);
return false;
}
}
if (reason && !quiet)
pr_err("imsm volume name %s\n", reason);
return !reason;
return true;
}
static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
@ -5689,8 +5656,9 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
}
}
if (!check_name(super, name, 0))
if (imsm_is_name_allowed(super, name, 1) == false)
return 0;
dv = xmalloc(sizeof(*dv));
dev = xcalloc(1, sizeof(*dev) + sizeof(__u32) * (info->raid_disks - 1));
/*
@ -8018,7 +7986,7 @@ static int update_subarray_imsm(struct supertype *st, char *subarray,
char *ep;
int vol;
if (!check_name(super, name, 0))
if (imsm_is_name_allowed(super, name, 1) == false)
return 2;
vol = strtoul(subarray, &ep, 10);
@ -10345,7 +10313,8 @@ 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 || !check_name(super, name, 1)) {
if (a || !dev || imsm_is_name_allowed(super, name, 0) == false) {
dprintf("failed to rename subarray-%d\n", target);
break;
}

View file

@ -1967,6 +1967,14 @@ fail_to_write:
return 1;
}
static bool has_raid0_layout(struct mdp_superblock_1 *sb)
{
if (sb->level == 0 && sb->layout != 0)
return true;
else
return false;
}
static int write_init_super1(struct supertype *st)
{
struct mdp_superblock_1 *sb = st->sb;
@ -1978,12 +1986,17 @@ static int write_init_super1(struct supertype *st)
unsigned long long sb_offset;
unsigned long long data_offset;
long bm_offset;
int raid0_need_layout = 0;
bool raid0_need_layout = false;
/* Since linux kernel v5.4, raid0 always has a layout */
if (has_raid0_layout(sb) && get_linux_version() >= 5004000)
raid0_need_layout = true;
for (di = st->info; di; di = di->next) {
if (di->disk.state & (1 << MD_DISK_JOURNAL))
sb->feature_map |= __cpu_to_le32(MD_FEATURE_JOURNAL);
if (sb->level == 0 && sb->layout != 0) {
if (has_raid0_layout(sb) && !raid0_need_layout) {
struct devinfo *di2 = st->info;
unsigned long long s1, s2;
s1 = di->dev_size;
@ -1995,7 +2008,7 @@ static int write_init_super1(struct supertype *st)
s2 -= di2->data_offset;
s2 /= __le32_to_cpu(sb->chunksize);
if (s1 != s2)
raid0_need_layout = 1;
raid0_need_layout = true;
}
}

8
test
View file

@ -107,8 +107,12 @@ do_test() {
echo -ne "$_script... "
if ( set -ex ; . $_script ) &> $targetdir/log
then
dmesg | grep -iq "error\|call trace\|segfault" &&
die "dmesg prints errors when testing $_basename!"
if [ -f "${_script}.inject_error" ]; then
echo "dmesg checking is skipped because test inject error"
else
dmesg | grep -iq "error\|call trace\|segfault" &&
die "dmesg prints errors when testing $_basename!"
fi
echo "succeeded"
_fail=0
else

107
tests/00confnames Normal file
View file

@ -0,0 +1,107 @@
set -x -e
. tests/templates/names_template
# Test how <devname> and <name> from config are handled during Incremental assemblation.
# 1-6 <devnode> only tests (no <name> in config).
# 6-10 <devname> and <name> combinations are tested.
# 11-13 corner cases.
names_create "/dev/md/name"
local _UUID="$(mdadm -D --export /dev/md127 | grep MD_UUID | cut -d'=' -f2)"
[[ "$_UUID" == "" ]] && echo "Cannot obtain UUID for $DEVNODE_NAME" && exit 1
# 1. <devname> definition consistent with metadata name.
names_make_conf $_UUID "/dev/md/name" "empty" $config
mdadm -S "/dev/md127"
mdadm -I $dev0 --config=$config
names_verify "/dev/md127" "name" "name"
mdadm -S "/dev/md127"
# 2. Same as 1, but use short name form of <devname>.
names_make_conf $_UUID "name" "empty" $config
mdadm -I $dev0 --config=$config
names_verify "/dev/md127" "name" "name"
mdadm -S "/dev/md127"
# 3. Same as 1, but use different <devname> than metadata provides.
names_make_conf $_UUID "/dev/md/other" "empty" $config
mdadm -I $dev0 --config=$config
names_verify "/dev/md127" "other" "name"
mdadm -S "/dev/md127"
# 4. Same as 3, but use short name form of <devname>.
names_make_conf $_UUID "other" "empty" $config
mdadm -I $dev0 --config=$config
names_verify "/dev/md127" "other" "name"
mdadm -S "/dev/md127"
# 5. Force particular node creation by setting <devname> to /dev/mdX. Link is not created in this
# case.
names_make_conf $_UUID "/dev/md4" "empty" $config
mdadm -I $dev0 --config=$config
names_verify "/dev/md4" "empty" "name"
mdadm -S "/dev/md4"
# 6. <devname> set to /dev/mdX, <name> same as in metadata.
# Metadata name and default node used - controversial. Current behavior documented.
names_make_conf $_UUID "/dev/md22" "name" $config
mdadm -I $dev0 --config=$config
names_verify "/dev/md127" "name" "name"
mdadm -S "/dev/md127"
# 7. <devname> set to /dev/mdX, <name> different than in metadata.
# Metadata name and default node used - controversial. Current behavior documented.
names_make_conf $_UUID "/dev/md8" "other" $config
mdadm -I $dev0 --config=$config
names_verify "/dev/md127" "name" "name"
mdadm -S "/dev/md127"
# 8. Both <devname> and <name> different than in metadata.
# Metadata name and default node used - controversial. Current behavior documented.
names_make_conf $_UUID "devnode" "other_name" $config
mdadm -I $dev0 --config=$config
names_verify "/dev/md127" "name" "name"
mdadm -S "/dev/md127"
# 9. <devname> set to metadata name, <name> different than in metadata.
# Metadata name and default node used - controversial. Current behavior documented.
names_make_conf $_UUID "name" "other_name" $config
mdadm -I $dev0 --config=$config
names_verify "/dev/md127" "name" "name"
mdadm -S "/dev/md127"
# 10. Bad <devname> set, no <name>.
# Metadata name and default node used - expected.
names_make_conf $_UUID "/im/bad/devname" "empty" $config
mdadm -I $dev0 --config=$config
names_verify "/dev/md127" "name" "name"
mdadm -S "/dev/md127"
# 11. <devname> with some special symbols and locales, no <name>.
# <devname> should be ignored.
names_make_conf $_UUID "tźż-\.,<>st+-" "empty" $config
mdadm -I $dev0 --config=$config
names_verify "/dev/md127" "name" "name"
mdadm -S "/dev/md127"
# 12. No <devname> and <name> set.
# Metadata name and default node used - expected.
names_make_conf $_UUID "empty" "empty" $config
mdadm -I $dev0 --config=$config
names_verify "/dev/md127" "name" "name"
mdadm -S "/dev/md127"
# 13. No <devname>, <name> set to /dev/mdX.
# Entry should be ignored, it is not ignored but result is good anyway.
names_make_conf $_UUID "empty" "/dev/md12" $config
mdadm -I $dev0 --config=$config
names_verify "/dev/md127" "name" "name"
mdadm -S "/dev/md127"
# 13. No <devname>, <name> with special symbols and locales.
# Entry should be ignored, it is not ignored but result is good anyway.
names_make_conf $_UUID "empty" "./\śćń#&" $config
mdadm -I $dev0 --config=$config
names_verify "/dev/md127" "name" "name"
mdadm -S "/dev/md127"

View file

@ -1,93 +1,44 @@
set -x -e
. tests/templates/names_template
# 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"
names_create "/dev/md/name"
names_verify "/dev/md127" "name" "name"
mdadm -S "/dev/md127"
_create "name"
_verify "/dev/md127" "name" "name"
names_create "name"
names_verify "/dev/md127" "name" "name"
mdadm -S "/dev/md127"
# Use 'mdX' as name.
_create "/dev/md/md0"
_verify "/dev/md127" "md0" "md0"
names_create "/dev/md/md0"
names_verify "/dev/md127" "md0" "md0"
mdadm -S "/dev/md127"
_create "md0"
_verify "/dev/md127" "md0" "md0"
names_create "md0"
names_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"
names_create "/dev/md/devnode" "name"
names_verify "/dev/md127" "devnode" "name"
mdadm -S "/dev/md127"
_create "devnode" "name"
_verify "/dev/md127" "devnode" "name"
names_create "devnode" "name"
names_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"
names_create "/dev/md0"
names_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"
names_create "/dev/md0" "name"
names_verify "/dev/md0" "empty" "name"
mdadm -S "/dev/md0"
# Devnode is a special ignore keyword. Should be rejected.
names_create "<ignore>" "name", "true"

View file

@ -3,8 +3,8 @@ set -x
# create an array with a name
mdadm -CR $md0 -l0 -n2 --metadata=1 --name="Fred" $dev0 $dev1
mdadm -E $dev0 | grep 'Name : [^:]*:Fred ' > /dev/null || exit 1
mdadm -D $md0 | grep 'Name : [^:]*:Fred ' > /dev/null || exit 1
mdadm -E $dev0 | grep 'Name : Fred' > /dev/null || exit 1
mdadm -D $md0 | grep 'Name : Fred' > /dev/null || exit 1
mdadm -S $md0
mdadm -A $md0 --name="Fred" $devlist

34
tests/23rdev-lifetime Normal file
View file

@ -0,0 +1,34 @@
devname=${dev0##*/}
devt=`cat /sys/block/$devname/dev`
pid=""
runtime=2
clean_up_test() {
pill -9 $pid
echo clear > /sys/block/md0/md/array_state
}
trap 'clean_up_test' EXIT
add_by_sysfs() {
while true; do
echo $devt > /sys/block/md0/md/new_dev
done
}
remove_by_sysfs(){
while true; do
echo remove > /sys/block/md0/md/dev-${devname}/state
done
}
echo md0 > /sys/module/md_mod/parameters/new_array || die "create md0 failed"
add_by_sysfs &
pid="$pid $!"
remove_by_sysfs &
pid="$pid $!"
sleep $runtime
exit 0

88
tests/24raid10deadlock Normal file
View file

@ -0,0 +1,88 @@
devs="$dev0 $dev1 $dev2 $dev3"
runtime=120
pid=""
action_pid=""
set_up_injection()
{
echo -1 > /sys/kernel/debug/fail_make_request/times
echo 1 > /sys/kernel/debug/fail_make_request/probability
echo 0 > /sys/kernel/debug/fail_make_request/verbose
echo 1 > /sys/block/${1##*/}/make-it-fail
}
clean_up_injection()
{
echo 0 > /sys/block/${1##*/}/make-it-fail
echo 0 > /sys/kernel/debug/fail_make_request/times
echo 0 > /sys/kernel/debug/fail_make_request/probability
echo 2 > /sys/kernel/debug/fail_make_request/verbose
}
test_rdev()
{
while true; do
mdadm -f $md0 $1 &> /dev/null
mdadm -r $md0 $1 &> /dev/null
mdadm --zero-superblock $1 &> /dev/null
mdadm -a $md0 $1 &> /dev/null
sleep $2
done
}
test_write_action()
{
while true; do
echo frozen > /sys/block/md0/md/sync_action
echo idle > /sys/block/md0/md/sync_action
sleep 0.1
done
}
set_up_test()
{
fio -h &> /dev/null || die "fio not found"
# create a simple raid10
mdadm -Cv -R -n 4 -l10 $md0 $devs || die "create raid10 failed"
}
clean_up_test()
{
clean_up_injection $dev0
pkill -9 fio
kill -9 $pid
kill -9 $action_pid
sleep 1
if ps $action_pid | tail -1 | awk '{print $3}' | grep D; then
die "thread that is writing sysfs is stuck in D state, deadlock is triggered"
fi
mdadm -S $md0
}
cat /sys/kernel/debug/fail_make_request/times || die "fault injection is not enabled"
trap 'clean_up_test' EXIT
set_up_test || die "set up test failed"
# backgroup io pressure
fio -filename=$md0 -rw=randwrite -direct=1 -name=test -bs=4k -numjobs=16 -iodepth=16 &
# trigger add/remove device by io failure
set_up_injection $dev0
test_rdev $dev0 2 &
pid="$pid $!"
# add/remove device directly
test_rdev $dev3 10 &
pid="$pid $!"
test_write_action &
action_pid="$!"
sleep $runtime
exit 0

View file

58
tests/24raid456deadlock Normal file
View file

@ -0,0 +1,58 @@
devs="$dev0 $dev1 $dev2 $dev3 $dev4 $dev5"
runtime=120
pid=""
old=`cat /proc/sys/vm/dirty_background_ratio`
test_write_action()
{
while true; do
echo check > /sys/block/md0/md/sync_action &> /dev/null
sleep 0.1
echo idle > /sys/block/md0/md/sync_action &> /dev/null
done
}
test_write_back()
{
fio -filename=$md0 -bs=4k -rw=write -numjobs=1 -name=test \
-time_based -runtime=$runtime &> /dev/null
}
set_up_test()
{
fio -h &> /dev/null || die "fio not found"
# create a simple raid6
mdadm -Cv -R -n 6 -l6 $md0 $devs --assume-clean || die "create raid6 failed"
# trigger dirty pages write back
echo 0 > /proc/sys/vm/dirty_background_ratio
}
clean_up_test()
{
echo $old > /proc/sys/vm/dirty_background_ratio
pkill -9 fio
kill -9 $pid
sleep 1
if ps $pid | tail -1 | awk '{print $3}' | grep D; then
die "thread that is writing sysfs is stuck in D state, deadlock is triggered"
fi
mdadm -S $md0
}
trap 'clean_up_test' EXIT
set_up_test || die "set up test failed"
test_write_back &
test_write_action &
pid="$!"
sleep $runtime
exit 0

View file

@ -0,0 +1,33 @@
devs="$dev0 $dev1 $dev2"
set_up_test()
{
mdadm -Cv -R -n 3 -l5 $md0 $devs --assume-clean --size=50M || die "create array failed"
mdadm -a $md0 $dev3 $dev4 || die "failed to bind new disk to array"
echo 1000 > /sys/block/md0/md/sync_speed_max
}
clean_up_test()
{
mdadm -S $md0
}
trap 'clean_up_test' EXIT
set_up_test || die "set up test failed"
# trigger reshape
mdadm --grow -l 6 $md0
sleep 1
# set up replacement
echo frozen > /sys/block/md0/md/sync_action
echo want_replacement > /sys/block/md0/md/rd0/state
echo reshape > /sys/block/md0/md/sync_action
sleep 1
# reassemeble array
mdadm -S $md0 || die "can't stop array"
mdadm --assemble $md0 $devs $dev3 $dev4 || die "can't assemble array"
exit 0

View file

@ -0,0 +1,35 @@
devs="$dev0 $dev1 $dev2"
set_up_test()
{
mdadm -Cv -R -n 3 -l5 $md0 $devs --size=50M || die "create array failed"
mdadm -a $md0 $dev3 || die "failed to bind new disk to array"
mkfs.xfs -f $md0 || die "mkfs failed"
xfs_ncheck $md0 || die "check fs failed"
}
clean_up_test()
{
mdadm -S $md0
}
trap 'clean_up_test' EXIT
set_up_test || die "set up test failed"
# trigger reshape
echo 1000 > /sys/block/md0/md/sync_speed_max
mdadm --grow -l 6 $md0
sleep 1
# stop and start reshape
echo frozen > /sys/block/md0/md/sync_action
echo system > /sys/block/md0/md/sync_speed_max
echo reshape > /sys/block/md0/md/sync_action
mdadm -W $md0
# check if data is corrupted
xfs_ncheck $md0 || die "data is corrupted after reshape"
exit 0

View file

@ -0,0 +1,34 @@
devs="$dev0 $dev1 $dev2"
set_up_test()
{
mdadm -Cv -R -n 3 -l5 $md0 $devs --size=50M || die "create array failed"
mdadm -a $md0 $dev3 || die "failed to bind new disk to array"
echo 1000 > /sys/block/md0/md/sync_speed_max
}
clean_up_test()
{
echo idle > /sys/block/md0/md/sync_action
mdadm -S $md0
}
trap 'clean_up_test' EXIT
set_up_test || die "set up test failed"
# trigger reshape
mdadm --grow -l 6 $md0
sleep 1
# stop reshape
echo frozen > /sys/block/md0/md/sync_action
# read accross reshape
dd if=$md0 of=/dev/NULL bs=1m count=100 iflag=direct &> /dev/null &
sleep 2
# suspend array
echo 1 > /sys/block/md0/md/suspend_lo
exit 0

View file

@ -0,0 +1,32 @@
devs="$dev0 $dev1 $dev2"
set_up_test()
{
mdadm -Cv -R -n 3 -l5 $md0 $devs --assume-clean --size=50M || die "create array failed"
mdadm -a $md0 $dev3 $dev4 || die "failed to bind new disk to array"
echo 1000 > /sys/block/md0/md/sync_speed_max
}
clean_up_test()
{
mdadm -S $md0
}
trap 'clean_up_test' EXIT
set_up_test || die "set up test failed"
# set up replacement
echo want_replacement > /sys/block/md0/md/rd0/state
sleep 1
# trigger reshape
echo frozen > /sys/block/md0/md/sync_action
mdadm --grow -l 6 $md0
sleep 1
# reassemeble array
mdadm -S $md0 || die "can't stop array"
mdadm --assemble $md0 $devs $dev3 $dev4 || die "can't assemble array"
exit 0

View file

@ -170,7 +170,6 @@ do_setup() {
dd if=/dev/zero of=$targetdir/mdtest$d count=$sz bs=1K > /dev/null 2>&1
# make sure udev doesn't touch
mdadm --zero $targetdir/mdtest$d 2> /dev/null
[ -b /dev/loop$d ] || mknod /dev/loop$d b 7 $d
if [ $d -eq 7 ]
then
losetup /dev/loop$d $targetdir/mdtest6 # for multipath use

View file

@ -0,0 +1,80 @@
# NAME is optional. Testing with native 1.2 superblock.
function names_create() {
local DEVNAME=$1
local NAME=$2
local NEG_TEST=$3
if [[ -z "$NAME" ]]; then
mdadm -CR "$DEVNAME" -l0 -n 1 $dev0 --force
else
mdadm -CR "$DEVNAME" --name="$NAME" --metadata=1.2 -l0 -n 1 $dev0 --force
fi
if [[ "$NEG_TEST" == "true" ]]; then
[[ "$?" == "0" ]] && return 0
echo "Negative verification failed"
exit 1
fi
if [[ "$?" != "0" ]]; then
echo "Cannot create device."
exit 1
fi
}
# Three properties to check:
# - devnode name
# - link in /dev/md/ (MD_DEVNAME property from --detail --export)
# - name in metadata (MD_NAME property from --detail --export)- that works only with 1.2 sb.
function names_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"
fi
if [[ "$RES" != "$EXPECTED" ]]; then
echo "$RES doesn't match $EXPECTED."
exit 1
fi
local RES="$(mdadm -D --export $DEVNODE_NAME | 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
}
# Generate ARRAYLINE for tested array.
names_make_conf() {
local UUID="$1"
local WANTED_DEVNAME="$2"
local WANTED_NAME="$3"
local CONF="$4"
local LINE="ARRAY metadata=1.2 UUID=$UUID"
if [[ "$WANTED_DEVNAME" != "empty" ]]; then
LINE="$LINE $WANTED_DEVNAME"
fi
if [[ "$WANTED_NAME" != "empty" ]]; then
LINE="$LINE name=$WANTED_NAME"
fi
echo $LINE > $CONF
}