10 #include "structs_vec.h"
12 #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)
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 pathinfo(pp, conf->hwtable, DI_PRIO | DI_CHECKER);
79 orphan_path (struct path * pp)
82 pp->dmstate = PSTATE_UNDEF;
85 checker_put(&pp->checker);
92 orphan_paths (vector pathvec, struct multipath * mpp)
97 vector_foreach_slot (pathvec, pp, i) {
99 condlog(4, "%s: orphaned", pp->dev);
106 set_multipath_wwid (struct multipath * mpp)
111 dm_get_uuid(mpp->alias, mpp->wwid);
114 #define KEEP_WAITER 0
115 #define STOP_WAITER 1
119 _remove_map (struct multipath * mpp, struct vectors * vecs,
120 int stop_waiter, int purge_vec)
124 condlog(4, "%s: remove multipath map", mpp->alias);
127 * stop the DM event waiter thread
130 stop_waiter_thread(mpp, vecs);
133 * clear references to this map
135 orphan_paths(vecs->pathvec, mpp);
138 (i = find_slot(vecs->mpvec, (void *)mpp)) != -1)
139 vector_del_slot(vecs->mpvec, i);
144 free_multipath(mpp, KEEP_PATHS);
148 remove_map (struct multipath * mpp, struct vectors * vecs, int purge_vec)
150 _remove_map(mpp, vecs, KEEP_WAITER, purge_vec);
154 remove_map_and_stop_waiter (struct multipath * mpp, struct vectors * vecs,
157 _remove_map(mpp, vecs, STOP_WAITER, purge_vec);
161 _remove_maps (struct vectors * vecs, int stop_waiter)
164 struct multipath * mpp;
166 vector_foreach_slot (vecs->mpvec, mpp, i) {
167 _remove_map(mpp, vecs, stop_waiter, 1);
171 vector_free(vecs->mpvec);
176 remove_maps (struct vectors * vecs)
178 _remove_maps(vecs, KEEP_WAITER);
182 remove_maps_and_stop_waiters (struct vectors * vecs)
184 _remove_maps(vecs, STOP_WAITER);
187 static struct hwentry *
188 extract_hwe_from_path(struct multipath * mpp)
191 struct pathgroup * pgp;
193 pgp = VECTOR_SLOT(mpp->pg, 0);
194 pp = VECTOR_SLOT(pgp->paths, 0);
200 update_multipath_table (struct multipath *mpp, vector pathvec)
205 if (dm_get_map(mpp->alias, &mpp->size, mpp->params))
208 if (disassemble_map(pathvec, mpp->params, mpp))
215 update_multipath_status (struct multipath *mpp)
220 if(dm_get_status(mpp->alias, mpp->status))
223 if (disassemble_status(mpp->status, mpp))
230 update_multipath_strings (struct multipath *mpp, vector pathvec)
232 free_multipath_attributes(mpp);
233 free_pgvec(mpp->pg, KEEP_PATHS);
236 if (update_multipath_table(mpp, pathvec))
239 if (update_multipath_status(mpp))
246 set_no_path_retry(struct multipath *mpp)
249 mpp->nr_active = pathcount(mpp, PATH_UP) + pathcount(mpp, PATH_GHOST);
250 select_no_path_retry(mpp);
252 switch (mpp->no_path_retry) {
253 case NO_PATH_RETRY_UNDEF:
255 case NO_PATH_RETRY_FAIL:
256 dm_queue_if_no_path(mpp->alias, 0);
258 case NO_PATH_RETRY_QUEUE:
259 dm_queue_if_no_path(mpp->alias, 1);
262 dm_queue_if_no_path(mpp->alias, 1);
263 if (mpp->nr_active == 0) {
264 /* Enter retry mode */
265 mpp->retry_tick = mpp->no_path_retry * conf->checkint;
266 condlog(1, "%s: Entering recovery mode: max_retries=%d",
267 mpp->alias, mpp->no_path_retry);
274 setup_multipath (struct vectors * vecs, struct multipath * mpp)
277 if (dm_get_info(mpp->alias, &mpp->dmi)) {
278 /* Error accessing table */
279 condlog(3, "%s: cannot access table", mpp->alias);
283 if (!dm_map_present(mpp->alias)) {
284 /* Table has been removed */
285 condlog(3, "%s: table does not exist", mpp->alias);
289 set_multipath_wwid(mpp);
290 mpp->mpe = find_mpe(mpp->wwid);
291 condlog(3, "%s: discover", mpp->alias);
293 if (update_multipath_strings(mpp, vecs->pathvec)) {
294 char new_alias[WWID_SIZE];
297 * detect an external rename of the multipath device
299 if (dm_get_name(mpp->wwid, DEFAULT_TARGET, new_alias)) {
300 condlog(3, "%s multipath mapped device name has "
301 "changed from %s to %s", mpp->wwid,
302 mpp->alias, new_alias);
303 strcpy(mpp->alias, new_alias);
306 strncpy(((struct event_thread *)mpp->waiter)->mapname,
307 new_alias, WWID_SIZE);
310 condlog(0, "%s: failed to setup multipath", mpp->alias);
314 //adopt_paths(vecs->pathvec, mpp);
315 mpp->hwe = extract_hwe_from_path(mpp);
316 select_rr_weight(mpp);
317 select_pgfailback(mpp);
318 set_no_path_retry(mpp);
319 select_pg_timeout(mpp);
323 remove_map(mpp, vecs, PURGE_VEC);
327 extern struct multipath *
328 add_map_without_path (struct vectors * vecs,
329 int minor, char * alias)
331 struct multipath * mpp = alloc_multipath();
338 if (setup_multipath(vecs, mpp))
339 return NULL; /* mpp freed in setup_multipath */
341 if (adopt_paths(vecs->pathvec, mpp))
344 if (!vector_alloc_slot(vecs->mpvec))
347 vector_set_slot(vecs->mpvec, mpp);
349 if (start_waiter_thread(mpp, vecs))
354 remove_map(mpp, vecs, PURGE_VEC);
358 extern struct multipath *
359 add_map_with_path (struct vectors * vecs,
360 struct path * pp, int add_vec)
362 struct multipath * mpp;
364 if (!(mpp = alloc_multipath()))
367 mpp->mpe = find_mpe(pp->wwid);
370 strcpy(mpp->wwid, pp->wwid);
372 mpp->size = pp->size;
374 if (adopt_paths(vecs->pathvec, mpp))
378 if (!vector_alloc_slot(vecs->mpvec))
381 vector_set_slot(vecs->mpvec, mpp);
387 remove_map(mpp, vecs, PURGE_VEC);
392 verify_paths(struct multipath * mpp, struct vectors * vecs, vector rpvec)
398 vector_foreach_slot (mpp->paths, pp, i) {
400 * see if path is in sysfs
402 if (!pp->sysdev || sysfs_get_dev(pp->sysdev,
403 pp->dev_t, BLK_DEV_SIZE)) {
404 condlog(0, "%s: failed to access path %s", mpp->alias,
405 pp->sysdev ? pp->sysdev->devpath : pp->dev_t);
407 vector_del_slot(mpp->paths, i);
411 store_path(rpvec, pp);
413 if ((j = find_slot(vecs->pathvec,
415 vector_del_slot(vecs->pathvec, j);
423 int update_multipath (struct vectors *vecs, char *mapname)
425 struct multipath *mpp;
426 struct pathgroup *pgp;
430 mpp = find_mp_by_alias(vecs->mpvec, mapname);
433 condlog(3, "%s: multipath map not found\n", mapname);
437 free_pgvec(mpp->pg, KEEP_PATHS);
440 if (setup_multipath(vecs, mpp))
441 return 1; /* mpp freed in setup_multipath */
444 * compare checkers states with DM states
446 vector_foreach_slot (mpp->pg, pgp, i) {
447 vector_foreach_slot (pgp->paths, pp, j) {
448 if (pp->dmstate != PSTATE_FAILED)
451 if (pp->state != PATH_DOWN) {
452 int oldstate = pp->state;
453 condlog(2, "%s: mark as failed", pp->dev_t);
454 mpp->stat_path_failures++;
455 pp->state = PATH_DOWN;
456 if (oldstate == PATH_UP ||
457 oldstate == PATH_GHOST)
458 update_queue_mode_del_path(mpp);
462 * schedule the next check earlier
464 if (pp->tick > conf->checkint)
465 pp->tick = conf->checkint;
474 * mpp->no_path_retry:
475 * -2 (QUEUE) : queue_if_no_path enabled, never turned off
476 * -1 (FAIL) : fail_if_no_path
477 * 0 (UNDEF) : nothing
478 * >0 : queue_if_no_path enabled, turned off after polling n times
480 void update_queue_mode_del_path(struct multipath *mpp)
482 if (--mpp->nr_active == 0 && mpp->no_path_retry > 0) {
485 * meaning of +1: retry_tick may be decremented in
486 * checkerloop before starting retry.
488 mpp->stat_queueing_timeouts++;
489 mpp->retry_tick = mpp->no_path_retry * conf->checkint + 1;
490 condlog(1, "%s: Entering recovery mode: max_retries=%d",
491 mpp->alias, mpp->no_path_retry);
493 condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);
496 void update_queue_mode_add_path(struct multipath *mpp)
498 if (mpp->nr_active++ == 0 && mpp->no_path_retry > 0) {
499 /* come back to normal mode from retry mode */
501 dm_queue_if_no_path(mpp->alias, 1);
502 condlog(2, "%s: queue_if_no_path enabled", mpp->alias);
503 condlog(1, "%s: Recovered to normal mode", mpp->alias);
505 condlog(2, "%s: remaining active paths: %d", mpp->alias, mpp->nr_active);