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