--- libmultipath/dict.c | 12 ++++++++++++ libmultipath/print.c | 2 ++ libmultipath/structs.h | 3 ++- multipathd/main.c | 31 +++++++++++++++++++++++++++++-- 4 files changed, 45 insertions(+), 3 deletions(-) Index: multipath-tools/libmultipath/dict.c =================================================================== --- multipath-tools.orig/libmultipath/dict.c +++ multipath-tools/libmultipath/dict.c @@ -348,6 +348,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); @@ -917,6 +919,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); @@ -1169,6 +1173,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); @@ -1472,6 +1478,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); } @@ -1748,6 +1756,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); } @@ -1970,6 +1980,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", pgfailback); } Index: multipath-tools/libmultipath/print.c =================================================================== --- multipath-tools.orig/libmultipath/print.c +++ multipath-tools/libmultipath/print.c @@ -142,6 +142,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/libmultipath/structs.h =================================================================== --- multipath-tools.orig/libmultipath/structs.h +++ multipath-tools/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 { Index: multipath-tools/multipathd/main.c =================================================================== --- multipath-tools.orig/multipathd/main.c +++ multipath-tools/multipathd/main.c @@ -875,6 +875,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->state != PATH_DOWN && pp1->state != PATH_SHAKY) + return 0; + } + return 1; +} + static void defered_failback_tick (vector mpvec) { @@ -1013,8 +1039,9 @@ check_path (struct vectors * vecs, struc if (pp->mpp->pgfailback > 0) pp->mpp->failback_tick = pp->mpp->pgfailback + 1; - else if (pp->mpp->pgfailback == -FAILBACK_IMMEDIATE && - need_switch_pathgroup(pp->mpp, 1)) + else if (need_switch_pathgroup(pp->mpp, 1) && + (pp->mpp->pgfailback == -FAILBACK_IMMEDIATE || + followover_should_failback(pp))) switch_pathgroup(pp->mpp); /*