--- libmultipath/discovery.c | 3 + libmultipath/wwids.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++ libmultipath/wwids.h | 1 multipath/main.c | 26 ++++++++++++-- multipath/multipath.8 | 5 ++ 5 files changed, 115 insertions(+), 6 deletions(-) Index: multipath-tools-130222/libmultipath/discovery.c =================================================================== --- multipath-tools-130222.orig/libmultipath/discovery.c +++ multipath-tools-130222/libmultipath/discovery.c @@ -53,7 +53,8 @@ store_pathinfo (vector pathvec, vector h goto out; } pp->udev = udev_device_ref(udevice); - err = pathinfo(pp, hwtable, flag | DI_BLACKLIST); + err = pathinfo(pp, hwtable, + (conf->dry_run == 3)? flag : (flag | DI_BLACKLIST)); if (err) goto out; Index: multipath-tools-130222/libmultipath/wwids.c =================================================================== --- multipath-tools-130222.orig/libmultipath/wwids.c +++ multipath-tools-130222/libmultipath/wwids.c @@ -82,6 +82,92 @@ write_out_wwid(int fd, char *wwid) { } int +do_remove_wwid(int fd, char *str) { + char buf[4097]; + char *ptr; + off_t start = 0; + int bytes; + + while (1) { + if (lseek(fd, start, SEEK_SET) < 0) { + condlog(0, "wwid file read lseek failed : %s", + strerror(errno)); + return -1; + } + bytes = read(fd, buf, 4096); + if (bytes < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + condlog(0, "failed to read from wwids file : %s", + strerror(errno)); + return -1; + } + if (!bytes) /* didn't find wwid to remove */ + return 1; + buf[bytes] = '\0'; + ptr = strstr(buf, str); + if (ptr != NULL) { + condlog(3, "found '%s'", str); + if (lseek(fd, start + (ptr - buf), SEEK_SET) < 0) { + condlog(0, "write lseek failed : %s", + strerror(errno)); + return -1; + } + while (1) { + if (write(fd, "#", 1) < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + condlog(0, "failed to write to wwids file : %s", strerror(errno)); + return -1; + } + return 0; + } + } + ptr = strrchr(buf, '\n'); + if (ptr == NULL) { /* shouldn't happen, assume it is EOF */ + condlog(4, "couldn't find newline, assuming end of file"); + return 1; + } + start = start + (ptr - buf) + 1; + } +} + + +int +remove_wwid(char *wwid) { + int fd, len, can_write; + char *str; + int ret = -1; + + len = strlen(wwid) + 4; /* two slashes the newline and a zero byte */ + str = malloc(len); + if (str == NULL) { + condlog(0, "can't allocate memory to remove wwid : %s", + strerror(errno)); + return -1; + } + if (snprintf(str, len, "/%s/\n", wwid) >= len) { + condlog(0, "string overflow trying to remove wwid"); + goto out; + } + condlog(3, "removing line '%s' from wwids file", str); + fd = open_file(conf->wwids_file, &can_write, WWIDS_FILE_HEADER); + if (fd < 0) + goto out; + if (!can_write) { + condlog(0, "cannot remove wwid. wwids file is read-only"); + goto out_file; + } + ret = do_remove_wwid(fd, str); + +out_file: + close(fd); +out: + free(str); + return ret; +} + +int check_wwids_file(char *wwid, int write_wwid) { int fd, can_write, found, ret; Index: multipath-tools-130222/libmultipath/wwids.h =================================================================== --- multipath-tools-130222.orig/libmultipath/wwids.h +++ multipath-tools-130222/libmultipath/wwids.h @@ -15,5 +15,6 @@ int should_multipath(struct path *pp, vector pathvec); int remember_wwid(char *wwid); int check_wwids_file(char *wwid, int write_wwid); +int remove_wwid(char *wwid); #endif /* _WWIDS_H */ Index: multipath-tools-130222/multipath/main.c =================================================================== --- multipath-tools-130222.orig/multipath/main.c +++ multipath-tools-130222/multipath/main.c @@ -83,7 +83,7 @@ usage (char * progname) { fprintf (stderr, VERSION_STRING); fprintf (stderr, "Usage:\n"); - fprintf (stderr, " %s [-c] [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname); + fprintf (stderr, " %s [-c|-w] [-d] [-r] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname); fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname); fprintf (stderr, " %s -F [-v lvl]\n", progname); fprintf (stderr, " %s -t\n", progname); @@ -104,6 +104,7 @@ usage (char * progname) " -B treat the bindings file as read only\n" \ " -p policy failover|multibus|group_by_serial|group_by_prio\n" \ " -b fil bindings file location\n" \ + " -w remove a device from the wwids file\n" \ " -p pol force all maps to specified path grouping policy :\n" \ " . failover one path per priority group\n" \ " . multibus all paths in one priority group\n" \ @@ -212,7 +213,6 @@ get_dm_mpvec (vector curmp, vector pathv if (!conf->dry_run) reinstate_paths(mpp); - remember_wwid(mpp->wwid); } return 0; } @@ -262,7 +262,7 @@ configure (void) /* * if we have a blacklisted device parameter, exit early */ - if (dev && conf->dev_type == DEV_DEVNODE && + if (dev && conf->dev_type == DEV_DEVNODE && conf->dry_run != 3 && (filter_devnode(conf->blist_devnode, conf->elist_devnode, dev) > 0)) { if (conf->dry_run == 2) @@ -284,6 +284,17 @@ configure (void) condlog(3, "scope is nul"); goto out; } + if (conf->dry_run == 3) { + r = remove_wwid(refwwid); + if (r == 0) + printf("wwid '%s' removed\n", refwwid); + else if (r == 1) { + printf("wwid '%s' not in wwids file\n", + refwwid); + r = 0; + } + goto out; + } condlog(3, "scope limited to %s", refwwid); if (conf->dry_run == 2) { if (check_wwids_file(refwwid, 0) == 0){ @@ -439,7 +450,7 @@ main (int argc, char *argv[]) if (dm_prereq()) exit(1); - while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:Brtq")) != EOF ) { + while ((arg = getopt(argc, argv, ":dchl::FfM:v:p:b:Brtqw")) != EOF ) { switch(arg) { case 1: printf("optarg : %s\n",optarg); break; @@ -504,6 +515,9 @@ main (int argc, char *argv[]) case 'h': usage(argv[0]); exit(0); + case 'w': + conf->dry_run = 3; + break; case ':': fprintf(stderr, "Missing option argument\n"); usage(argv[0]); @@ -555,6 +569,10 @@ main (int argc, char *argv[]) condlog(0, "the -c option requires a path to check"); goto out; } + if (conf->dry_run == 3 && !conf->dev) { + condlog(0, "the -w option requires a device"); + goto out; + } if (conf->remove == FLUSH_ONE) { if (conf->dev_type == DEV_DEVMAP) { r = dm_suspend_and_flush_map(conf->dev); Index: multipath-tools-130222/multipath/multipath.8 =================================================================== --- multipath-tools-130222.orig/multipath/multipath.8 +++ multipath-tools-130222/multipath/multipath.8 @@ -8,7 +8,7 @@ multipath \- Device mapper target autoco .RB [\| \-b\ \c .IR bindings_file \|] .RB [\| \-d \|] -.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r \|] +.RB [\| \-h | \-l | \-ll | \-f | \-t | \-F | \-B | \-c | \-q | \|-r | \-w \|] .RB [\| \-p\ \c .BR failover | multibus | group_by_serial | group_by_prio | group_by_node_name \|] .RB [\| device \|] @@ -68,6 +68,9 @@ check if a block device should be a path .B \-q allow device tables with queue_if_no_path when multipathd is not running .TP +.B \-w +remove the wwid for the specified device from the wwids file +.TP .BI \-p " policy" force new maps to use the specified policy: .RS 1.2i