From c2ecf5f61aca2d73b7d5a6cb3a26973916d5c0d1 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 18 Apr 2012 11:00:07 +1000 Subject: [PATCH] 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 --- Detail.c | 11 ++++++----- Monitor.c | 18 +++++++++++------- ReadMe.c | 1 + lib.c | 9 +++++++-- mdadm.8.in | 22 ++++++++++++++++++++++ mdadm.c | 15 ++++++++++++--- mdadm.h | 12 +++++++++--- 7 files changed, 68 insertions(+), 20 deletions(-) diff --git a/Detail.c b/Detail.c index 1d7e3a1..ae15846 100644 --- a/Detail.c +++ b/Detail.c @@ -27,7 +27,7 @@ #include "md_u.h" #include -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<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 && diff --git a/ReadMe.c b/ReadMe.c index a60e11b..24c03e0 100644 --- a/ReadMe.c +++ b/ReadMe.c @@ -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}, diff --git a/lib.c b/lib.c index 2739b3d..c04f6a0 100644 --- a/lib.c +++ b/lib.c @@ -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. diff --git a/mdadm.8.in b/mdadm.8.in index bddecd9..fa4d2f3 100644 --- a/mdadm.8.in +++ b/mdadm.8.in @@ -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 diff --git a/mdadm.c b/mdadm.c index 4d4820d..846bc96 100644 --- a/mdadm.c +++ b/mdadm.c @@ -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: diff --git a/mdadm.h b/mdadm.h index 71cef38..e60a706 100644 --- a/mdadm.h +++ b/mdadm.h @@ -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);