11 #include "structs_vec.h"
14 #include "devmapper.h"
17 #include "discovery.h"
21 * creates or updates mpp->paths reading mpp->pg
23 int update_mpp_paths(struct multipath *mpp, vector pathvec)
25 struct pathgroup * pgp;
33 !(mpp->paths = vector_alloc()))
36 vector_foreach_slot (mpp->pg, pgp, i) {
37 vector_foreach_slot (pgp->paths, pp, j) {
38 if (!find_path_by_devt(mpp->paths, pp->dev_t) &&
39 (find_path_by_devt(pathvec, pp->dev_t)) &&
40 store_path(mpp->paths, pp))
47 int adopt_paths(vector pathvec, struct multipath *mpp)
56 if (update_mpp_paths(mpp, pathvec))
59 vector_foreach_slot (pathvec, pp, i) {
60 if (!strncmp(mpp->wwid, pp->wwid, WWID_SIZE)) {
61 condlog(3, "%s: ownership set to %s",
65 if (!mpp->paths && !(mpp->paths = vector_alloc()))
68 if (!find_path_by_dev(mpp->paths, pp->dev) &&
69 store_path(mpp->paths, pp))
71 conf = get_multipath_config();
72 ret = pathinfo(pp, conf,
73 DI_PRIO | DI_CHECKER);
74 put_multipath_config(conf);
82 void orphan_path(struct path *pp, const char *reason)
84 condlog(3, "%s: orphan path, %s", pp->dev, reason);
86 pp->dmstate = PSTATE_UNDEF;
87 pp->uid_attribute = NULL;
90 checker_put(&pp->checker);
96 void orphan_paths(vector pathvec, struct multipath *mpp)
101 vector_foreach_slot (pathvec, pp, i) {
102 if (pp->mpp == mpp) {
103 orphan_path(pp, "map flushed");
109 set_multipath_wwid (struct multipath * mpp)
111 if (strlen(mpp->wwid))
114 dm_get_uuid(mpp->alias, mpp->wwid);
117 #define KEEP_WAITER 0
118 #define STOP_WAITER 1
122 _remove_map (struct multipath * mpp, struct vectors * vecs,
123 int stop_waiter, int purge_vec)
127 condlog(4, "%s: remove multipath map", mpp->alias);
130 * stop the DM event waiter thread
133 stop_waiter_thread(mpp, vecs);
136 * clear references to this map
138 orphan_paths(vecs->pathvec, mpp);
141 (i = find_slot(vecs->mpvec, (void *)mpp)) != -1)
142 vector_del_slot(vecs->mpvec, i);
147 free_multipath(mpp, KEEP_PATHS);
150 void remove_map(struct multipath *mpp, struct vectors *vecs, int purge_vec)
152 _remove_map(mpp, vecs, KEEP_WAITER, purge_vec);
155 void remove_map_and_stop_waiter(struct multipath *mpp, struct vectors *vecs,
158 _remove_map(mpp, vecs, STOP_WAITER, purge_vec);
162 _remove_maps (struct vectors * vecs, int stop_waiter)
165 struct multipath * mpp;
170 vector_foreach_slot (vecs->mpvec, mpp, i) {
171 _remove_map(mpp, vecs, stop_waiter, 1);
175 vector_free(vecs->mpvec);
179 void remove_maps(struct vectors *vecs)
181 _remove_maps(vecs, KEEP_WAITER);
184 void remove_maps_and_stop_waiters(struct vectors *vecs)
186 _remove_maps(vecs, STOP_WAITER);
189 static struct hwentry *
190 extract_hwe_from_path(struct multipath * mpp)
192 struct path * pp = NULL;
193 int pg_num = -1, p_num = -1, i;
194 struct pathgroup * pgp = NULL;
196 condlog(3, "%s: searching paths for valid hwe", mpp->alias);
198 if (mpp && mpp->pg) {
199 vector_foreach_slot(mpp->pg, pgp, i) {
200 if (pgp->status == PGSTATE_ACTIVE ||
201 pgp->status == PGSTATE_ENABLED) {
207 pgp = VECTOR_SLOT(mpp->pg, pg_num);
210 if (pgp && pgp->paths) {
211 vector_foreach_slot(pgp->paths, pp, i) {
212 if (pp->dmstate == PSTATE_FAILED)
214 if (strlen(pp->vendor_id) > 0 &&
215 strlen(pp->product_id) > 0 &&
216 strlen(pp->rev) > 0) {
222 pp = VECTOR_SLOT(pgp->paths, i);
226 if (!strlen(pp->vendor_id) ||
227 !strlen(pp->product_id) ||
229 condlog(3, "%s: no device details available", pp->dev);
232 condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
233 condlog(3, "%s: product = %s", pp->dev, pp->product_id);
234 condlog(3, "%s: rev = %s", pp->dev, pp->rev);
236 struct config *conf = get_multipath_config();
238 condlog(3, "searching hwtable");
239 pp->hwe = find_hwe(conf->hwtable, pp->vendor_id,
240 pp->product_id, pp->rev);
241 put_multipath_config(conf);
245 return pp?pp->hwe:NULL;
249 update_multipath_table (struct multipath *mpp, vector pathvec, int is_daemon)
251 char params[PARAMS_SIZE] = {0};
256 if (dm_get_map(mpp->alias, &mpp->size, params)) {
257 condlog(3, "%s: cannot get map", mpp->alias);
261 if (disassemble_map(pathvec, params, mpp, is_daemon)) {
262 condlog(3, "%s: cannot disassemble map", mpp->alias);
270 update_multipath_status (struct multipath *mpp)
272 char status[PARAMS_SIZE] = {0};
277 if (dm_get_status(mpp->alias, status)) {
278 condlog(3, "%s: cannot get status", mpp->alias);
282 if (disassemble_status(status, mpp)) {
283 condlog(3, "%s: cannot disassemble status", mpp->alias);
290 void sync_paths(struct multipath *mpp, vector pathvec)
293 struct pathgroup *pgp;
296 vector_foreach_slot (mpp->paths, pp, i) {
298 vector_foreach_slot(mpp->pg, pgp, j) {
299 if (find_slot(pgp->paths, (void *)pp) != -1) {
305 condlog(3, "%s dropped path %s", mpp->alias, pp->dev);
306 vector_del_slot(mpp->paths, i--);
307 orphan_path(pp, "path removed externally");
310 update_mpp_paths(mpp, pathvec);
311 vector_foreach_slot (mpp->paths, pp, i)
316 update_multipath_strings(struct multipath *mpp, vector pathvec, int is_daemon)
321 update_mpp_paths(mpp, pathvec);
322 condlog(4, "%s: %s", mpp->alias, __FUNCTION__);
324 free_multipath_attributes(mpp);
325 free_pgvec(mpp->pg, KEEP_PATHS);
328 if (update_multipath_table(mpp, pathvec, is_daemon))
330 sync_paths(mpp, pathvec);
332 if (update_multipath_status(mpp))
338 void set_no_path_retry(struct config *conf, struct multipath *mpp)
341 mpp->nr_active = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST);
342 select_no_path_retry(conf, mpp);
344 switch (mpp->no_path_retry) {
345 case NO_PATH_RETRY_UNDEF:
347 case NO_PATH_RETRY_FAIL:
348 dm_queue_if_no_path(mpp->alias, 0);
350 case NO_PATH_RETRY_QUEUE:
351 dm_queue_if_no_path(mpp->alias, 1);
354 dm_queue_if_no_path(mpp->alias, 1);
355 if (mpp->nr_active == 0) {
356 struct config *conf = get_multipath_config();
357 /* Enter retry mode */
358 mpp->retry_tick = mpp->no_path_retry * conf->checkint;
359 condlog(1, "%s: Entering recovery mode: max_retries=%d",
360 mpp->alias, mpp->no_path_retry);
361 put_multipath_config(conf);
367 int __setup_multipath(struct vectors *vecs, struct multipath *mpp,
368 int reset, int is_daemon)
372 if (dm_get_info(mpp->alias, &mpp->dmi)) {
373 /* Error accessing table */
374 condlog(3, "%s: cannot access table", mpp->alias);
378 if (!dm_map_present(mpp->alias)) {
379 /* Table has been removed */
380 condlog(3, "%s: table does not exist", mpp->alias);
384 if (update_multipath_strings(mpp, vecs->pathvec, is_daemon)) {
385 condlog(0, "%s: failed to setup multipath", mpp->alias);
389 set_multipath_wwid(mpp);
390 conf = get_multipath_config();
391 mpp->mpe = find_mpe(conf->mptable, mpp->wwid);
392 put_multipath_config(conf);
393 condlog(3, "%s: discover", mpp->alias);
396 mpp->hwe = extract_hwe_from_path(mpp);
398 condlog(3, "%s: no hardware entry found, using defaults",
402 conf = get_multipath_config();
403 select_rr_weight(conf, mpp);
404 select_pgfailback(conf, mpp);
405 set_no_path_retry(conf, mpp);
406 select_flush_on_last_del(conf, mpp);
407 put_multipath_config(conf);
408 if (VECTOR_SIZE(mpp->paths) != 0)
409 dm_cancel_deferred_remove(mpp);
414 remove_map(mpp, vecs, PURGE_VEC);
418 struct multipath *add_map_without_path (struct vectors *vecs, char *alias)
420 struct multipath * mpp = alloc_multipath();
429 mpp->alias = STRDUP(alias);
431 if (setup_multipath(vecs, mpp))
432 return NULL; /* mpp freed in setup_multipath */
434 if (adopt_paths(vecs->pathvec, mpp))
437 if (!vector_alloc_slot(vecs->mpvec))
440 vector_set_slot(vecs->mpvec, mpp);
442 if (start_waiter_thread(mpp, vecs))
447 remove_map(mpp, vecs, PURGE_VEC);
452 find_existing_alias (struct multipath * mpp,
453 struct vectors *vecs)
455 struct multipath * mp;
458 vector_foreach_slot (vecs->mpvec, mp, i)
459 if (strncmp(mp->wwid, mpp->wwid, WWID_SIZE - 1) == 0) {
460 strncpy(mpp->alias_old, mp->alias, WWID_SIZE - 1);
465 struct multipath *add_map_with_path(struct vectors *vecs, struct path *pp,
468 struct multipath * mpp;
469 struct config *conf = NULL;
471 if (!strlen(pp->wwid))
474 if (!(mpp = alloc_multipath()))
477 conf = get_multipath_config();
478 mpp->mpe = find_mpe(conf->mptable, pp->wwid);
480 put_multipath_config(conf);
482 strcpy(mpp->wwid, pp->wwid);
483 find_existing_alias(mpp, vecs);
484 if (select_alias(conf, mpp))
486 mpp->size = pp->size;
488 if (adopt_paths(vecs->pathvec, mpp))
492 if (!vector_alloc_slot(vecs->mpvec))
495 vector_set_slot(vecs->mpvec, mpp);
501 remove_map(mpp, vecs, PURGE_VEC);
505 int verify_paths(struct multipath *mpp, struct vectors *vecs)
514 vector_foreach_slot (mpp->paths, pp, i) {
516 * see if path is in sysfs
518 if (sysfs_attr_get_value(pp->udev, "dev",
519 pp->dev_t, BLK_DEV_SIZE) < 0) {
520 if (pp->state != PATH_DOWN) {
521 condlog(1, "%s: removing valid path %s in state %d",
522 mpp->alias, pp->dev, pp->state);
524 condlog(3, "%s: failed to access path %s",
525 mpp->alias, pp->dev);
528 vector_del_slot(mpp->paths, i);
531 if ((j = find_slot(vecs->pathvec,
533 vector_del_slot(vecs->pathvec, j);
536 condlog(4, "%s: verified path %s dev_t %s",
537 mpp->alias, pp->dev, pp->dev_t);
543 int update_multipath (struct vectors *vecs, char *mapname, int reset)
545 struct multipath *mpp;
546 struct pathgroup *pgp;
550 mpp = find_mp_by_alias(vecs->mpvec, mapname);
553 condlog(3, "%s: multipath map not found", mapname);
557 if (__setup_multipath(vecs, mpp, reset, 1))
558 return 1; /* mpp freed in setup_multipath */
561 * compare checkers states with DM states
563 vector_foreach_slot (mpp->pg, pgp, i) {
564 vector_foreach_slot (pgp->paths, pp, j) {
565 if (pp->dmstate != PSTATE_FAILED)
568 if (pp->state != PATH_DOWN) {
569 struct config *conf = get_multipath_config();
570 int oldstate = pp->state;
571 condlog(2, "%s: mark as failed", pp->dev);
572 mpp->stat_path_failures++;
573 pp->state = PATH_DOWN;
574 if (oldstate == PATH_UP ||
575 oldstate == PATH_GHOST)
576 update_queue_mode_del_path(mpp);
580 * schedule the next check earlier
582 if (pp->tick > conf->checkint)
583 pp->tick = conf->checkint;
584 put_multipath_config(conf);
592 * mpp->no_path_retry:
593 * -2 (QUEUE) : queue_if_no_path enabled, never turned off
594 * -1 (FAIL) : fail_if_no_path
595 * 0 (UNDEF) : nothing
596 * >0 : queue_if_no_path enabled, turned off after polling n times
598 void update_queue_mode_del_path(struct multipath *mpp)
600 if (--mpp->nr_active == 0) {
601 if (mpp->no_path_retry > 0) {
602 struct config *conf = get_multipath_config();
606 * meaning of +1: retry_tick may be decremented in
607 * checkerloop before starting retry.
609 mpp->stat_queueing_timeouts++;
610 mpp->retry_tick = mpp->no_path_retry *
612 condlog(1, "%s: Entering recovery mode: max_retries=%d",
613 mpp->alias, mpp->no_path_retry);
614 put_multipath_config(conf);
615 } else if (mpp->no_path_retry != NO_PATH_RETRY_QUEUE)
616 mpp->stat_map_failures++;
618 condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
621 void update_queue_mode_add_path(struct multipath *mpp)
623 if (mpp->nr_active++ == 0 && mpp->no_path_retry > 0) {
624 /* come back to normal mode from retry mode */
626 dm_queue_if_no_path(mpp->alias, 1);
627 condlog(2, "%s: queue_if_no_path enabled", mpp->alias);
628 condlog(1, "%s: Recovered to normal mode", mpp->alias);
630 condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);