--- /dev/null
+---
+ 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;