2 * Soft: multipath device mapper target autoconfig
4 * Version: $Id: main.h,v 0.0.1 2003/09/18 15:13:38 cvaroqui Exp $
6 * Author: Christophe Varoqui
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 * See the GNU General Public License for more details.
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version
16 * 2 of the License, or (at your option) any later version.
18 * Copyright (c) 2003, 2004, 2005 Christophe Varoqui
19 * Copyright (c) 2005 Benjamin Marzinski, Redhat
20 * Copyright (c) 2005 Kiyoshi Ueda, NEC
21 * Copyright (c) 2005 Patrick Caulfield, Redhat
22 * Copyright (c) 2005 Edward Goggin, EMC
25 #include <sys/types.h>
39 #include <libdevmapper.h>
40 #include "devmapper.h"
45 #include "structs_vec.h"
48 #include "blacklist.h"
49 #include "discovery.h"
51 #include "switchgroup.h"
52 #include "dm-generic.h"
55 #include "configure.h"
56 #include "pgpolicies.h"
61 #include "mpath_cmd.h"
64 #include "time-util.h"
69 struct config *multipath_conf;
71 struct config *get_multipath_config(void)
73 return multipath_conf;
76 void put_multipath_config(void *arg)
82 dump_config (struct config *conf, vector hwes, vector mpvec)
84 char * reply = snprint_config(conf, NULL, hwes, mpvec);
94 void rcu_register_thread_memb(void) {}
96 void rcu_unregister_thread_memb(void) {}
99 filter_pathvec (vector pathvec, char * refwwid)
104 if (!refwwid || !strlen(refwwid))
107 vector_foreach_slot (pathvec, pp, i) {
108 if (strncmp(pp->wwid, refwwid, WWID_SIZE) != 0) {
109 condlog(3, "skip path %s : out of scope", pp->dev);
111 vector_del_slot(pathvec, i);
119 usage (char * progname)
121 fprintf (stderr, VERSION_STRING);
122 fprintf (stderr, "Usage:\n");
123 fprintf (stderr, " %s [-a|-c|-w|-W] [-d] [-r] [-i] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
124 fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [-R num] [dev]\n", progname);
125 fprintf (stderr, " %s -F [-v lvl] [-R num]\n", progname);
126 fprintf (stderr, " %s [-t|-T]\n", progname);
127 fprintf (stderr, " %s -h\n", progname);
131 " -h print this usage text\n"
132 " -l show multipath topology (sysfs and DM info)\n"
133 " -ll show multipath topology (maximum info)\n"
134 " -f flush a multipath device map\n"
135 " -F flush all multipath device maps\n"
136 " -a add a device wwid to the wwids file\n"
137 " -c check if a device should be a path in a multipath device\n"
138 " -C check if a multipath device has usable paths\n"
139 " -q allow queue_if_no_path when multipathd is not running\n"
140 " -d dry run, do not create or update devmaps\n"
141 " -t display the currently used multipathd configuration\n"
142 " -T display the multipathd configuration without builtin defaults\n"
143 " -r force devmap reload\n"
144 " -i ignore wwids file\n"
145 " -B treat the bindings file as read only\n"
146 " -b fil bindings file location\n"
147 " -w remove a device from the wwids file\n"
148 " -W reset the wwids file include only the current devices\n"
149 " -p pol force all maps to specified path grouping policy :\n"
150 " . failover one path per priority group\n"
151 " . multibus all paths in one priority group\n"
152 " . group_by_serial one priority group per serial\n"
153 " . group_by_prio one priority group per priority lvl\n"
154 " . group_by_node_name one priority group per target node\n"
155 " -v lvl verbosity level\n"
157 " . 1 print created devmap names only\n"
158 " . 2 default verbosity\n"
159 " . 3 print debug information\n"
160 " -R num number of times to retry removes of in-use devices\n"
161 " dev action limited to:\n"
162 " . multipath named 'dev' (ex: mpath0) or\n"
163 " . multipath whose wwid is 'dev' (ex: 60051..)\n"
164 " . multipath including the path named 'dev' (ex: /dev/sda)\n"
165 " . multipath including the path with maj:min 'dev' (ex: 8:0)\n"
171 update_paths (struct multipath * mpp, int quick)
174 struct pathgroup * pgp;
181 vector_foreach_slot (mpp->pg, pgp, i) {
185 vector_foreach_slot (pgp->paths, pp, j) {
186 if (!strlen(pp->dev)) {
187 if (devt2devname(pp->dev, FILE_NAME_SIZE,
190 * path is not in sysfs anymore
192 pp->chkrstate = pp->state = PATH_DOWN;
199 conf = get_multipath_config();
200 if (pathinfo(pp, conf, DI_ALL))
201 pp->state = PATH_UNCHECKED;
202 put_multipath_config(conf);
208 if (pp->state == PATH_UNCHECKED ||
209 pp->state == PATH_WILD) {
210 conf = get_multipath_config();
211 if (pathinfo(pp, conf, DI_CHECKER))
212 pp->state = PATH_UNCHECKED;
213 put_multipath_config(conf);
216 if (pp->priority == PRIO_UNDEF) {
217 conf = get_multipath_config();
218 if (pathinfo(pp, conf, DI_PRIO))
219 pp->priority = PRIO_UNDEF;
220 put_multipath_config(conf);
228 get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid)
231 struct multipath * mpp;
232 char params[PARAMS_SIZE], status[PARAMS_SIZE];
234 if (dm_get_maps(curmp))
237 vector_foreach_slot (curmp, mpp, i) {
239 * discard out of scope maps
241 if (refwwid && strlen(refwwid) &&
242 strncmp(mpp->wwid, refwwid, WWID_SIZE)) {
243 condlog(3, "skip map %s: out of scope", mpp->alias);
244 free_multipath(mpp, KEEP_PATHS);
245 vector_del_slot(curmp, i);
250 if (cmd == CMD_VALID_PATH)
253 dm_get_map(mpp->alias, &mpp->size, params);
254 condlog(3, "params = %s", params);
255 dm_get_status(mpp->alias, status);
256 condlog(3, "status = %s", status);
258 disassemble_map(pathvec, params, mpp, 0);
261 * disassemble_map() can add new paths to pathvec.
262 * If not in "fast list mode", we need to fetch information
265 update_paths(mpp, (cmd == CMD_LIST_SHORT));
267 if (cmd == CMD_LIST_LONG)
268 mpp->bestpg = select_path_group(mpp);
270 disassemble_status(status, mpp);
272 if (cmd == CMD_LIST_SHORT ||
273 cmd == CMD_LIST_LONG) {
274 struct config *conf = get_multipath_config();
275 print_multipath_topology(mpp, conf->verbosity);
276 put_multipath_config(conf);
279 if (cmd == CMD_CREATE)
280 reinstate_paths(mpp);
283 if (cmd == CMD_LIST_SHORT || cmd == CMD_LIST_LONG) {
284 struct config *conf = get_multipath_config();
286 print_foreign_topology(conf->verbosity);
287 put_multipath_config(conf);
293 static int check_usable_paths(struct config *conf,
294 const char *devpath, enum devtypes dev_type)
296 struct udev_device *ud = NULL;
297 struct multipath *mpp = NULL;
298 struct pathgroup *pg;
301 vector pathvec = NULL;
302 char params[PARAMS_SIZE], status[PARAMS_SIZE];
306 ud = get_udev_device(devpath, dev_type);
310 devt = udev_device_get_devnum(ud);
311 if (!dm_is_dm_major(major(devt))) {
312 condlog(1, "%s is not a dm device", devpath);
316 mapname = dm_mapname(major(devt), minor(devt));
317 if (mapname == NULL) {
318 condlog(1, "dm device not found: %s", devpath);
322 if (!dm_is_mpath(mapname)) {
323 condlog(1, "%s is not a multipath map", devpath);
327 /* pathvec is needed for disassemble_map */
328 pathvec = vector_alloc();
332 mpp = dm_get_multipath(mapname);
336 dm_get_map(mpp->alias, &mpp->size, params);
337 dm_get_status(mpp->alias, status);
338 disassemble_map(pathvec, params, mpp, 0);
339 disassemble_status(status, mpp);
341 vector_foreach_slot (mpp->pg, pg, i) {
342 vector_foreach_slot (pg->paths, pp, j) {
343 pp->udev = get_udev_device(pp->dev_t, DEV_DEVT);
344 if (pp->udev == NULL)
346 if (pathinfo(pp, conf, DI_SYSFS|DI_NOIO) != PATHINFO_OK)
349 if (pp->state == PATH_UP &&
350 pp->dmstate == PSTATE_ACTIVE) {
351 condlog(3, "%s: path %s is usable",
359 condlog(r == 0 ? 3 : 2, "%s:%s usable paths found",
360 devpath, r == 0 ? "" : " no");
363 free_multipath(mpp, FREE_PATHS);
364 vector_free(pathvec);
366 udev_device_unref(ud);
371 FIND_MULTIPATHS_WAIT_DONE = 0,
372 FIND_MULTIPATHS_WAITING = 1,
373 FIND_MULTIPATHS_ERROR = -1,
374 FIND_MULTIPATHS_NEVER = -2,
377 static const char shm_find_mp_dir[] = MULTIPATH_SHM_BASE "find_multipaths";
378 static void close_fd(void *arg)
384 * find_multipaths_check_timeout(wwid, tmo)
385 * Helper for "find_multipaths smart"
387 * @param[in] pp: path to check / record
388 * @param[in] tmo: configured timeout for this WWID, or value <= 0 for checking
389 * @param[out] until: timestamp until we must wait, CLOCK_REALTIME, if return
390 * value is FIND_MULTIPATHS_WAITING
391 * @returns: FIND_MULTIPATHS_WAIT_DONE, if waiting has finished
392 * @returns: FIND_MULTIPATHS_ERROR, if internal error occurred
393 * @returns: FIND_MULTIPATHS_NEVER, if tmo is 0 and we didn't wait for this
395 * @returns: FIND_MULTIPATHS_WAITING, if timeout hasn't expired
397 static int find_multipaths_check_timeout(const struct path *pp, long tmo,
398 struct timespec *until)
401 struct timespec now, ftimes[2], tdiff;
404 int r, err, retries = 0;
406 clock_gettime(CLOCK_REALTIME, &now);
408 if (snprintf(path, sizeof(path), "%s/%s", shm_find_mp_dir, pp->dev_t)
410 condlog(1, "%s: path name overflow", __func__);
411 return FIND_MULTIPATHS_ERROR;
414 if (ensure_directories_exist(path, 0700)) {
415 condlog(1, "%s: error creating directories", __func__);
416 return FIND_MULTIPATHS_ERROR;
420 fd = open(path, O_RDONLY);
422 pthread_cleanup_push(close_fd, (void *)fd);
426 pthread_cleanup_pop(1);
428 } else if (tmo > 0) {
430 fd = open(path, O_RDWR|O_EXCL|O_CREAT, 0644);
432 if (errno == EEXIST && !retries++)
433 /* We could have raced with another process */
435 condlog(1, "%s: error opening %s: %s",
436 __func__, path, strerror(errno));
437 return FIND_MULTIPATHS_ERROR;
440 pthread_cleanup_push(close_fd, (void *)fd);
442 * We just created the file. Set st_mtim to our desired
445 ftimes[0].tv_sec = 0;
446 ftimes[0].tv_nsec = UTIME_OMIT;
447 ftimes[1].tv_sec = now.tv_sec + tmo;
448 ftimes[1].tv_nsec = now.tv_nsec;
449 if (futimens(fd, ftimes) != 0) {
450 condlog(1, "%s: error in futimens(%s): %s", __func__,
451 path, strerror(errno));
456 pthread_cleanup_pop(1);
458 return FIND_MULTIPATHS_NEVER;
461 condlog(1, "%s: error in fstat for %s: %s", __func__,
462 path, strerror(err));
463 return FIND_MULTIPATHS_ERROR;
466 timespecsub(&st.st_mtim, &now, &tdiff);
468 if (tdiff.tv_sec <= 0)
469 return FIND_MULTIPATHS_WAIT_DONE;
472 return FIND_MULTIPATHS_WAITING;
475 static int print_cmd_valid(int k, const vector pathvec,
478 static const int vals[] = { 1, 0, 2 };
479 int wait = FIND_MULTIPATHS_NEVER;
480 struct timespec until;
483 if (k < 0 || k >= (sizeof(vals) / sizeof(int)))
488 * Caller ensures that pathvec[0] is the path to
491 pp = VECTOR_SLOT(pathvec, 0);
492 select_find_multipaths_timeout(conf, pp);
493 wait = find_multipaths_check_timeout(
494 pp, pp->find_multipaths_timeout, &until);
495 if (wait != FIND_MULTIPATHS_WAITING)
497 } else if (pathvec != NULL && (pp = VECTOR_SLOT(pathvec, 0)))
498 wait = find_multipaths_check_timeout(pp, 0, &until);
499 if (wait == FIND_MULTIPATHS_WAITING)
500 printf("FIND_MULTIPATHS_WAIT_UNTIL=\"%ld.%06ld\"\n",
501 until.tv_sec, until.tv_nsec/1000);
502 else if (wait == FIND_MULTIPATHS_WAIT_DONE)
503 printf("FIND_MULTIPATHS_WAIT_UNTIL=\"0\"\n");
504 printf("DM_MULTIPATH_DEVICE_PATH=\"%d\"\n", vals[k]);
509 * Returns true if this device has been handled before,
510 * and released to systemd.
512 * This must be called before get_refwwid(),
513 * otherwise udev_device_new_from_environment() will have
514 * destroyed environ(7).
516 static bool released_to_systemd(void)
518 static const char dmdp[] = "DM_MULTIPATH_DEVICE_PATH";
519 const char *dm_mp_dev_path = getenv(dmdp);
522 ret = dm_mp_dev_path != NULL && !strcmp(dm_mp_dev_path, "0");
523 condlog(4, "%s: %s=%s -> %d", __func__, dmdp, dm_mp_dev_path, ret);
534 configure (struct config *conf, enum mpath_cmds cmd,
535 enum devtypes dev_type, char *devpath)
538 vector pathvec = NULL;
542 char * refwwid = NULL;
544 bool released = released_to_systemd();
547 * allocate core vectors to store paths and multipaths
549 curmp = vector_alloc();
550 pathvec = vector_alloc();
552 if (!curmp || !pathvec) {
553 condlog(0, "can not allocate memory");
556 vecs.pathvec = pathvec;
559 dev = convert_dev(devpath, (dev_type == DEV_DEVNODE));
562 * if we have a blacklisted device parameter, exit early
564 if (dev && (dev_type == DEV_DEVNODE ||
565 dev_type == DEV_UEVENT) &&
566 cmd != CMD_REMOVE_WWID &&
567 (filter_devnode(conf->blist_devnode,
568 conf->elist_devnode, dev) > 0)) {
573 * scope limiting must be translated into a wwid
574 * failing the translation is fatal (by policy)
577 int failed = get_refwwid(cmd, devpath, dev_type,
580 condlog(4, "%s: failed to get wwid", devpath);
581 if (failed == 2 && cmd == CMD_VALID_PATH)
584 condlog(3, "scope is null");
587 if (cmd == CMD_REMOVE_WWID) {
588 r = remove_wwid(refwwid);
590 printf("wwid '%s' removed\n", refwwid);
592 printf("wwid '%s' not in wwids file\n",
598 if (cmd == CMD_ADD_WWID) {
599 r = remember_wwid(refwwid);
601 printf("wwid '%s' added\n", refwwid);
603 printf("failed adding '%s' to wwids file\n",
607 condlog(3, "scope limited to %s", refwwid);
608 /* If you are ignoring the wwids file and find_multipaths is
609 * set, you need to actually check if there are two available
610 * paths to determine if this path should be multipathed. To
611 * do this, we put off the check until after discovering all
613 * Paths listed in the wwids file are always considered valid.
615 if (cmd == CMD_VALID_PATH) {
616 if (is_failed_wwid(refwwid) == WWID_IS_FAILED) {
620 if ((!find_multipaths_on(conf) &&
621 ignore_wwids_on(conf)) ||
622 check_wwids_file(refwwid, 0) == 0)
624 if (!ignore_wwids_on(conf))
626 /* At this point, either r==0 or find_multipaths_on. */
629 * Shortcut for find_multipaths smart:
630 * Quick check if path is already multipathed.
632 if (sysfs_is_multipathed(VECTOR_SLOT(pathvec, 0))) {
638 * DM_MULTIPATH_DEVICE_PATH=="0" means that we have
639 * been called for this device already, and have
640 * released it to systemd. Unless the device is now
641 * already multipathed (see above), we can't try to
642 * grab it, because setting SYSTEMD_READY=0 would
643 * cause file systems to be unmounted.
644 * Leave DM_MULTIPATH_DEVICE_PATH="0".
652 /* find_multipaths_on: Fall through to path detection */
662 if (cmd == CMD_LIST_LONG)
663 /* extended path info '-ll' */
664 di_flag |= DI_SYSFS | DI_CHECKER | DI_SERIAL;
665 else if (cmd == CMD_LIST_SHORT)
666 /* minimum path info '-l' */
672 if (path_discovery(pathvec, di_flag) < 0)
675 if (conf->verbosity > 2)
676 print_all_paths(pathvec, 1);
678 get_path_layout(pathvec, 0);
679 foreign_path_layout();
681 if (get_dm_mpvec(cmd, curmp, pathvec, refwwid))
684 filter_pathvec(pathvec, refwwid);
686 if (cmd == CMD_DUMP_CONFIG) {
687 vector hwes = get_used_hwes(pathvec);
689 dump_config(conf, hwes, curmp);
694 if (cmd == CMD_VALID_PATH) {
698 /* This only happens if find_multipaths and
699 * ignore_wwids is set, and the path is not in WWIDs
700 * file, not currently multipathed, and has
701 * never been released to systemd.
702 * If there is currently a multipath device matching
703 * the refwwid, or there is more than one path matching
704 * the refwwid, then the path is valid */
705 if (VECTOR_SIZE(curmp) != 0) {
708 } else if (VECTOR_SIZE(pathvec) > 1)
711 /* Use r=2 as an indication for "maybe" */
715 * If opening the path with O_EXCL fails, the path
716 * is in use (e.g. mounted during initramfs processing).
717 * We know that it's not used by dm-multipath.
718 * We may not set SYSTEMD_READY=0 on such devices, it
719 * might cause systemd to umount the device.
720 * Use O_RDONLY, because udevd would trigger another
721 * uevent for close-after-write.
723 * The O_EXCL check is potentially dangerous, because it may
724 * race with other tasks trying to access the device. Therefore
725 * this code is only executed if the path hasn't been released
726 * to systemd earlier (see above).
728 * get_refwwid() above stores the path we examine in slot 0.
730 pp = VECTOR_SLOT(pathvec, 0);
731 fd = open(udev_device_get_devnode(pp->udev),
736 condlog(3, "%s: path %s is in use: %s",
740 * Check if we raced with multipathd
742 r = !sysfs_is_multipathed(VECTOR_SLOT(pathvec, 0));
747 if (cmd != CMD_CREATE && cmd != CMD_DRY_RUN) {
753 * core logic entry point
755 r = coalesce_paths(&vecs, NULL, refwwid,
756 conf->force_reload, cmd);
759 if (cmd == CMD_VALID_PATH)
760 r = print_cmd_valid(r, pathvec, conf);
766 free_multipathvec(curmp, KEEP_PATHS);
767 free_pathvec(pathvec, FREE_PATHS);
773 get_dev_type(char *dev) {
777 if (stat(dev, &buf) == 0 && S_ISBLK(buf.st_mode)) {
778 if (dm_is_dm_major(major(buf.st_rdev)))
782 else if (sscanf(dev, "%d:%d", &i, &i) == 2)
784 else if (valid_alias(dev))
790 * Some multipath commands are dangerous to run while multipathd is running.
791 * For example, "multipath -r" may apply a modified configuration to the kernel,
792 * while multipathd is still using the old configuration, leading to
793 * inconsistent state.
795 * It is safer to use equivalent multipathd client commands instead.
803 int delegate_to_multipathd(enum mpath_cmds cmd, const char *dev,
804 enum devtypes dev_type, const struct config *conf)
807 char command[1024], *p, *reply = NULL;
808 int n, r = DELEGATE_ERROR;
814 if (cmd == CMD_CREATE && conf->force_reload == FORCE_RELOAD_YES) {
815 p += snprintf(p, n, "reconfigure");
817 /* Add other translations here */
819 if (strlen(command) == 0)
820 /* No command found, no need to delegate */
821 return NOT_DELEGATED;
823 fd = mpath_connect();
825 return NOT_DELEGATED;
827 if (p >= command + sizeof(command)) {
828 condlog(0, "internal error - command buffer overflow");
832 condlog(3, "delegating command to multipathd");
834 if (mpath_process_cmd(fd, command, &reply, conf->uxsock_timeout)
836 condlog(1, "error in multipath command %s: %s",
837 command, strerror(errno));
841 if (reply != NULL && *reply != '\0' && strcmp(reply, "ok\n"))
852 main (int argc, char *argv[])
858 enum mpath_cmds cmd = CMD_CREATE;
859 enum devtypes dev_type = DEV_NONE;
866 conf = load_config(DEFAULT_CONFIGFILE);
869 multipath_conf = conf;
870 conf->retrigger_tries = 0;
871 while ((arg = getopt(argc, argv, ":adcChl::FfM:v:p:b:BrR:itTquUwW")) != EOF ) {
873 case 1: printf("optarg : %s\n",optarg);
876 if (sizeof(optarg) > sizeof(char *) ||
877 !isdigit(optarg[0])) {
882 conf->verbosity = atoi(optarg);
885 conf->bindings_file = strdup(optarg);
888 conf->bindings_read_only = 1;
891 conf->allow_queueing = 1;
894 cmd = CMD_VALID_PATH;
897 cmd = CMD_USABLE_PATHS;
900 if (cmd == CMD_CREATE)
904 conf->remove = FLUSH_ONE;
907 conf->remove = FLUSH_ALL;
910 if (optarg && !strncmp(optarg, "l", 1))
913 cmd = CMD_LIST_SHORT;
918 debug = atoi(optarg);
922 conf->pgpolicy_flag = get_pgpolicy_id(optarg);
923 if (conf->pgpolicy_flag == IOPOLICY_UNDEF) {
924 printf("'%s' is not a valid policy\n", optarg);
930 conf->force_reload = FORCE_RELOAD_YES;
933 conf->find_multipaths |= _FIND_MULTIPATHS_I;
936 r = dump_config(conf, NULL, NULL);
937 goto out_free_config;
939 cmd = CMD_DUMP_CONFIG;
945 cmd = CMD_VALID_PATH;
946 dev_type = DEV_UEVENT;
949 cmd = CMD_USABLE_PATHS;
950 dev_type = DEV_UEVENT;
953 cmd = CMD_REMOVE_WWID;
956 cmd = CMD_RESET_WWIDS;
962 retries = atoi(optarg);
965 fprintf(stderr, "Missing option argument\n");
969 fprintf(stderr, "Unknown switch: %s\n", optarg);
979 fprintf(stderr, "need to be root\n");
984 dev = MALLOC(FILE_NAME_SIZE);
989 strncpy(dev, argv[optind], FILE_NAME_SIZE);
990 if (dev_type != DEV_UEVENT)
991 dev_type = get_dev_type(dev);
992 if (dev_type == DEV_NONE) {
993 condlog(0, "'%s' is not a valid argument\n", dev);
997 if (dev_type == DEV_UEVENT) {
998 openlog("multipath", 0, LOG_DAEMON);
999 setlogmask(LOG_UPTO(conf->verbosity + 3));
1003 set_max_fds(conf->max_fds);
1005 libmp_udev_set_sync_support(1);
1007 if (init_checkers(conf->multipath_dir)) {
1008 condlog(0, "failed to initialize checkers");
1011 if (init_prio(conf->multipath_dir)) {
1012 condlog(0, "failed to initialize prioritizers");
1015 /* Failing here is non-fatal */
1016 init_foreign(conf->multipath_dir);
1017 if (cmd == CMD_USABLE_PATHS) {
1018 r = check_usable_paths(conf, dev, dev_type);
1021 if (cmd == CMD_VALID_PATH &&
1022 (!dev || dev_type == DEV_DEVMAP)) {
1023 condlog(0, "the -c option requires a path to check");
1026 if (cmd == CMD_VALID_PATH &&
1027 dev_type == DEV_UEVENT) {
1030 fd = mpath_connect();
1032 condlog(3, "%s: daemon is not running", dev);
1033 if (!systemd_service_enabled(dev)) {
1034 r = print_cmd_valid(1, NULL, conf);
1038 mpath_disconnect(fd);
1041 if (cmd == CMD_REMOVE_WWID && !dev) {
1042 condlog(0, "the -w option requires a device");
1046 switch(delegate_to_multipathd(cmd, dev, dev_type, conf)) {
1049 case DELEGATE_ERROR:
1055 if (cmd == CMD_RESET_WWIDS) {
1056 struct multipath * mpp;
1060 curmp = vector_alloc();
1062 condlog(0, "can't allocate memory for mp list");
1065 if (dm_get_maps(curmp) == 0)
1066 r = replace_wwids(curmp);
1068 printf("successfully reset wwids\n");
1069 vector_foreach_slot_backwards(curmp, mpp, i) {
1070 vector_del_slot(curmp, i);
1071 free_multipath(mpp, KEEP_PATHS);
1077 retries = conf->remove_retries;
1078 if (conf->remove == FLUSH_ONE) {
1079 if (dev_type == DEV_DEVMAP) {
1080 r = dm_suspend_and_flush_map(dev, retries);
1082 condlog(0, "must provide a map name to remove");
1086 else if (conf->remove == FLUSH_ALL) {
1087 r = dm_flush_maps(retries);
1090 while ((r = configure(conf, cmd, dev_type, dev)) < 0)
1091 condlog(3, "restart multipath configuration process");
1102 * multipath -u must exit with status 0, otherwise udev won't
1103 * import its output.
1105 if (cmd == CMD_VALID_PATH && dev_type == DEV_UEVENT && r == 1)
1108 if (dev_type == DEV_UEVENT)
1113 * Freeing config must be done after dm_lib_exit(), because
1114 * the logging function (dm_write_log()), which is called there,
1115 * references the config.
1123 dbg_free_final(NULL);