Add --prefer option for --detail and --monitor

Both --detail and --monitor can report the names of member
devices on an array, and do so by searching /dev and finding
the shortest name that matches.

If
   --prefer=foo
is given, they will instead prefer a name that contain /foo/.
So
   mdadm --detail /dev/md0 --prefer=by-path

will list the component devices via their /dev/disk/by-path/xxx
names.

Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
NeilBrown 2012-04-18 11:00:07 +10:00
parent 480f356641
commit c2ecf5f61a
7 changed files with 68 additions and 20 deletions

View File

@ -27,7 +27,7 @@
#include "md_u.h"
#include <dirent.h>
int Detail(char *dev, int brief, int export, int test, char *homehost)
int Detail(char *dev, int brief, int export, int test, char *homehost, char *prefer)
{
/*
* Print out details for an md array by using
@ -105,7 +105,7 @@ int Detail(char *dev, int brief, int export, int test, char *homehost)
int dn = st->container_dev;
member = subarray;
container = map_dev(dev2major(dn), dev2minor(dn), 1);
container = map_dev_preferred(dev2major(dn), dev2minor(dn), 1, prefer);
}
/* try to load a superblock */
@ -491,8 +491,9 @@ This is pretty boring
vbuf[10+nlen] != '/')
continue;
dn = devname2devnum(de->d_name);
printf(" %s", map_dev(dev2major(dn),
dev2minor(dn), 1));
printf(" %s", map_dev_preferred(
dev2major(dn),
dev2minor(dn), 1, prefer));
}
if (dir)
closedir(dir);
@ -558,7 +559,7 @@ This is pretty boring
if (test && d < array.raid_disks
&& !(disk.state & (1<<MD_DISK_SYNC)))
rv |= 1;
if ((dv=map_dev(disk.major, disk.minor, 0))) {
if ((dv=map_dev_preferred(disk.major, disk.minor, 0, prefer))) {
if (brief) {
if (devices) {
devices = realloc(devices,

View File

@ -69,7 +69,7 @@ static int check_one_sharer(int scan);
static void alert(char *event, char *dev, 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);
int increments, char *prefer);
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);
@ -79,7 +79,7 @@ int Monitor(struct mddev_dev *devlist,
char *mailaddr, char *alert_cmd,
int period, int daemonise, int scan, int oneshot,
int dosyslog, int test, char *pidfile, int increments,
int share)
int share, char *prefer)
{
/*
* Every few seconds, scan every md device looking for changes
@ -221,7 +221,8 @@ int Monitor(struct mddev_dev *devlist,
mdstat = mdstat_read(oneshot?0:1, 0);
for (st=statelist; st; st=st->next)
if (check_array(st, mdstat, test, &info, increments))
if (check_array(st, mdstat, test, &info,
increments, prefer))
anydegraded = 1;
/* now check if there are any new devices found in mdstat */
@ -445,7 +446,7 @@ static void alert(char *event, char *dev, char *disc, struct alert_info *info)
static int check_array(struct state *st, struct mdstat_ent *mdstat,
int test, struct alert_info *ainfo,
int increments)
int increments, char *prefer)
{
/* Update the state 'st' to reflect any changes shown in mdstat,
* or found by directly examining the array, and return
@ -617,7 +618,9 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
disc.major = disc.minor = 0;
} else if (info[i].major || info[i].minor) {
newstate = info[i].state;
dv = map_dev(info[i].major, info[i].minor, 1);
dv = map_dev_preferred(
info[i].major, info[i].minor, 1,
prefer);
disc.state = newstate;
disc.major = info[i].major;
disc.minor = info[i].minor;
@ -629,8 +632,9 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
disc.major = disc.minor = 0;
}
if (dv == NULL && st->devid[i])
dv = map_dev(major(st->devid[i]),
minor(st->devid[i]), 1);
dv = map_dev_preferred(
major(st->devid[i]),
minor(st->devid[i]), 1, prefer);
change = newstate ^ st->devstate[i];
if (st->utime && change && !st->err) {
if (i < array.raid_disks &&

View File

@ -174,6 +174,7 @@ struct option long_options[] = {
{"export", 0, 0, 'Y'},
{"sparc2.2", 0, 0, Sparc22},
{"test", 0, 0, 't'},
{"prefer", 1, 0, Prefer},
/* For Follow/monitor */
{"mail", 1, 0, EMail},

9
lib.c
View File

@ -188,8 +188,11 @@ int nftw(const char *path, int (*han)(const char *name, const struct stat *stb,
* If we find multiple names, choose the shortest.
* If we find a name in /dev/md/, we prefer that.
* This applies only to names for MD devices.
* If 'prefer' is set (normally to e.g. /by-path/)
* then we prefer a name which contains that string.
*/
char *map_dev(int major, int minor, int create)
char *map_dev_preferred(int major, int minor, int create,
char *prefer)
{
struct devmap *p;
char *regular = NULL, *preferred=NULL;
@ -219,7 +222,8 @@ char *map_dev(int major, int minor, int create)
for (p=devlist; p; p=p->next)
if (p->major == major &&
p->minor == minor) {
if (strncmp(p->name, "/dev/md/",8) == 0) {
if (strncmp(p->name, "/dev/md/",8) == 0
|| (prefer && strstr(p->name, prefer))) {
if (preferred == NULL ||
strlen(p->name) < strlen(preferred))
preferred = p->name;
@ -243,6 +247,7 @@ char *map_dev(int major, int minor, int create)
}
/* conf_word gets one word from the conf file.
* if "allow_key", then accept words at the start of a line,
* otherwise stop when such a word is found.

View File

@ -389,6 +389,28 @@ will be allowed to use 'local' names (i.e. not ending in '_' followed
by a digit string). See below under
.BR "Auto Assembly" .
.TP
.B \-\-prefer=
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
given with
.B \-\-prefer
.I mdadm
will prefer a longer name if it contains that component. For example
.B \-\-prefer=by-uuid
will prefer a name in a subdirectory of
.B /dev
called
.BR by-uuid .
This functionality is currently only provided by
.B \-\-detail
and
.BR \-\-monitor .
.SH For create, build, or grow:
.TP

15
mdadm.c
View File

@ -73,6 +73,7 @@ int main(int argc, char *argv[])
int test = 0;
int export = 0;
int assume_clean = 0;
char *prefer = NULL;
char *symlinks = NULL;
int grow_continue = 0;
/* autof indicates whether and how to create device node.
@ -184,6 +185,13 @@ int main(int argc, char *argv[])
__offroot = 1;
continue;
case Prefer:
if (prefer)
free(prefer);
if (asprintf(&prefer, "/%s/", optarg) <= 0)
prefer = NULL;
continue;
case ':':
case '?':
fputs(Usage, stderr);
@ -1498,7 +1506,7 @@ int main(int argc, char *argv[])
if (devmode == 'D')
rv |= Detail(name, v,
export, test,
homehost);
homehost, prefer);
else
rv |= WaitClean(name, -1, v);
put_md_name(name);
@ -1552,7 +1560,7 @@ int main(int argc, char *argv[])
case 'D':
rv |= Detail(dv->devname,
brief?1+verbose:0,
export, test, homehost);
export, test, homehost, prefer);
continue;
case 'K': /* Zero superblock */
if (ss)
@ -1626,7 +1634,8 @@ int main(int argc, char *argv[])
}
rv= Monitor(devlist, mailaddr, program,
delay?delay:60, daemonise, scan, oneshot,
dosyslog, test, pidfile, increments, spare_sharing);
dosyslog, test, pidfile, increments,
spare_sharing, prefer);
break;
case GROW:

12
mdadm.h
View File

@ -322,6 +322,7 @@ enum special_options {
FreezeReshape,
Continue,
OffRootOpt,
Prefer,
};
/* structures read from config file */
@ -532,7 +533,12 @@ extern char *map_num(mapping_t *map, int num);
extern int map_name(mapping_t *map, char *name);
extern mapping_t r5layout[], r6layout[], pers[], modes[], faultylayout[];
extern char *map_dev(int major, int minor, int create);
extern char *map_dev_preferred(int major, int minor, int create,
char *prefer);
static inline char *map_dev(int major, int minor, int create)
{
return map_dev_preferred(major, minor, create, NULL);
}
struct active_array;
struct metadata_update;
@ -1080,7 +1086,7 @@ extern int Create(struct supertype *st, char *mddev,
int runstop, int verbose, int force, int assume_clean,
char *bitmap_file, int bitmap_chunk, int write_behind, int delay, int autof);
extern int Detail(char *dev, int brief, int export, int test, char *homehost);
extern int Detail(char *dev, int brief, int export, int test, char *homehost, char *prefer);
extern int Detail_Platform(struct superswitch *ss, int scan, int verbose);
extern int Query(char *dev);
extern int Examine(struct mddev_dev *devlist, int brief, int export, int scan,
@ -1089,7 +1095,7 @@ extern int Monitor(struct mddev_dev *devlist,
char *mailaddr, char *alert_cmd,
int period, int daemonise, int scan, int oneshot,
int dosyslog, int test, char *pidfile, int increments,
int share);
int share, char *prefer);
extern int Kill(char *dev, struct supertype *st, int force, int quiet, int noexcl);
extern int Kill_subarray(char *dev, char *subarray, int quiet);