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>
37 #include <libdevmapper.h>
38 #include <devmapper.h>
42 #include <structs_vec.h>
46 #include <blacklist.h>
47 #include <discovery.h>
49 #include <switchgroup.h>
52 #include <configure.h>
53 #include <pgpolicies.h>
57 #include <sys/resource.h>
60 #include <mpath_cmd.h>
65 filter_pathvec (vector pathvec, char * refwwid)
70 if (!refwwid || !strlen(refwwid))
73 vector_foreach_slot (pathvec, pp, i) {
74 if (strncmp(pp->wwid, refwwid, WWID_SIZE) != 0) {
75 condlog(3, "skip path %s : out of scope", pp->dev);
77 vector_del_slot(pathvec, i);
85 usage (char * progname)
87 fprintf (stderr, VERSION_STRING);
88 fprintf (stderr, "Usage:\n");
89 fprintf (stderr, " %s [-a|-c|-w|-W] [-d] [-r] [-i] [-v lvl] [-p pol] [-b fil] [-q] [dev]\n", progname);
90 fprintf (stderr, " %s -l|-ll|-f [-v lvl] [-b fil] [dev]\n", progname);
91 fprintf (stderr, " %s -F [-v lvl]\n", progname);
92 fprintf (stderr, " %s -t\n", progname);
93 fprintf (stderr, " %s -h\n", progname);
97 " -h print this usage text\n" \
98 " -l show multipath topology (sysfs and DM info)\n" \
99 " -ll show multipath topology (maximum info)\n" \
100 " -f flush a multipath device map\n" \
101 " -F flush all multipath device maps\n" \
102 " -a add a device wwid to the wwids file\n" \
103 " -c check if a device should be a path in a multipath device\n" \
104 " -q allow queue_if_no_path when multipathd is not running\n"\
105 " -d dry run, do not create or update devmaps\n" \
106 " -t dump internal hardware table\n" \
107 " -r force devmap reload\n" \
108 " -i ignore wwids file\n" \
109 " -B treat the bindings file as read only\n" \
110 " -b fil bindings file location\n" \
111 " -w remove a device from the wwids file\n" \
112 " -W reset the wwids file include only the current devices\n" \
113 " -p pol force all maps to specified path grouping policy :\n" \
114 " . failover one path per priority group\n" \
115 " . multibus all paths in one priority group\n" \
116 " . group_by_serial one priority group per serial\n" \
117 " . group_by_prio one priority group per priority lvl\n" \
118 " . group_by_node_name one priority group per target node\n" \
119 " -v lvl verbosity level\n" \
121 " . 1 print created devmap names only\n" \
122 " . 2 default verbosity\n" \
123 " . 3 print debug information\n" \
124 " dev action limited to:\n" \
125 " . multipath named 'dev' (ex: mpath0) or\n" \
126 " . multipath whose wwid is 'dev' (ex: 60051..)\n" \
127 " . multipath including the path named 'dev' (ex: /dev/sda)\n" \
128 " . multipath including the path with maj:min 'dev' (ex: 8:0)\n" \
134 update_paths (struct multipath * mpp)
137 struct pathgroup * pgp;
143 vector_foreach_slot (mpp->pg, pgp, i) {
147 vector_foreach_slot (pgp->paths, pp, j) {
148 if (!strlen(pp->dev)) {
149 if (devt2devname(pp->dev, FILE_NAME_SIZE,
152 * path is not in sysfs anymore
154 pp->chkrstate = pp->state = PATH_DOWN;
158 if (pathinfo(pp, conf->hwtable, DI_ALL))
159 pp->state = PATH_UNCHECKED;
163 if (pp->state == PATH_UNCHECKED ||
164 pp->state == PATH_WILD) {
165 if (pathinfo(pp, conf->hwtable, DI_CHECKER))
166 pp->state = PATH_UNCHECKED;
169 if (pp->priority == PRIO_UNDEF) {
170 if (pathinfo(pp, conf->hwtable, DI_PRIO))
171 pp->priority = PRIO_UNDEF;
179 get_dm_mpvec (vector curmp, vector pathvec, char * refwwid)
182 struct multipath * mpp;
183 char params[PARAMS_SIZE], status[PARAMS_SIZE];
185 if (dm_get_maps(curmp))
188 vector_foreach_slot (curmp, mpp, i) {
190 * discard out of scope maps
192 if (mpp->wwid && refwwid &&
193 strncmp(mpp->wwid, refwwid, WWID_SIZE)) {
194 condlog(3, "skip map %s: out of scope", mpp->alias);
195 free_multipath(mpp, KEEP_PATHS);
196 vector_del_slot(curmp, i);
201 if (conf->cmd == CMD_VALID_PATH)
204 dm_get_map(mpp->alias, &mpp->size, params);
205 condlog(3, "params = %s", params);
206 dm_get_status(mpp->alias, status);
207 condlog(3, "status = %s", status);
209 disassemble_map(pathvec, params, mpp, 0);
212 * disassemble_map() can add new paths to pathvec.
213 * If not in "fast list mode", we need to fetch information
216 if (conf->cmd != CMD_LIST_SHORT)
219 if (conf->cmd == CMD_LIST_LONG)
220 mpp->bestpg = select_path_group(mpp);
222 disassemble_status(status, mpp);
224 if (conf->cmd == CMD_LIST_SHORT ||
225 conf->cmd == CMD_LIST_LONG)
226 print_multipath_topology(mpp, conf->verbosity);
228 if (conf->cmd == CMD_CREATE)
229 reinstate_paths(mpp);
245 vector pathvec = NULL;
249 char * refwwid = NULL;
253 * allocate core vectors to store paths and multipaths
255 curmp = vector_alloc();
256 pathvec = vector_alloc();
258 if (!curmp || !pathvec) {
259 condlog(0, "can not allocate memory");
262 vecs.pathvec = pathvec;
265 dev = convert_dev(conf->dev, (conf->dev_type == DEV_DEVNODE));
268 * if we have a blacklisted device parameter, exit early
270 if (dev && conf->dev_type == DEV_DEVNODE &&
271 conf->cmd != CMD_REMOVE_WWID &&
272 (filter_devnode(conf->blist_devnode,
273 conf->elist_devnode, dev) > 0)) {
274 if (conf->cmd == CMD_VALID_PATH)
275 printf("%s is not a valid multipath device path\n",
280 * scope limiting must be translated into a wwid
281 * failing the translation is fatal (by policy)
284 int failed = get_refwwid(conf->dev, conf->dev_type, pathvec,
287 condlog(4, "%s: failed to get wwid", conf->dev);
288 if (failed == 2 && conf->cmd == CMD_VALID_PATH)
289 printf("%s is not a valid multipath device path\n", conf->dev);
291 condlog(3, "scope is nul");
294 if (conf->cmd == CMD_REMOVE_WWID) {
295 r = remove_wwid(refwwid);
297 printf("wwid '%s' removed\n", refwwid);
299 printf("wwid '%s' not in wwids file\n",
305 if (conf->cmd == CMD_ADD_WWID) {
306 r = remember_wwid(refwwid);
308 printf("wwid '%s' added\n", refwwid);
310 printf("failed adding '%s' to wwids file\n",
314 condlog(3, "scope limited to %s", refwwid);
315 /* If you are ignoring the wwids file and find_multipaths is
316 * set, you need to actually check if there are two available
317 * paths to determine if this path should be multipathed. To
318 * do this, we put off the check until after discovering all
320 if (conf->cmd == CMD_VALID_PATH &&
321 (!conf->find_multipaths || !conf->ignore_wwids)) {
322 if (conf->ignore_wwids ||
323 check_wwids_file(refwwid, 0) == 0)
326 printf("%s %s a valid multipath device path\n",
327 conf->dev, r == 0 ? "is" : "is not");
338 if (conf->cmd == CMD_LIST_LONG)
339 /* extended path info '-ll' */
340 di_flag |= DI_SYSFS | DI_CHECKER;
341 else if (conf->cmd == CMD_LIST_SHORT)
342 /* minimum path info '-l' */
348 if (path_discovery(pathvec, conf, di_flag) < 0)
351 if (conf->verbosity > 2)
352 print_all_paths(pathvec, 1);
354 get_path_layout(pathvec, 0);
356 if (get_dm_mpvec(curmp, pathvec, refwwid))
359 filter_pathvec(pathvec, refwwid);
362 if (conf->cmd == CMD_VALID_PATH) {
363 /* This only happens if find_multipaths is and
364 * ignore_wwids is set.
365 * If there is currently a multipath device matching
366 * the refwwid, or there is more than one path matching
367 * the refwwid, then the path is valid */
368 if (VECTOR_SIZE(curmp) != 0 || VECTOR_SIZE(pathvec) > 1)
370 printf("%s %s a valid multipath device path\n",
371 conf->dev, r == 0 ? "is" : "is not");
375 if (conf->cmd != CMD_CREATE && conf->cmd != CMD_DRY_RUN) {
381 * core logic entry point
383 r = coalesce_paths(&vecs, NULL, refwwid,
384 conf->force_reload, 0);
390 free_multipathvec(curmp, KEEP_PATHS);
391 free_pathvec(pathvec, FREE_PATHS);
399 char * c, * tmp = NULL;
401 unsigned int maxlen = 256;
404 reply = MALLOC(maxlen);
413 c += snprint_defaults(c, reply + maxlen - c);
414 again = ((c - reply) == maxlen);
416 reply = REALLOC(reply, maxlen *= 2);
419 c += snprint_blacklist(c, reply + maxlen - c);
420 again = ((c - reply) == maxlen);
422 reply = REALLOC(reply, maxlen *= 2);
425 c += snprint_blacklist_except(c, reply + maxlen - c);
426 again = ((c - reply) == maxlen);
428 reply = REALLOC(reply, maxlen *= 2);
431 c += snprint_hwtable(c, reply + maxlen - c, conf->hwtable);
432 again = ((c - reply) == maxlen);
434 reply = REALLOC(reply, maxlen *= 2);
437 c += snprint_overrides(c, reply + maxlen - c, conf->overrides);
438 again = ((c - reply) == maxlen);
440 reply = REALLOC(reply, maxlen *= 2);
443 if (VECTOR_SIZE(conf->mptable) > 0) {
444 c += snprint_mptable(c, reply + maxlen - c,
446 again = ((c - reply) == maxlen);
448 reply = REALLOC(reply, maxlen *= 2);
458 get_dev_type(char *dev) {
462 if (stat(dev, &buf) == 0 && S_ISBLK(buf.st_mode)) {
463 if (dm_is_dm_major(major(buf.st_rdev)))
467 else if (sscanf(dev, "%d:%d", &i, &i) == 2)
469 else if (valid_alias(dev))
475 main (int argc, char *argv[])
485 if (load_config(DEFAULT_CONFIGFILE, udev))
488 while ((arg = getopt(argc, argv, ":adchl::FfM:v:p:b:BritquwW")) != EOF ) {
490 case 1: printf("optarg : %s\n",optarg);
493 if (sizeof(optarg) > sizeof(char *) ||
494 !isdigit(optarg[0])) {
499 conf->verbosity = atoi(optarg);
502 conf->bindings_file = strdup(optarg);
505 conf->bindings_read_only = 1;
508 conf->allow_queueing = 1;
511 conf->cmd = CMD_VALID_PATH;
514 if (conf->cmd == CMD_CREATE)
515 conf->cmd = CMD_DRY_RUN;
518 conf->remove = FLUSH_ONE;
521 conf->remove = FLUSH_ALL;
524 if (optarg && !strncmp(optarg, "l", 1))
525 conf->cmd = CMD_LIST_LONG;
527 conf->cmd = CMD_LIST_SHORT;
532 debug = atoi(optarg);
536 conf->pgpolicy_flag = get_pgpolicy_id(optarg);
537 if (conf->pgpolicy_flag == -1) {
538 printf("'%s' is not a valid policy\n", optarg);
544 conf->force_reload = 1;
547 conf->ignore_wwids = 1;
551 goto out_free_config;
556 conf->cmd = CMD_VALID_PATH;
557 conf->dev_type = DEV_UEVENT;
560 conf->cmd = CMD_REMOVE_WWID;
563 conf->cmd = CMD_RESET_WWIDS;
566 conf->cmd = CMD_ADD_WWID;
569 fprintf(stderr, "Missing option argument\n");
573 fprintf(stderr, "Unknown switch: %s\n", optarg);
583 fprintf(stderr, "need to be root\n");
587 dm_init(conf->verbosity);
590 dm_drv_version(conf->version, TGT_MPATH);
591 dm_udev_set_sync_support(1);
594 conf->dev = MALLOC(FILE_NAME_SIZE);
599 strncpy(conf->dev, argv[optind], FILE_NAME_SIZE);
600 if (conf->dev_type != DEV_UEVENT)
601 conf->dev_type = get_dev_type(conf->dev);
602 if (conf->dev_type == DEV_NONE) {
603 condlog(0, "'%s' is not a valid argument\n", conf->dev);
607 if (conf->dev_type == DEV_UEVENT) {
608 openlog("multipath", 0, LOG_DAEMON);
609 setlogmask(LOG_UPTO(conf->verbosity + 3));
614 struct rlimit fd_limit;
616 fd_limit.rlim_cur = conf->max_fds;
617 fd_limit.rlim_max = conf->max_fds;
618 if (setrlimit(RLIMIT_NOFILE, &fd_limit) < 0)
619 condlog(0, "can't set open fds limit to %d : %s",
620 conf->max_fds, strerror(errno));
623 if (init_checkers()) {
624 condlog(0, "failed to initialize checkers");
628 condlog(0, "failed to initialize prioritizers");
632 if (conf->cmd == CMD_VALID_PATH &&
633 (!conf->dev || conf->dev_type == DEV_DEVMAP)) {
634 condlog(0, "the -c option requires a path to check");
637 if (conf->cmd == CMD_VALID_PATH &&
638 conf->dev_type == DEV_UEVENT) {
641 fd = mpath_connect();
643 printf("%s is not a valid multipath device path\n",
647 mpath_disconnect(fd);
649 if (conf->cmd == CMD_REMOVE_WWID && !conf->dev) {
650 condlog(0, "the -w option requires a device");
653 if (conf->cmd == CMD_RESET_WWIDS) {
654 struct multipath * mpp;
658 curmp = vector_alloc();
660 condlog(0, "can't allocate memory for mp list");
663 if (dm_get_maps(curmp) == 0)
664 r = replace_wwids(curmp);
666 printf("successfully reset wwids\n");
667 vector_foreach_slot_backwards(curmp, mpp, i) {
668 vector_del_slot(curmp, i);
669 free_multipath(mpp, KEEP_PATHS);
674 if (conf->remove == FLUSH_ONE) {
675 if (conf->dev_type == DEV_DEVMAP) {
676 r = dm_suspend_and_flush_map(conf->dev);
678 condlog(0, "must provide a map name to remove");
682 else if (conf->remove == FLUSH_ALL) {
686 while ((r = configure()) < 0)
687 condlog(3, "restart multipath configuration process");
696 if (conf->dev_type == DEV_UEVENT)
701 * Freeing config must be done after dm_lib_exit(), because
702 * the logging function (dm_write_log()), which is called there,
703 * references the config.
709 dbg_free_final(NULL);