11 #include "structs_vec.h"
14 #include "devmapper.h"
17 #include "discovery.h"
21 * creates or updates mpp->paths reading mpp->pg
24 update_mpp_paths(struct multipath * mpp, vector pathvec)
26 struct pathgroup * pgp;
34 !(mpp->paths = vector_alloc()))
37 vector_foreach_slot (mpp->pg, pgp, i) {
38 vector_foreach_slot (pgp->paths, pp, j) {
39 if (!find_path_by_devt(mpp->paths, pp->dev_t) &&
40 (find_path_by_devt(pathvec, pp->dev_t)) &&
41 store_path(mpp->paths, pp))
49 adopt_paths (vector pathvec, struct multipath * mpp)
58 if (update_mpp_paths(mpp, pathvec))
61 vector_foreach_slot (pathvec, pp, i) {
62 if (!strncmp(mpp->wwid, pp->wwid, WWID_SIZE)) {
63 condlog(3, "%s: ownership set to %s",
67 if (!mpp->paths && !(mpp->paths = vector_alloc()))
70 if (!find_path_by_dev(mpp->paths, pp->dev) &&
71 store_path(mpp->paths, pp))
73 conf = get_multipath_config();
74 ret = pathinfo(pp, conf,
75 DI_PRIO | DI_CHECKER);
76 put_multipath_config(conf);
85 orphan_path (struct path * pp, const char *reason)
87 condlog(3, "%s: orphan path, %s", pp->dev, reason);
89 pp->dmstate = PSTATE_UNDEF;
90 pp->uid_attribute = NULL;
93 checker_put(&pp->checker);
100 orphan_paths (vector pathvec, struct multipath * mpp)
105 vector_foreach_slot (pathvec, pp, i) {
106 if (pp->mpp == mpp) {
107 orphan_path(pp, "map flushed");
113 set_multipath_wwid (struct multipath * mpp)
115 if (strlen(mpp->wwid))
118 dm_get_uuid(mpp->alias, mpp->wwid);
121 #define KEEP_WAITER 0
122 #define STOP_WAITER 1
126 _remove_map (struct multipath * mpp, struct vectors * vecs,
127 int stop_waiter, int purge_vec)
131 condlog(4, "%s: remove multipath map", mpp->alias);
134 * stop the DM event waiter thread
137 stop_waiter_thread(mpp, vecs);
140 * clear references to this map
142 orphan_paths(vecs->pathvec, mpp);
145 (i = find_slot(vecs->mpvec, (void *)mpp)) != -1)
146 vector_del_slot(vecs->mpvec, i);
151 free_multipath(mpp, KEEP_PATHS);
155 remove_map (struct multipath * mpp, struct vectors * vecs, int purge_vec)
157 _remove_map(mpp, vecs, KEEP_WAITER, purge_vec);
161 remove_map_and_stop_waiter (struct multipath * mpp, struct vectors * vecs,
164 _remove_map(mpp, vecs, STOP_WAITER, purge_vec);
168 _remove_maps (struct vectors * vecs, int stop_waiter)
171 struct multipath * mpp;
176 vector_foreach_slot (vecs->mpvec, mpp, i) {
177 _remove_map(mpp, vecs, stop_waiter, 1);
181 vector_free(vecs->mpvec);
186 remove_maps (struct vectors * vecs)
188 _remove_maps(vecs, KEEP_WAITER);
192 remove_maps_and_stop_waiters (struct vectors * vecs)
194 _remove_maps(vecs, STOP_WAITER);
197 static struct hwentry *
198 extract_hwe_from_path(struct multipath * mpp)
200 struct path * pp = NULL;
201 int pg_num = -1, p_num = -1, i;
202 struct pathgroup * pgp = NULL;
204 condlog(3, "%s: searching paths for valid hwe", mpp->alias);
206 if (mpp && mpp->pg) {
207 vector_foreach_slot(mpp->pg, pgp, i) {
208 if (pgp->status == PGSTATE_ACTIVE ||
209 pgp->status == PGSTATE_ENABLED) {
215 pgp = VECTOR_SLOT(mpp->pg, pg_num);
218 if (pgp && pgp->paths) {
219 vector_foreach_slot(pgp->paths, pp, i) {
220 if (pp->dmstate == PSTATE_FAILED)
222 if (strlen(pp->vendor_id) > 0 &&
223 strlen(pp->product_id) > 0 &&
224 strlen(pp->rev) > 0) {
230 pp = VECTOR_SLOT(pgp->paths, i);
234 if (!strlen(pp->vendor_id) ||
235 !strlen(pp->product_id) ||
237 condlog(3, "%s: no device details available", pp->dev);
240 condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
241 condlog(3, "%s: product = %s", pp->dev, pp->product_id);
242 condlog(3, "%s: rev = %s", pp->dev, pp->rev);
244 struct config *conf = get_multipath_config();
246 condlog(3, "searching hwtable");
247 pp->hwe = find_hwe(conf->hwtable, pp->vendor_id,
248 pp->product_id, pp->rev);
249 put_multipath_config(conf);
253 return pp?pp->hwe:NULL;
257 update_multipath_table (struct multipath *mpp, vector pathvec, int is_daemon)
259 char params[PARAMS_SIZE] = {0};
264 if (dm_get_map(mpp->alias, &mpp->size, params)) {
265 condlog(3, "%s: cannot get map", mpp->alias);
269 if (disassemble_map(pathvec, params, mpp, is_daemon)) {
270 condlog(3, "%s: cannot disassemble map", mpp->alias);
278 update_multipath_status (struct multipath *mpp)
280 char status[PARAMS_SIZE] = {0};
285 if (dm_get_status(mpp->alias, status)) {
286 condlog(3, "%s: cannot get status", mpp->alias);
290 if (disassemble_status(status, mpp)) {
291 condlog(3, "%s: cannot disassemble status", mpp->alias);
298 void sync_paths(struct multipath *mpp, vector pathvec)
301 struct pathgroup *pgp;
304 vector_foreach_slot (mpp->paths, pp, i) {
306 vector_foreach_slot(mpp->pg, pgp, j) {
307 if (find_slot(pgp->paths, (void *)pp) != -1) {
313 condlog(3, "%s dropped path %s", mpp->alias, pp->dev);
314 vector_del_slot(mpp->paths, i--);
315 orphan_path(pp, "path removed externally");
318 update_mpp_paths(mpp, pathvec);
319 vector_foreach_slot (mpp->paths, pp, i)
324 update_multipath_strings (struct multipath *mpp, vector pathvec, int is_daemon)
329 update_mpp_paths(mpp, pathvec);
330 condlog(4, "%s: %s", mpp->alias, __FUNCTION__);
332 free_multipath_attributes(mpp);
333 free_pgvec(mpp->pg, KEEP_PATHS);
336 if (update_multipath_table(mpp, pathvec, is_daemon))
338 sync_paths(mpp, pathvec);
340 if (update_multipath_status(mpp))
347 set_no_path_retry(struct config *conf, struct multipath *mpp)
350 mpp->nr_active = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST);
351 select_no_path_retry(conf, mpp);
353 switch (mpp->no_path_retry) {
354 case NO_PATH_RETRY_UNDEF:
356 case NO_PATH_RETRY_FAIL:
357 dm_queue_if_no_path(mpp->alias, 0);
359 case NO_PATH_RETRY_QUEUE:
360 dm_queue_if_no_path(mpp->alias, 1);
363 dm_queue_if_no_path(mpp->alias, 1);
364 if (mpp->nr_active == 0) {
365 struct config *conf = get_multipath_config();
366 /* Enter retry mode */
367 mpp->retry_tick = mpp->no_path_retry * conf->checkint;
368 condlog(1, "%s: Entering recovery mode: max_retries=%d",
369 mpp->alias, mpp->no_path_retry);
370 put_multipath_config(conf);
377 __setup_multipath (struct vectors * vecs, struct multipath * mpp,
378 int reset, int is_daemon)
382 if (dm_get_info(mpp->alias, &mpp->dmi)) {
383 /* Error accessing table */
384 condlog(3, "%s: cannot access table", mpp->alias);
388 if (!dm_map_present(mpp->alias)) {
389 /* Table has been removed */
390 condlog(3, "%s: table does not exist", mpp->alias);
394 if (update_multipath_strings(mpp, vecs->pathvec, is_daemon)) {
395 condlog(0, "%s: failed to setup multipath", mpp->alias);
399 set_multipath_wwid(mpp);
400 conf = get_multipath_config();
401 mpp->mpe = find_mpe(conf->mptable, mpp->wwid);
402 put_multipath_config(conf);
403 condlog(3, "%s: discover", mpp->alias);
406 mpp->hwe = extract_hwe_from_path(mpp);
408 condlog(3, "%s: no hardware entry found, using defaults",
412 conf = get_multipath_config();
413 select_rr_weight(conf, mpp);
414 select_pgfailback(conf, mpp);
415 set_no_path_retry(conf, mpp);
416 select_flush_on_last_del(conf, mpp);
417 put_multipath_config(conf);
418 if (VECTOR_SIZE(mpp->paths) != 0)
419 dm_cancel_deferred_remove(mpp);
424 remove_map(mpp, vecs, PURGE_VEC);
428 extern struct multipath *
429 add_map_without_path (struct vectors * vecs, char * alias)
431 struct multipath * mpp = alloc_multipath();
440 mpp->alias = STRDUP(alias);
442 if (setup_multipath(vecs, mpp))
443 return NULL; /* mpp freed in setup_multipath */
445 if (adopt_paths(vecs->pathvec, mpp))
448 if (!vector_alloc_slot(vecs->mpvec))
451 vector_set_slot(vecs->mpvec, mpp);
453 if (start_waiter_thread(mpp, vecs))
458 remove_map(mpp, vecs, PURGE_VEC);
463 find_existing_alias (struct multipath * mpp,
464 struct vectors *vecs)
466 struct multipath * mp;
469 vector_foreach_slot (vecs->mpvec, mp, i)
470 if (strncmp(mp->wwid, mpp->wwid, WWID_SIZE - 1) == 0) {
471 strncpy(mpp->alias_old, mp->alias, WWID_SIZE - 1);
476 extern struct multipath *
477 add_map_with_path (struct vectors * vecs,
478 struct path * pp, int add_vec)
480 struct multipath * mpp;
481 struct config *conf = NULL;
483 if (!strlen(pp->wwid))
486 if (!(mpp = alloc_multipath()))
489 conf = get_multipath_config();
490 mpp->mpe = find_mpe(conf->mptable, pp->wwid);
492 put_multipath_config(conf);
494 strcpy(mpp->wwid, pp->wwid);
495 find_existing_alias(mpp, vecs);
496 if (select_alias(conf, mpp))
498 mpp->size = pp->size;
500 if (adopt_paths(vecs->pathvec, mpp))
504 if (!vector_alloc_slot(vecs->mpvec))
507 vector_set_slot(vecs->mpvec, mpp);
513 remove_map(mpp, vecs, PURGE_VEC);
518 verify_paths(struct multipath * mpp, struct vectors * vecs)
527 vector_foreach_slot (mpp->paths, pp, i) {
529 * see if path is in sysfs
531 if (sysfs_attr_get_value(pp->udev, "dev",
532 pp->dev_t, BLK_DEV_SIZE) < 0) {
533 if (pp->state != PATH_DOWN) {
534 condlog(1, "%s: removing valid path %s in state %d",
535 mpp->alias, pp->dev, pp->state);
537 condlog(3, "%s: failed to access path %s",
538 mpp->alias, pp->dev);
541 vector_del_slot(mpp->paths, i);
544 if ((j = find_slot(vecs->pathvec,
546 vector_del_slot(vecs->pathvec, j);
549 condlog(4, "%s: verified path %s dev_t %s",
550 mpp->alias, pp->dev, pp->dev_t);
556 int update_multipath (struct vectors *vecs, char *mapname, int reset)
558 struct multipath *mpp;
559 struct pathgroup *pgp;
563 mpp = find_mp_by_alias(vecs->mpvec, mapname);
566 condlog(3, "%s: multipath map not found", mapname);
570 if (__setup_multipath(vecs, mpp, reset, 1))
571 return 1; /* mpp freed in setup_multipath */
574 * compare checkers states with DM states
576 vector_foreach_slot (mpp->pg, pgp, i) {
577 vector_foreach_slot (pgp->paths, pp, j) {
578 if (pp->dmstate != PSTATE_FAILED)
581 if (pp->state != PATH_DOWN) {
582 struct config *conf = get_multipath_config();
583 int oldstate = pp->state;
584 condlog(2, "%s: mark as failed", pp->dev);
585 mpp->stat_path_failures++;
586 pp->state = PATH_DOWN;
587 if (oldstate == PATH_UP ||
588 oldstate == PATH_GHOST)
589 update_queue_mode_del_path(mpp);
593 * schedule the next check earlier
595 if (pp->tick > conf->checkint)
596 pp->tick = conf->checkint;
597 put_multipath_config(conf);
605 * mpp->no_path_retry:
606 * -2 (QUEUE) : queue_if_no_path enabled, never turned off
607 * -1 (FAIL) : fail_if_no_path
608 * 0 (UNDEF) : nothing
609 * >0 : queue_if_no_path enabled, turned off after polling n times
611 void update_queue_mode_del_path(struct multipath *mpp)
613 if (--mpp->nr_active == 0) {
614 if (mpp->no_path_retry > 0) {
615 struct config *conf = get_multipath_config();
619 * meaning of +1: retry_tick may be decremented in
620 * checkerloop before starting retry.
622 mpp->stat_queueing_timeouts++;
623 mpp->retry_tick = mpp->no_path_retry *
625 condlog(1, "%s: Entering recovery mode: max_retries=%d",
626 mpp->alias, mpp->no_path_retry);
627 put_multipath_config(conf);
628 } else if (mpp->no_path_retry != NO_PATH_RETRY_QUEUE)
629 mpp->stat_map_failures++;
631 condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
634 void update_queue_mode_add_path(struct multipath *mpp)
636 if (mpp->nr_active++ == 0 && mpp->no_path_retry > 0) {
637 /* come back to normal mode from retry mode */
639 dm_queue_if_no_path(mpp->alias, 1);
640 condlog(2, "%s: queue_if_no_path enabled", mpp->alias);
641 condlog(1, "%s: Recovered to normal mode", mpp->alias);
643 condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);