--- libmultipath/dict.c | 12 ++++++++++++ libmultipath/print.c | 2 ++ libmultipath/structs.h | 3 ++- multipath/multipath.conf.5 | 5 +++++ multipathd/main.c | 29 ++++++++++++++++++++++++++++- 5 files changed, 49 insertions(+), 2 deletions(-) Index: multipath-tools-120123/libmultipath/dict.c =================================================================== --- multipath-tools-120123.orig/libmultipath/dict.c +++ multipath-tools-120123/libmultipath/dict.c @@ -406,6 +406,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); @@ -1031,6 +1033,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); @@ -1303,6 +1307,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); @@ -1646,6 +1652,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); } @@ -1985,6 +1993,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); } @@ -2243,6 +2253,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-120123/libmultipath/print.c =================================================================== --- multipath-tools-120123.orig/libmultipath/print.c +++ multipath-tools-120123/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-120123/libmultipath/structs.h =================================================================== --- multipath-tools-120123.orig/libmultipath/structs.h +++ multipath-tools-120123/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-120123/multipathd/main.c =================================================================== --- multipath-tools-120123.orig/multipathd/main.c +++ multipath-tools-120123/multipathd/main.c @@ -1011,6 +1011,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) { @@ -1238,7 +1264,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 || + followover_should_failback(pp)) switch_pathgroup(pp->mpp); } } Index: multipath-tools-120123/multipath/multipath.conf.5 =================================================================== --- multipath-tools-120123.orig/multipath/multipath.conf.5 +++ multipath-tools-120123/multipath/multipath.conf.5 @@ -258,6 +258,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