10 #include "structs_vec.h"
13 #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, int get_info)
57 if (update_mpp_paths(mpp, pathvec))
60 vector_foreach_slot (pathvec, pp, i) {
61 if (!strncmp(mpp->wwid, pp->wwid, WWID_SIZE)) {
62 condlog(3, "%s: ownership set to %s",
66 if (!mpp->paths && !(mpp->paths = vector_alloc()))
69 if (!find_path_by_dev(mpp->paths, pp->dev) &&
70 store_path(mpp->paths, pp))
72 if (get_info && pathinfo(pp, conf->hwtable,
73 DI_PRIO | DI_CHECKER))
81 orphan_path (struct path * pp, const char *reason)
83 condlog(3, "%s: orphan path, %s", pp->dev, reason);
85 pp->dmstate = PSTATE_UNDEF;
86 pp->uid_attribute = NULL;
89 checker_put(&pp->checker);
96 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);
151 remove_map (struct multipath * mpp, struct vectors * vecs, int purge_vec)
153 _remove_map(mpp, vecs, KEEP_WAITER, purge_vec);
157 remove_map_and_stop_waiter (struct multipath * mpp, struct vectors * vecs,
160 _remove_map(mpp, vecs, STOP_WAITER, purge_vec);
164 _remove_maps (struct vectors * vecs, int stop_waiter)
167 struct multipath * mpp;
172 vector_foreach_slot (vecs->mpvec, mpp, i) {
173 _remove_map(mpp, vecs, stop_waiter, 1);
177 vector_free(vecs->mpvec);
182 remove_maps (struct vectors * vecs)
184 _remove_maps(vecs, KEEP_WAITER);
188 remove_maps_and_stop_waiters (struct vectors * vecs)
190 _remove_maps(vecs, STOP_WAITER);
193 static struct hwentry *
194 extract_hwe_from_path(struct multipath * mpp)
196 struct path * pp = NULL;
197 int pg_num = -1, p_num = -1, i;
198 struct pathgroup * pgp = NULL;
200 condlog(3, "%s: searching paths for valid hwe", mpp->alias);
202 if (mpp && mpp->pg) {
203 vector_foreach_slot(mpp->pg, pgp, i) {
204 if (pgp->status == PGSTATE_ACTIVE ||
205 pgp->status == PGSTATE_ENABLED) {
211 pgp = VECTOR_SLOT(mpp->pg, pg_num);
214 if (pgp && pgp->paths) {
215 vector_foreach_slot(pgp->paths, pp, i) {
216 if (pp->dmstate == PSTATE_FAILED)
218 if (strlen(pp->vendor_id) > 0 &&
219 strlen(pp->product_id) > 0 &&
220 strlen(pp->rev) > 0) {
226 pp = VECTOR_SLOT(pgp->paths, i);
230 if (!strlen(pp->vendor_id) ||
231 !strlen(pp->product_id) ||
233 condlog(3, "%s: no device details available", pp->dev);
236 condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id);
237 condlog(3, "%s: product = %s", pp->dev, pp->product_id);
238 condlog(3, "%s: rev = %s", pp->dev, pp->rev);
240 condlog(3, "searching hwtable");
241 pp->hwe = find_hwe(conf->hwtable, pp->vendor_id,
242 pp->product_id, pp->rev);
246 return pp?pp->hwe:NULL;
250 update_multipath_table (struct multipath *mpp, vector pathvec)
252 char params[PARAMS_SIZE] = {0};
257 if (dm_get_map(mpp->alias, &mpp->size, params)) {
258 condlog(3, "%s: cannot get map", mpp->alias);
262 if (disassemble_map(pathvec, params, mpp)) {
263 condlog(3, "%s: cannot disassemble map", mpp->alias);
271 update_multipath_status (struct multipath *mpp)
273 char status[PARAMS_SIZE] = {0};
278 if (dm_get_status(mpp->alias, status)) {
279 condlog(3, "%s: cannot get status", mpp->alias);
283 if (disassemble_status(status, mpp)) {
284 condlog(3, "%s: cannot disassemble status", mpp->alias);
291 void sync_paths(struct multipath *mpp, vector pathvec)
294 struct pathgroup *pgp;
297 vector_foreach_slot (mpp->paths, pp, i) {
299 vector_foreach_slot(mpp->pg, pgp, j) {
300 if (find_slot(pgp->paths, (void *)pp) != -1) {
306 condlog(3, "%s dropped path %s", mpp->alias, pp->dev);
307 vector_del_slot(mpp->paths, i--);
308 orphan_path(pp, "path removed externally");
311 update_mpp_paths(mpp, pathvec);
312 vector_foreach_slot (mpp->paths, pp, i)
317 update_multipath_strings (struct multipath *mpp, vector pathvec)
322 update_mpp_paths(mpp, pathvec);
323 condlog(4, "%s: %s", mpp->alias, __FUNCTION__);
325 free_multipath_attributes(mpp);
326 free_pgvec(mpp->pg, KEEP_PATHS);
329 if (update_multipath_table(mpp, pathvec))
331 sync_paths(mpp, pathvec);
333 if (update_multipath_status(mpp))
340 set_no_path_retry(struct multipath *mpp)
343 mpp->nr_active = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST);
344 select_no_path_retry(mpp);
346 switch (mpp->no_path_retry) {
347 case NO_PATH_RETRY_UNDEF:
349 case NO_PATH_RETRY_FAIL:
350 dm_queue_if_no_path(mpp->alias, 0);
352 case NO_PATH_RETRY_QUEUE:
353 dm_queue_if_no_path(mpp->alias, 1);
356 dm_queue_if_no_path(mpp->alias, 1);
357 if (mpp->nr_active == 0) {
358 /* Enter retry mode */
359 mpp->retry_tick = mpp->no_path_retry * conf->checkint;
360 condlog(1, "%s: Entering recovery mode: max_retries=%d",
361 mpp->alias, mpp->no_path_retry);
368 __setup_multipath (struct vectors * vecs, struct multipath * mpp, int reset)
370 if (dm_get_info(mpp->alias, &mpp->dmi)) {
371 /* Error accessing table */
372 condlog(3, "%s: cannot access table", mpp->alias);
376 if (!dm_map_present(mpp->alias)) {
377 /* Table has been removed */
378 condlog(3, "%s: table does not exist", mpp->alias);
382 if (update_multipath_strings(mpp, vecs->pathvec)) {
383 condlog(0, "%s: failed to setup multipath", mpp->alias);
387 set_multipath_wwid(mpp);
388 mpp->mpe = find_mpe(mpp->wwid);
389 condlog(3, "%s: discover", mpp->alias);
392 mpp->hwe = extract_hwe_from_path(mpp);
394 condlog(3, "%s: no hardware entry found, using defaults",
398 select_rr_weight(mpp);
399 select_pgfailback(mpp);
400 set_no_path_retry(mpp);
401 select_flush_on_last_del(mpp);
402 if (VECTOR_SIZE(mpp->paths) != 0)
403 dm_cancel_deferred_remove(mpp);
408 remove_map(mpp, vecs, PURGE_VEC);
412 extern struct multipath *
413 add_map_without_path (struct vectors * vecs, char * alias)
415 struct multipath * mpp = alloc_multipath();
420 mpp->alias = STRDUP(alias);
422 if (setup_multipath(vecs, mpp))
423 return NULL; /* mpp freed in setup_multipath */
425 if (adopt_paths(vecs->pathvec, mpp, 1))
428 if (!vector_alloc_slot(vecs->mpvec))
431 vector_set_slot(vecs->mpvec, mpp);
433 if (start_waiter_thread(mpp, vecs))
438 remove_map(mpp, vecs, PURGE_VEC);
443 find_existing_alias (struct multipath * mpp,
444 struct vectors *vecs)
446 struct multipath * mp;
449 vector_foreach_slot (vecs->mpvec, mp, i)
450 if (strcmp(mp->wwid, mpp->wwid) == 0) {
451 strncpy(mpp->alias_old, mp->alias, WWID_SIZE);
456 extern struct multipath *
457 add_map_with_path (struct vectors * vecs,
458 struct path * pp, int add_vec)
460 struct multipath * mpp;
462 if (!strlen(pp->wwid))
465 if (!(mpp = alloc_multipath()))
468 mpp->mpe = find_mpe(pp->wwid);
471 strcpy(mpp->wwid, pp->wwid);
472 find_existing_alias(mpp, vecs);
473 if (select_alias(mpp))
475 mpp->size = pp->size;
477 if (adopt_paths(vecs->pathvec, mpp, 1))
481 if (!vector_alloc_slot(vecs->mpvec))
484 vector_set_slot(vecs->mpvec, mpp);
490 remove_map(mpp, vecs, PURGE_VEC);
495 verify_paths(struct multipath * mpp, struct vectors * vecs)
504 vector_foreach_slot (mpp->paths, pp, i) {
506 * see if path is in sysfs
508 if (sysfs_attr_get_value(pp->udev, "dev",
509 pp->dev_t, BLK_DEV_SIZE) < 0) {
510 if (pp->state != PATH_DOWN) {
511 condlog(1, "%s: removing valid path %s in state %d",
512 mpp->alias, pp->dev, pp->state);
514 condlog(3, "%s: failed to access path %s",
515 mpp->alias, pp->dev);
518 vector_del_slot(mpp->paths, i);
521 if ((j = find_slot(vecs->pathvec,
523 vector_del_slot(vecs->pathvec, j);
526 condlog(4, "%s: verified path %s dev_t %s",
527 mpp->alias, pp->dev, pp->dev_t);
533 int update_multipath (struct vectors *vecs, char *mapname, int reset)
535 struct multipath *mpp;
536 struct pathgroup *pgp;
540 mpp = find_mp_by_alias(vecs->mpvec, mapname);
543 condlog(3, "%s: multipath map not found", mapname);
547 if (__setup_multipath(vecs, mpp, reset))
548 return 1; /* mpp freed in setup_multipath */
551 * compare checkers states with DM states
553 vector_foreach_slot (mpp->pg, pgp, i) {
554 vector_foreach_slot (pgp->paths, pp, j) {
555 if (pp->dmstate != PSTATE_FAILED)
558 if (pp->state != PATH_DOWN) {
559 int oldstate = pp->state;
560 condlog(2, "%s: mark as failed", pp->dev);
561 mpp->stat_path_failures++;
562 pp->state = PATH_DOWN;
563 if (oldstate == PATH_UP ||
564 oldstate == PATH_GHOST)
565 update_queue_mode_del_path(mpp);
569 * schedule the next check earlier
571 if (pp->tick > conf->checkint)
572 pp->tick = conf->checkint;
580 * mpp->no_path_retry:
581 * -2 (QUEUE) : queue_if_no_path enabled, never turned off
582 * -1 (FAIL) : fail_if_no_path
583 * 0 (UNDEF) : nothing
584 * >0 : queue_if_no_path enabled, turned off after polling n times
586 void update_queue_mode_del_path(struct multipath *mpp)
588 if (--mpp->nr_active == 0 && mpp->no_path_retry > 0) {
591 * meaning of +1: retry_tick may be decremented in
592 * checkerloop before starting retry.
594 mpp->stat_queueing_timeouts++;
595 mpp->retry_tick = mpp->no_path_retry * conf->checkint + 1;
596 condlog(1, "%s: Entering recovery mode: max_retries=%d",
597 mpp->alias, mpp->no_path_retry);
599 condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
602 void update_queue_mode_add_path(struct multipath *mpp)
604 if (mpp->nr_active++ == 0 && mpp->no_path_retry > 0) {
605 /* come back to normal mode from retry mode */
607 dm_queue_if_no_path(mpp->alias, 1);
608 condlog(2, "%s: queue_if_no_path enabled", mpp->alias);
609 condlog(1, "%s: Recovered to normal mode", mpp->alias);
611 condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);