--- libmultipath/dict.c | 12 ++++++++++++ libmultipath/discovery.c | 6 +++--- libmultipath/print.c | 2 ++ libmultipath/structs.h | 4 +++- multipath/main.c | 2 +- multipath/multipath.conf.5 | 5 +++++ multipathd/main.c | 35 ++++++++++++++++++++++++++++++++++- 7 files changed, 60 insertions(+), 6 deletions(-) Index: multipath-tools-120518/libmultipath/dict.c =================================================================== --- multipath-tools-120518.orig/libmultipath/dict.c +++ multipath-tools-120518/libmultipath/dict.c @@ -398,6 +398,8 @@ default_failback_handler(vector strvec) conf->pgfailback = -FAILBACK_MANUAL; else if (strlen(buff) == 9 && !strcmp(buff, "immediate")) conf->pgfailback = -FAILBACK_IMMEDIATE; + else if (strlen(buff) == 10 && !strcmp(buff, "followover")) + conf->pgfailback = -FAILBACK_FOLLOWOVER; else conf->pgfailback = atoi(buff); @@ -1053,6 +1055,8 @@ hw_failback_handler(vector strvec) hwe->pgfailback = -FAILBACK_MANUAL; else if (strlen(buff) == 9 && !strcmp(buff, "immediate")) hwe->pgfailback = -FAILBACK_IMMEDIATE; + else if (strlen(buff) == 10 && !strcmp(buff, "followover")) + hwe->pgfailback = -FAILBACK_FOLLOWOVER; else hwe->pgfailback = atoi(buff); @@ -1351,6 +1355,8 @@ mp_failback_handler(vector strvec) mpe->pgfailback = -FAILBACK_MANUAL; else if (strlen(buff) == 9 && !strcmp(buff, "immediate")) mpe->pgfailback = -FAILBACK_IMMEDIATE; + else if (strlen(buff) == 10 && !strcmp(buff, "followover")) + mpe->pgfailback = -FAILBACK_FOLLOWOVER; else mpe->pgfailback = atoi(buff); @@ -1769,6 +1775,8 @@ snprint_mp_failback (char * buff, int le return snprintf(buff, len, "manual"); case -FAILBACK_IMMEDIATE: return snprintf(buff, len, "immediate"); + case -FAILBACK_FOLLOWOVER: + return snprintf(buff, len, "followover"); default: return snprintf(buff, len, "%i", mpe->pgfailback); } @@ -2130,6 +2138,8 @@ snprint_hw_failback (char * buff, int le return snprintf(buff, len, "manual"); case -FAILBACK_IMMEDIATE: return snprintf(buff, len, "immediate"); + case -FAILBACK_FOLLOWOVER: + return snprintf(buff, len, "followover"); default: return snprintf(buff, len, "%i", hwe->pgfailback); } @@ -2394,6 +2404,8 @@ snprint_def_failback (char * buff, int l return snprintf(buff, len, "manual"); case -FAILBACK_IMMEDIATE: return snprintf(buff, len, "immediate"); + case -FAILBACK_FOLLOWOVER: + return snprintf(buff, len, "followover"); default: return snprintf(buff, len, "%i", conf->pgfailback); } Index: multipath-tools-120518/libmultipath/print.c =================================================================== --- multipath-tools-120518.orig/libmultipath/print.c +++ multipath-tools-120518/libmultipath/print.c @@ -143,6 +143,8 @@ snprint_failback (char * buff, size_t le { if (mpp->pgfailback == -FAILBACK_IMMEDIATE) return snprintf(buff, len, "immediate"); + if (mpp->pgfailback == -FAILBACK_FOLLOWOVER) + return snprintf(buff, len, "followover"); if (!mpp->failback_tick) return snprintf(buff, len, "-"); Index: multipath-tools-120518/libmultipath/structs.h =================================================================== --- multipath-tools-120518.orig/libmultipath/structs.h +++ multipath-tools-120518/libmultipath/structs.h @@ -39,7 +39,8 @@ enum rr_weight_mode { enum failback_mode { FAILBACK_UNDEF, FAILBACK_MANUAL, - FAILBACK_IMMEDIATE + FAILBACK_IMMEDIATE, + FAILBACK_FOLLOWOVER }; enum sysfs_buses { @@ -151,6 +152,7 @@ struct path { int offline; int state; int dmstate; + int chkrstate; int failcount; int priority; int pgindex; Index: multipath-tools-120518/multipathd/main.c =================================================================== --- multipath-tools-120518.orig/multipathd/main.c +++ multipath-tools-120518/multipathd/main.c @@ -995,6 +995,32 @@ mpvec_garbage_collector (struct vectors } } +/* This is called after a path has started working again. It the multipath + * device for this path uses the followover failback type, and this is the + * best pathgroup, and this is the first path in the pathgroup to come back + * up, then switch to this pathgroup */ +static int +followover_should_failback(struct path * pp) +{ + struct pathgroup * pgp; + struct path *pp1; + int i; + + if (pp->mpp->pgfailback != -FAILBACK_FOLLOWOVER || + !pp->mpp->pg || !pp->pgindex || + pp->pgindex != pp->mpp->bestpg) + return 0; + + pgp = VECTOR_SLOT(pp->mpp->pg, pp->pgindex - 1); + vector_foreach_slot(pgp->paths, pp1, i) { + if (pp1 == pp) + continue; + if (pp1->chkrstate != PATH_DOWN && pp1->chkrstate != PATH_SHAKY) + return 0; + } + return 1; +} + static void defered_failback_tick (vector mpvec) { @@ -1092,6 +1118,8 @@ check_path (struct vectors * vecs, struc { int newstate; int new_path_up = 0; + int chkr_new_path_up = 0; + int oldchkrstate = pp->chkrstate; if (!pp->mpp) return; @@ -1130,6 +1158,7 @@ check_path (struct vectors * vecs, struc pp->dev); pp->dmstate = PSTATE_UNDEF; } + pp->chkrstate = newstate; if (newstate != pp->state) { int oldstate = pp->state; pp->state = newstate; @@ -1182,6 +1211,9 @@ check_path (struct vectors * vecs, struc new_path_up = 1; + if (oldchkrstate != PATH_UP && oldchkrstate != PATH_GHOST) + chkr_new_path_up = 1; + /* * if at least one path is up in a group, and * the group is disabled, re-enable it @@ -1233,7 +1265,8 @@ check_path (struct vectors * vecs, struc (new_path_up || pp->mpp->failback_tick <= 0)) pp->mpp->failback_tick = pp->mpp->pgfailback + 1; - else if (pp->mpp->pgfailback == -FAILBACK_IMMEDIATE) + else if (pp->mpp->pgfailback == -FAILBACK_IMMEDIATE || + (chkr_new_path_up && followover_should_failback(pp))) switch_pathgroup(pp->mpp); } } Index: multipath-tools-120518/multipath/multipath.conf.5 =================================================================== --- multipath-tools-120518.orig/multipath/multipath.conf.5 +++ multipath-tools-120518/multipath/multipath.conf.5 @@ -254,6 +254,11 @@ active paths. .B manual Do not perform automatic failback. .TP +.B followover +Only perform automatic failback when the first path of a pathgroup +becomes active. This keeps a node from automatically failing back when +another node requested the failover. +.TP .B values > 0 deferred failback (time to defer in seconds) .TP Index: multipath-tools-120518/libmultipath/discovery.c =================================================================== --- multipath-tools-120518.orig/libmultipath/discovery.c +++ multipath-tools-120518/libmultipath/discovery.c @@ -878,13 +878,13 @@ pathinfo (struct path *pp, vector hwtabl if (mask & DI_CHECKER) { if (path_state == PATH_UP) { - pp->state = get_state(pp, 0); + pp->chkrstate = pp->state = get_state(pp, 0); if (pp->state == PATH_UNCHECKED || pp->state == PATH_WILD) goto blank; } else { condlog(3, "%s: path inaccessible", pp->dev); - pp->state = path_state; + pp->chkrstate = pp->state = path_state; } } @@ -912,7 +912,7 @@ blank: * Recoverable error, for example faulty or offline path */ memset(pp->wwid, 0, WWID_SIZE); - pp->state = PATH_DOWN; + pp->chkrstate = pp->state = PATH_DOWN; return 0; } Index: multipath-tools-120518/multipath/main.c =================================================================== --- multipath-tools-120518.orig/multipath/main.c +++ multipath-tools-120518/multipath/main.c @@ -144,7 +144,7 @@ update_paths (struct multipath * mpp) /* * path is not in sysfs anymore */ - pp->state = PATH_DOWN; + pp->chkrstate = pp->state = PATH_DOWN; continue; } pp->mpp = mpp;