Blame SOURCES/0114-RHBZ-1196394-delayed-reintegration.patch

ecd2a9
---
ecd2a9
 libmultipath/checkers.c    |    3 
ecd2a9
 libmultipath/checkers.h    |    9 +
ecd2a9
 libmultipath/config.c      |    4 
ecd2a9
 libmultipath/config.h      |    6 +
ecd2a9
 libmultipath/configure.c   |    2 
ecd2a9
 libmultipath/defaults.h    |    1 
ecd2a9
 libmultipath/dict.c        |  204 ++++++++++++++++++++++++++++++++++++++++++++-
ecd2a9
 libmultipath/print.c       |    2 
ecd2a9
 libmultipath/propsel.c     |   52 +++++++++++
ecd2a9
 libmultipath/propsel.h     |    2 
ecd2a9
 libmultipath/structs.h     |    9 +
ecd2a9
 multipath.conf.annotated   |   40 ++++++++
ecd2a9
 multipath.conf.defaults    |    2 
ecd2a9
 multipath/multipath.conf.5 |   27 +++++
ecd2a9
 multipathd/main.c          |   34 ++++++-
ecd2a9
 15 files changed, 388 insertions(+), 9 deletions(-)
ecd2a9
ecd2a9
Index: multipath-tools-130222/libmultipath/config.h
ecd2a9
===================================================================
ecd2a9
--- multipath-tools-130222.orig/libmultipath/config.h
ecd2a9
+++ multipath-tools-130222/libmultipath/config.h
ecd2a9
@@ -62,6 +62,8 @@ struct hwentry {
ecd2a9
 	int retain_hwhandler;
ecd2a9
 	int detect_prio;
ecd2a9
 	int deferred_remove;
ecd2a9
+	int delay_watch_checks;
ecd2a9
+	int delay_wait_checks;
ecd2a9
 	char * bl_product;
ecd2a9
 };
ecd2a9
 
ecd2a9
@@ -86,6 +88,8 @@ struct mpentry {
ecd2a9
 	int attribute_flags;
ecd2a9
 	int user_friendly_names;
ecd2a9
 	int deferred_remove;
ecd2a9
+	int delay_watch_checks;
ecd2a9
+	int delay_wait_checks;
ecd2a9
 	uid_t uid;
ecd2a9
 	gid_t gid;
ecd2a9
 	mode_t mode;
ecd2a9
@@ -133,6 +137,8 @@ struct config {
ecd2a9
 	int deferred_remove;
ecd2a9
 	int ignore_new_boot_devs;
ecd2a9
 	int processed_main_config;
ecd2a9
+	int delay_watch_checks;
ecd2a9
+	int delay_wait_checks;
ecd2a9
 	unsigned int version[3];
ecd2a9
 
ecd2a9
 	char * dev;
ecd2a9
Index: multipath-tools-130222/libmultipath/structs.h
ecd2a9
===================================================================
ecd2a9
--- multipath-tools-130222.orig/libmultipath/structs.h
ecd2a9
+++ multipath-tools-130222/libmultipath/structs.h
ecd2a9
@@ -134,6 +134,11 @@ enum scsi_protocol {
ecd2a9
 	SCSI_PROTOCOL_UNSPEC = 0xf, /* No specific protocol */
ecd2a9
 };
ecd2a9
 
ecd2a9
+enum delay_checks_states {
ecd2a9
+	DELAY_CHECKS_OFF = -1,
ecd2a9
+	DELAY_CHECKS_UNDEF = 0,
ecd2a9
+};
ecd2a9
+
ecd2a9
 struct sg_id {
ecd2a9
 	int host_no;
ecd2a9
 	int channel;
ecd2a9
@@ -180,6 +185,8 @@ struct path {
ecd2a9
 	int priority;
ecd2a9
 	int pgindex;
ecd2a9
 	int detect_prio;
ecd2a9
+	int watch_checks;
ecd2a9
+	int wait_checks;
ecd2a9
 	char * uid_attribute;
ecd2a9
 	struct prio prio;
ecd2a9
 	char * prio_args;
ecd2a9
@@ -215,6 +222,8 @@ struct multipath {
ecd2a9
 	int fast_io_fail;
ecd2a9
 	int retain_hwhandler;
ecd2a9
 	int deferred_remove;
ecd2a9
+	int delay_watch_checks;
ecd2a9
+	int delay_wait_checks;
ecd2a9
 	unsigned int dev_loss;
ecd2a9
 	uid_t uid;
ecd2a9
 	gid_t gid;
ecd2a9
Index: multipath-tools-130222/libmultipath/checkers.h
ecd2a9
===================================================================
ecd2a9
--- multipath-tools-130222.orig/libmultipath/checkers.h
ecd2a9
+++ multipath-tools-130222/libmultipath/checkers.h
ecd2a9
@@ -46,6 +46,14 @@
ecd2a9
  * PATH_PENDING:
ecd2a9
  * - Use: All async checkers
ecd2a9
  * - Description: Indicates a check IO is in flight.
ecd2a9
+ *
ecd2a9
+ * PATH_DELAYED:
ecd2a9
+ * - Use: None of the checkers (returned if the path is being delayed before
ecd2a9
+ *   reintegration.
ecd2a9
+ * - Description: If a path fails after being up for less than
ecd2a9
+ *   delay_watch_checks checks, when it comes back up again, it will not
ecd2a9
+ *   be marked as up until it has been up for delay_wait_checks checks.
ecd2a9
+ *   During this time, it is marked as "delayed"
ecd2a9
  */
ecd2a9
 enum path_check_state {
ecd2a9
 	PATH_WILD,
ecd2a9
@@ -55,6 +63,7 @@ enum path_check_state {
ecd2a9
 	PATH_SHAKY,
ecd2a9
 	PATH_GHOST,
ecd2a9
 	PATH_PENDING,
ecd2a9
+	PATH_DELAYED,
ecd2a9
 	PATH_MAX_STATE
ecd2a9
 };
ecd2a9
 
ecd2a9
Index: multipath-tools-130222/libmultipath/configure.c
ecd2a9
===================================================================
ecd2a9
--- multipath-tools-130222.orig/libmultipath/configure.c
ecd2a9
+++ multipath-tools-130222/libmultipath/configure.c
ecd2a9
@@ -291,6 +291,8 @@ setup_map (struct multipath * mpp, char
ecd2a9
 	select_reservation_key(mpp);
ecd2a9
 	select_retain_hwhandler(mpp);
ecd2a9
 	select_deferred_remove(mpp);
ecd2a9
+	select_delay_watch_checks(mpp);
ecd2a9
+	select_delay_wait_checks(mpp);
ecd2a9
 
ecd2a9
 	sysfs_set_scsi_tmo(mpp);
ecd2a9
 	/*
ecd2a9
Index: multipath-tools-130222/libmultipath/defaults.h
ecd2a9
===================================================================
ecd2a9
--- multipath-tools-130222.orig/libmultipath/defaults.h
ecd2a9
+++ multipath-tools-130222/libmultipath/defaults.h
ecd2a9
@@ -20,6 +20,7 @@
ecd2a9
 #define DEFAULT_RETAIN_HWHANDLER RETAIN_HWHANDLER_OFF
ecd2a9
 #define DEFAULT_DETECT_PRIO DETECT_PRIO_OFF
ecd2a9
 #define DEFAULT_DEFERRED_REMOVE DEFERRED_REMOVE_OFF
ecd2a9
+#define DEFAULT_DELAY_CHECKS DELAY_CHECKS_OFF
ecd2a9
 
ecd2a9
 #define DEFAULT_CHECKINT	5
ecd2a9
 #define MAX_CHECKINT(a)		(a << 2)
ecd2a9
Index: multipath-tools-130222/libmultipath/dict.c
ecd2a9
===================================================================
ecd2a9
--- multipath-tools-130222.orig/libmultipath/dict.c
ecd2a9
+++ multipath-tools-130222/libmultipath/dict.c
ecd2a9
@@ -801,6 +801,44 @@ def_ignore_new_boot_devs_handler(vector
ecd2a9
 	return 0;
ecd2a9
 }
ecd2a9
 
ecd2a9
+static int
ecd2a9
+def_delay_watch_checks_handler(vector strvec)
ecd2a9
+{
ecd2a9
+	char * buff;
ecd2a9
+
ecd2a9
+	buff = set_value(strvec);
ecd2a9
+	if (!buff)
ecd2a9
+		return 1;
ecd2a9
+
ecd2a9
+	if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
ecd2a9
+	    (strlen(buff) == 1 && !strcmp(buff, "0")))
ecd2a9
+		conf->delay_watch_checks = DELAY_CHECKS_OFF;
ecd2a9
+	else if ((conf->delay_watch_checks = atoi(buff)) < 1)
ecd2a9
+		conf->delay_watch_checks = DELAY_CHECKS_OFF;
ecd2a9
+
ecd2a9
+	FREE(buff);
ecd2a9
+	return 0;
ecd2a9
+}
ecd2a9
+
ecd2a9
+static int
ecd2a9
+def_delay_wait_checks_handler(vector strvec)
ecd2a9
+{
ecd2a9
+	char * buff;
ecd2a9
+
ecd2a9
+	buff = set_value(strvec);
ecd2a9
+	if (!buff)
ecd2a9
+		return 1;
ecd2a9
+
ecd2a9
+	if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
ecd2a9
+	    (strlen(buff) == 1 && !strcmp(buff, "0")))
ecd2a9
+		conf->delay_wait_checks = DELAY_CHECKS_OFF;
ecd2a9
+	else if ((conf->delay_wait_checks = atoi(buff)) < 1)
ecd2a9
+		conf->delay_wait_checks = DELAY_CHECKS_OFF;
ecd2a9
+
ecd2a9
+	FREE(buff);
ecd2a9
+	return 0;
ecd2a9
+}
ecd2a9
+
ecd2a9
 /*
ecd2a9
  * blacklist block handlers
ecd2a9
  */
ecd2a9
@@ -1517,6 +1555,52 @@ hw_deferred_remove_handler(vector strvec
ecd2a9
 	return 0;
ecd2a9
 }
ecd2a9
 
ecd2a9
+static int
ecd2a9
+hw_delay_watch_checks_handler(vector strvec)
ecd2a9
+{
ecd2a9
+	struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
ecd2a9
+	char * buff;
ecd2a9
+
ecd2a9
+	if (!hwe)
ecd2a9
+		return 1;
ecd2a9
+
ecd2a9
+	buff = set_value(strvec);
ecd2a9
+	if (!buff)
ecd2a9
+		return 1;
ecd2a9
+
ecd2a9
+	if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
ecd2a9
+	    (strlen(buff) == 1 && !strcmp(buff, "0")))
ecd2a9
+		hwe->delay_watch_checks = DELAY_CHECKS_OFF;
ecd2a9
+	else if ((hwe->delay_watch_checks = atoi(buff)) < 1)
ecd2a9
+		hwe->delay_watch_checks = DELAY_CHECKS_OFF;
ecd2a9
+
ecd2a9
+	FREE(buff);
ecd2a9
+	return 0;
ecd2a9
+}
ecd2a9
+
ecd2a9
+static int
ecd2a9
+hw_delay_wait_checks_handler(vector strvec)
ecd2a9
+{
ecd2a9
+	struct hwentry *hwe = VECTOR_LAST_SLOT(conf->hwtable);
ecd2a9
+	char * buff;
ecd2a9
+
ecd2a9
+	if (!hwe)
ecd2a9
+		return 1;
ecd2a9
+
ecd2a9
+	buff = set_value(strvec);
ecd2a9
+	if (!buff)
ecd2a9
+		return 1;
ecd2a9
+
ecd2a9
+	if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
ecd2a9
+	    (strlen(buff) == 1 && !strcmp(buff, "0")))
ecd2a9
+		hwe->delay_wait_checks = DELAY_CHECKS_OFF;
ecd2a9
+	else if ((hwe->delay_wait_checks = atoi(buff)) < 1)
ecd2a9
+		hwe->delay_wait_checks = DELAY_CHECKS_OFF;
ecd2a9
+
ecd2a9
+	FREE(buff);
ecd2a9
+	return 0;
ecd2a9
+}
ecd2a9
+
ecd2a9
 /*
ecd2a9
  * multipaths block handlers
ecd2a9
  */
ecd2a9
@@ -1996,6 +2080,52 @@ mp_deferred_remove_handler(vector strvec
ecd2a9
 	return 0;
ecd2a9
 }
ecd2a9
 
ecd2a9
+static int
ecd2a9
+mp_delay_watch_checks_handler(vector strvec)
ecd2a9
+{
ecd2a9
+	struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
ecd2a9
+	char * buff;
ecd2a9
+
ecd2a9
+	if (!mpe)
ecd2a9
+		return 1;
ecd2a9
+
ecd2a9
+	buff = set_value(strvec);
ecd2a9
+	if (!buff)
ecd2a9
+		return 1;
ecd2a9
+
ecd2a9
+	if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
ecd2a9
+	    (strlen(buff) == 1 && !strcmp(buff, "0")))
ecd2a9
+		mpe->delay_watch_checks = DELAY_CHECKS_OFF;
ecd2a9
+	else if ((mpe->delay_watch_checks = atoi(buff)) < 1)
ecd2a9
+		mpe->delay_watch_checks = DELAY_CHECKS_OFF;
ecd2a9
+
ecd2a9
+	FREE(buff);
ecd2a9
+	return 0;
ecd2a9
+}
ecd2a9
+
ecd2a9
+static int
ecd2a9
+mp_delay_wait_checks_handler(vector strvec)
ecd2a9
+{
ecd2a9
+	struct mpentry *mpe = VECTOR_LAST_SLOT(conf->mptable);
ecd2a9
+	char * buff;
ecd2a9
+
ecd2a9
+	if (!mpe)
ecd2a9
+		return 1;
ecd2a9
+
ecd2a9
+	buff = set_value(strvec);
ecd2a9
+	if (!buff)
ecd2a9
+		return 1;
ecd2a9
+
ecd2a9
+	if ((strlen(buff) == 2 && !strcmp(buff, "no")) ||
ecd2a9
+	    (strlen(buff) == 1 && !strcmp(buff, "0")))
ecd2a9
+		mpe->delay_wait_checks = DELAY_CHECKS_OFF;
ecd2a9
+	else if ((mpe->delay_wait_checks = atoi(buff)) < 1)
ecd2a9
+		mpe->delay_wait_checks = DELAY_CHECKS_OFF;
ecd2a9
+
ecd2a9
+	FREE(buff);
ecd2a9
+	return 0;
ecd2a9
+}
ecd2a9
+
ecd2a9
 /*
ecd2a9
  * config file keywords printing
ecd2a9
  */
ecd2a9
@@ -2258,6 +2388,30 @@ snprint_mp_deferred_remove (char * buff,
ecd2a9
 }
ecd2a9
 
ecd2a9
 static int
ecd2a9
+snprint_mp_delay_watch_checks(char * buff, int len, void * data)
ecd2a9
+{
ecd2a9
+	struct mpentry * mpe = (struct mpentry *)data;
ecd2a9
+
ecd2a9
+	if (mpe->delay_watch_checks == DELAY_CHECKS_UNDEF)
ecd2a9
+		return 0;
ecd2a9
+	if (mpe->delay_watch_checks == DELAY_CHECKS_OFF)
ecd2a9
+		return snprintf(buff, len, "no");
ecd2a9
+	return snprintf(buff, len, "%d", mpe->delay_watch_checks);
ecd2a9
+}
ecd2a9
+
ecd2a9
+static int
ecd2a9
+snprint_mp_delay_wait_checks(char * buff, int len, void * data)
ecd2a9
+{
ecd2a9
+	struct mpentry * mpe = (struct mpentry *)data;
ecd2a9
+
ecd2a9
+	if (mpe->delay_wait_checks == DELAY_CHECKS_UNDEF)
ecd2a9
+		return 0;
ecd2a9
+	if (mpe->delay_wait_checks == DELAY_CHECKS_OFF)
ecd2a9
+		return snprintf(buff, len, "no");
ecd2a9
+	return snprintf(buff, len, "%d", mpe->delay_wait_checks);
ecd2a9
+}
ecd2a9
+
ecd2a9
+static int
ecd2a9
 snprint_hw_fast_io_fail(char * buff, int len, void * data)
ecd2a9
 {
ecd2a9
 	struct hwentry * hwe = (struct hwentry *)data;
ecd2a9
@@ -2586,6 +2740,30 @@ snprint_hw_deferred_remove(char * buff,
ecd2a9
 }
ecd2a9
 
ecd2a9
 static int
ecd2a9
+snprint_hw_delay_watch_checks(char * buff, int len, void * data)
ecd2a9
+{
ecd2a9
+	struct hwentry * hwe = (struct hwentry *)data;
ecd2a9
+
ecd2a9
+	if (hwe->delay_watch_checks == DELAY_CHECKS_UNDEF)
ecd2a9
+		return 0;
ecd2a9
+	if (hwe->delay_watch_checks == DELAY_CHECKS_OFF)
ecd2a9
+		return snprintf(buff, len, "no");
ecd2a9
+	return snprintf(buff, len, "%d", hwe->delay_watch_checks);
ecd2a9
+}
ecd2a9
+
ecd2a9
+static int
ecd2a9
+snprint_hw_delay_wait_checks(char * buff, int len, void * data)
ecd2a9
+{
ecd2a9
+	struct hwentry * hwe = (struct hwentry *)data;
ecd2a9
+
ecd2a9
+	if (hwe->delay_wait_checks == DELAY_CHECKS_UNDEF)
ecd2a9
+		return 0;
ecd2a9
+	if (hwe->delay_wait_checks == DELAY_CHECKS_OFF)
ecd2a9
+		return snprintf(buff, len, "no");
ecd2a9
+	return snprintf(buff, len, "%d", hwe->delay_wait_checks);
ecd2a9
+}
ecd2a9
+
ecd2a9
+static int
ecd2a9
 snprint_detect_prio(char * buff, int len, void * data)
ecd2a9
 {
ecd2a9
 	struct hwentry * hwe = (struct hwentry *)data;
ecd2a9
@@ -2883,7 +3061,6 @@ snprint_def_find_multipaths (char * buff
ecd2a9
 	return snprintf(buff, len, "yes");
ecd2a9
 }
ecd2a9
 
ecd2a9
-
ecd2a9
 static int
ecd2a9
 snprint_def_user_friendly_names (char * buff, int len, void * data)
ecd2a9
 {
ecd2a9
@@ -2989,7 +3166,6 @@ snprint_def_ignore_new_boot_devs(char *
ecd2a9
 		return snprintf(buff, len, "no");
ecd2a9
 }
ecd2a9
 
ecd2a9
-
ecd2a9
 static int
ecd2a9
 snprint_def_config_dir (char * buff, int len, void * data)
ecd2a9
 {
ecd2a9
@@ -3000,6 +3176,24 @@ snprint_def_config_dir (char * buff, int
ecd2a9
 }
ecd2a9
 
ecd2a9
 static int
ecd2a9
+snprint_def_delay_watch_checks(char * buff, int len, void * data)
ecd2a9
+{
ecd2a9
+	if (conf->delay_watch_checks == DELAY_CHECKS_UNDEF ||
ecd2a9
+	    conf->delay_watch_checks == DELAY_CHECKS_OFF)
ecd2a9
+		return snprintf(buff, len, "no");
ecd2a9
+	return snprintf(buff, len, "%d", conf->delay_watch_checks);
ecd2a9
+}
ecd2a9
+
ecd2a9
+static int
ecd2a9
+snprint_def_delay_wait_checks(char * buff, int len, void * data)
ecd2a9
+{
ecd2a9
+	if (conf->delay_wait_checks == DELAY_CHECKS_UNDEF ||
ecd2a9
+	    conf->delay_wait_checks == DELAY_CHECKS_OFF)
ecd2a9
+		return snprintf(buff, len, "no");
ecd2a9
+	return snprintf(buff, len, "%d", conf->delay_wait_checks);
ecd2a9
+}
ecd2a9
+
ecd2a9
+static int
ecd2a9
 snprint_ble_simple (char * buff, int len, void * data)
ecd2a9
 {
ecd2a9
 	struct blentry * ble = (struct blentry *)data;
ecd2a9
@@ -3071,6 +3265,8 @@ init_keywords(void)
ecd2a9
 	install_keyword("deferred_remove", &def_deferred_remove_handler, &snprint_def_deferred_remove);
ecd2a9
 	install_keyword("ignore_new_boot_devs", &def_ignore_new_boot_devs_handler, &snprint_def_ignore_new_boot_devs);
ecd2a9
 	install_keyword("config_dir", &def_config_dir_handler, &snprint_def_config_dir);
ecd2a9
+	install_keyword("delay_watch_checks", &def_delay_watch_checks_handler, &snprint_def_delay_watch_checks);
ecd2a9
+	install_keyword("delay_wait_checks", &def_delay_wait_checks_handler, &snprint_def_delay_wait_checks);
ecd2a9
 	__deprecated install_keyword("default_selector", &def_selector_handler, NULL);
ecd2a9
 	__deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL);
ecd2a9
 	__deprecated install_keyword("default_uid_attribute", &def_uid_attribute_handler, NULL);
ecd2a9
@@ -3136,6 +3332,8 @@ init_keywords(void)
ecd2a9
 	install_keyword("retain_attached_hw_handler", &hw_retain_hwhandler_handler, &snprint_hw_retain_hwhandler_handler);
ecd2a9
 	install_keyword("detect_prio", &hw_detect_prio_handler, &snprint_detect_prio);
ecd2a9
 	install_keyword("deferred_remove", &hw_deferred_remove_handler, &snprint_hw_deferred_remove);
ecd2a9
+	install_keyword("delay_watch_checks", &hw_delay_watch_checks_handler, &snprint_hw_delay_watch_checks);
ecd2a9
+	install_keyword("delay_wait_checks", &hw_delay_wait_checks_handler, &snprint_hw_delay_wait_checks);
ecd2a9
 	install_sublevel_end();
ecd2a9
 
ecd2a9
 	install_keyword_root("multipaths", &multipaths_handler);
ecd2a9
@@ -3161,5 +3359,7 @@ init_keywords(void)
ecd2a9
 	install_keyword("reservation_key", &mp_reservation_key_handler, &snprint_mp_reservation_key);
ecd2a9
 	install_keyword("user_friendly_names", &mp_names_handler, &snprint_mp_user_friendly_names);
ecd2a9
 	install_keyword("deferred_remove", &mp_deferred_remove_handler, &snprint_mp_deferred_remove);
ecd2a9
+	install_keyword("delay_watch_checks", &mp_delay_watch_checks_handler, &snprint_mp_delay_watch_checks);
ecd2a9
+	install_keyword("delay_wait_checks", &mp_delay_wait_checks_handler, &snprint_mp_delay_wait_checks);
ecd2a9
 	install_sublevel_end();
ecd2a9
 }
ecd2a9
Index: multipath-tools-130222/libmultipath/print.c
ecd2a9
===================================================================
ecd2a9
--- multipath-tools-130222.orig/libmultipath/print.c
ecd2a9
+++ multipath-tools-130222/libmultipath/print.c
ecd2a9
@@ -336,6 +336,8 @@ snprint_chk_state (char * buff, size_t l
ecd2a9
 		return snprintf(buff, len, "shaky");
ecd2a9
 	case PATH_GHOST:
ecd2a9
 		return snprintf(buff, len, "ghost");
ecd2a9
+	case PATH_DELAYED:
ecd2a9
+		return snprintf(buff, len, "delayed");
ecd2a9
 	default:
ecd2a9
 		return snprintf(buff, len, "undef");
ecd2a9
 	}
ecd2a9
Index: multipath-tools-130222/libmultipath/propsel.c
ecd2a9
===================================================================
ecd2a9
--- multipath-tools-130222.orig/libmultipath/propsel.c
ecd2a9
+++ multipath-tools-130222/libmultipath/propsel.c
ecd2a9
@@ -788,3 +788,55 @@ select_detect_prio (struct path * pp)
ecd2a9
 	condlog(3, "%s: detect_prio = %d (compiled in default)", pp->dev, pp->detect_prio);
ecd2a9
 	return 0;
ecd2a9
 }
ecd2a9
+
ecd2a9
+extern int
ecd2a9
+select_delay_watch_checks (struct multipath * mp)
ecd2a9
+{
ecd2a9
+	if (mp->mpe && mp->mpe->delay_watch_checks != DELAY_CHECKS_UNDEF) {
ecd2a9
+		mp->delay_watch_checks = mp->mpe->delay_watch_checks;
ecd2a9
+		condlog(3, "delay_watch_checks = %i (multipath setting)",
ecd2a9
+				mp->delay_watch_checks);
ecd2a9
+		return 0;
ecd2a9
+	}
ecd2a9
+	if (mp->hwe && mp->hwe->delay_watch_checks != DELAY_CHECKS_UNDEF) {
ecd2a9
+		mp->delay_watch_checks = mp->hwe->delay_watch_checks;
ecd2a9
+		condlog(3, "delay_watch_checks = %i (controler setting)",
ecd2a9
+				mp->delay_watch_checks);
ecd2a9
+		return 0;
ecd2a9
+	}
ecd2a9
+	if (conf->delay_watch_checks != DELAY_CHECKS_UNDEF) {
ecd2a9
+		mp->delay_watch_checks = conf->delay_watch_checks;
ecd2a9
+		condlog(3, "delay_watch_checks = %i (config file default)",
ecd2a9
+				mp->delay_watch_checks);
ecd2a9
+		return 0;
ecd2a9
+	}
ecd2a9
+	mp->delay_watch_checks = DEFAULT_DELAY_CHECKS;
ecd2a9
+	condlog(3, "delay_watch_checks = DISABLED (internal default)");
ecd2a9
+	return 0;
ecd2a9
+}
ecd2a9
+
ecd2a9
+extern int
ecd2a9
+select_delay_wait_checks (struct multipath * mp)
ecd2a9
+{
ecd2a9
+	if (mp->mpe && mp->mpe->delay_wait_checks != DELAY_CHECKS_UNDEF) {
ecd2a9
+		mp->delay_wait_checks = mp->mpe->delay_wait_checks;
ecd2a9
+		condlog(3, "delay_wait_checks = %i (multipath setting)",
ecd2a9
+				mp->delay_wait_checks);
ecd2a9
+		return 0;
ecd2a9
+	}
ecd2a9
+	if (mp->hwe && mp->hwe->delay_wait_checks != DELAY_CHECKS_UNDEF) {
ecd2a9
+		mp->delay_wait_checks = mp->hwe->delay_wait_checks;
ecd2a9
+		condlog(3, "delay_wait_checks = %i (controler setting)",
ecd2a9
+				mp->delay_wait_checks);
ecd2a9
+		return 0;
ecd2a9
+	}
ecd2a9
+	if (conf->delay_wait_checks != DELAY_CHECKS_UNDEF) {
ecd2a9
+		mp->delay_wait_checks = conf->delay_wait_checks;
ecd2a9
+		condlog(3, "delay_wait_checks = %i (config file default)",
ecd2a9
+				mp->delay_wait_checks);
ecd2a9
+		return 0;
ecd2a9
+	}
ecd2a9
+	mp->delay_wait_checks = DEFAULT_DELAY_CHECKS;
ecd2a9
+	condlog(3, "delay_wait_checks = DISABLED (internal default)");
ecd2a9
+	return 0;
ecd2a9
+}
ecd2a9
Index: multipath-tools-130222/libmultipath/propsel.h
ecd2a9
===================================================================
ecd2a9
--- multipath-tools-130222.orig/libmultipath/propsel.h
ecd2a9
+++ multipath-tools-130222/libmultipath/propsel.h
ecd2a9
@@ -21,3 +21,5 @@ int select_reservation_key(struct multip
ecd2a9
 int select_retain_hwhandler (struct multipath * mp);
ecd2a9
 int select_detect_prio(struct path * pp);
ecd2a9
 int select_deferred_remove(struct multipath *mp);
ecd2a9
+int select_delay_watch_checks (struct multipath * mp);
ecd2a9
+int select_delay_wait_checks (struct multipath * mp);
ecd2a9
Index: multipath-tools-130222/multipathd/main.c
ecd2a9
===================================================================
ecd2a9
--- multipath-tools-130222.orig/multipathd/main.c
ecd2a9
+++ multipath-tools-130222/multipathd/main.c
ecd2a9
@@ -188,7 +188,8 @@ sync_map_state(struct multipath *mpp)
ecd2a9
 	vector_foreach_slot (mpp->pg, pgp, i){
ecd2a9
 		vector_foreach_slot (pgp->paths, pp, j){
ecd2a9
 			if (pp->state == PATH_UNCHECKED || 
ecd2a9
-			    pp->state == PATH_WILD)
ecd2a9
+			    pp->state == PATH_WILD ||
ecd2a9
+			    pp->state == PATH_DELAYED)
ecd2a9
 				continue;
ecd2a9
 			if ((pp->dmstate == PSTATE_FAILED ||
ecd2a9
 			     pp->dmstate == PSTATE_UNDEF) &&
ecd2a9
@@ -1165,6 +1166,16 @@ check_path (struct vectors * vecs, struc
ecd2a9
 	if (!pp->mpp)
ecd2a9
 		return;
ecd2a9
 
ecd2a9
+	if ((newstate == PATH_UP || newstate == PATH_GHOST) &&
ecd2a9
+	     pp->wait_checks > 0) {
ecd2a9
+		if (pp->mpp && pp->mpp->nr_active > 0) {
ecd2a9
+			pp->state = PATH_DELAYED;
ecd2a9
+			pp->wait_checks--;
ecd2a9
+			return;
ecd2a9
+		} else
ecd2a9
+			pp->wait_checks = 0;
ecd2a9
+	}
ecd2a9
+
ecd2a9
 	pp->chkrstate = newstate;
ecd2a9
 	if (newstate != pp->state) {
ecd2a9
 		int oldstate = pp->state;
ecd2a9
@@ -1182,9 +1193,14 @@ check_path (struct vectors * vecs, struc
ecd2a9
 			 * proactively fail path in the DM
ecd2a9
 			 */
ecd2a9
 			if (oldstate == PATH_UP ||
ecd2a9
-			    oldstate == PATH_GHOST)
ecd2a9
+			    oldstate == PATH_GHOST) {
ecd2a9
 				fail_path(pp, 1);
ecd2a9
-			else
ecd2a9
+				if (pp->mpp->delay_wait_checks > 0 &&
ecd2a9
+				    pp->watch_checks > 0) {
ecd2a9
+					pp->wait_checks = pp->mpp->delay_wait_checks;
ecd2a9
+					pp->watch_checks = 0;
ecd2a9
+				}
ecd2a9
+			}else
ecd2a9
 				fail_path(pp, 0);
ecd2a9
 
ecd2a9
 			/*
ecd2a9
@@ -1211,11 +1227,15 @@ check_path (struct vectors * vecs, struc
ecd2a9
 		 * reinstate this path
ecd2a9
 		 */
ecd2a9
 		if (oldstate != PATH_UP &&
ecd2a9
-		    oldstate != PATH_GHOST)
ecd2a9
+		    oldstate != PATH_GHOST) {
ecd2a9
+			if (pp->mpp->delay_watch_checks > 0)
ecd2a9
+				pp->watch_checks = pp->mpp->delay_watch_checks;
ecd2a9
 			reinstate_path(pp, 1);
ecd2a9
-		else
ecd2a9
+		} else {
ecd2a9
+			if (pp->watch_checks > 0)
ecd2a9
+				pp->watch_checks--;
ecd2a9
 			reinstate_path(pp, 0);
ecd2a9
-
ecd2a9
+		}
ecd2a9
 		new_path_up = 1;
ecd2a9
 
ecd2a9
 		if (oldchkrstate != PATH_UP && oldchkrstate != PATH_GHOST)
ecd2a9
@@ -1245,6 +1265,8 @@ check_path (struct vectors * vecs, struc
ecd2a9
 				else
ecd2a9
 					pp->checkint = conf->max_checkint;
ecd2a9
 			}
ecd2a9
+			if (pp->watch_checks > 0)
ecd2a9
+				pp->watch_checks--;
ecd2a9
 			pp->tick = pp->checkint;
ecd2a9
 			condlog(4, "%s: delay next check %is",
ecd2a9
 				pp->dev_t, pp->tick);
ecd2a9
Index: multipath-tools-130222/multipath.conf.annotated
ecd2a9
===================================================================
ecd2a9
--- multipath-tools-130222.orig/multipath.conf.annotated
ecd2a9
+++ multipath-tools-130222/multipath.conf.annotated
ecd2a9
@@ -242,6 +242,30 @@
ecd2a9
 #	#           files, just as if it was in /etc/multipath.conf
ecd2a9
 #	# values  : "" or a fully qualified pathname
ecd2a9
 #	# default : "/etc/multipath/conf.d"
ecd2a9
+#
ecd2a9
+#	#
ecd2a9
+#	# name    : delay_watch_checks
ecd2a9
+#	# scope   : multipathd
ecd2a9
+#	# desc    : If set to a value greater than 0, multipathd will watch
ecd2a9
+#	#           paths that have recently become valid for this many
ecd2a9
+#	#           checks.  If they fail again while they are being watched,
ecd2a9
+#	#           when they next become valid, they will not be used until
ecd2a9
+#	#           they have stayed up for delay_wait_checks checks.
ecd2a9
+#	# values  : no|<n> > 0
ecd2a9
+#	# default : no
ecd2a9
+#	delay_watch_checks 12
ecd2a9
+#
ecd2a9
+#	#
ecd2a9
+#	# name    : delay_wait_checks
ecd2a9
+#	# scope   : multipathd
ecd2a9
+#	# desc    : If set to a value greater than 0, when a device that has
ecd2a9
+#	#           recently come back online fails again within
ecd2a9
+#	#           delay_watch_checks checks, the next time it comes back
ecd2a9
+#	#           online, it will marked and delayed, and not used until
ecd2a9
+#	#           it has passed delay_wait_checks checks.
ecd2a9
+#	# values  : no|<n> > 0
ecd2a9
+#	# default : no
ecd2a9
+#	delay_wait_checks 12
ecd2a9
 #}
ecd2a9
 #	
ecd2a9
 ##
ecd2a9
@@ -383,6 +407,13 @@
ecd2a9
 #		#
ecd2a9
 #		flush_on_last_del       yes
ecd2a9
 #
ecd2a9
+#		#
ecd2a9
+#		# name    : delay_watch_checks
ecd2a9
+#		# See defualts section for information.
ecd2a9
+#
ecd2a9
+#		#
ecd2a9
+#		# name    : delay_wait_checks
ecd2a9
+#		# See defualts section for information.
ecd2a9
 #	}
ecd2a9
 #	multipath {
ecd2a9
 #		wwid	1DEC_____321816758474
ecd2a9
@@ -566,6 +597,15 @@
ecd2a9
 #		#           before removing it from the system.
ecd2a9
 #		# values  : n > 0
ecd2a9
 #		dev_loss_tmo 600
ecd2a9
+#
ecd2a9
+#		#
ecd2a9
+#		# name    : delay_watch_checks
ecd2a9
+#		# See defaults section for information.
ecd2a9
+#
ecd2a9
+#		#
ecd2a9
+#		# name    : delay_wait_checks
ecd2a9
+#		# See defaults section for information.
ecd2a9
+#
ecd2a9
 #	}
ecd2a9
 #	device {
ecd2a9
 #		vendor			"COMPAQ  "
ecd2a9
Index: multipath-tools-130222/multipath.conf.defaults
ecd2a9
===================================================================
ecd2a9
--- multipath-tools-130222.orig/multipath.conf.defaults
ecd2a9
+++ multipath-tools-130222/multipath.conf.defaults
ecd2a9
@@ -27,6 +27,8 @@
ecd2a9
 #	retain_attached_hw_handler no
ecd2a9
 #	detect_prio no
ecd2a9
 #	config_dir "/etc/multipath/conf.d"
ecd2a9
+#	delay_watch_checks no
ecd2a9
+#	delay_wait_checks no
ecd2a9
 #}
ecd2a9
 #blacklist {
ecd2a9
 #	devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
ecd2a9
Index: multipath-tools-130222/multipath/multipath.conf.5
ecd2a9
===================================================================
ecd2a9
--- multipath-tools-130222.orig/multipath/multipath.conf.5
ecd2a9
+++ multipath-tools-130222/multipath/multipath.conf.5
ecd2a9
@@ -459,6 +459,25 @@ alphabetically for file ending in ".conf
ecd2a9
 information from them, just as if it was in /etc/multipath.conf.  config_dir
ecd2a9
 must either be "" or a fully qualified directory name. Default is
ecd2a9
 .I "/etc/multipath/conf.d"
ecd2a9
+.TP
ecd2a9
+.B delay_watch_checks
ecd2a9
+If set to a value greater than 0, multipathd will watch paths that have
ecd2a9
+recently become valid for this many checks.  If they fail again while they are
ecd2a9
+being watched, when they next become valid, they will not be used until they
ecd2a9
+have stayed up for
ecd2a9
+.I delay_wait_checks
ecd2a9
+checks. Default is
ecd2a9
+.I no
ecd2a9
+.TP
ecd2a9
+.B delay_wait_checks
ecd2a9
+If set to a value greater than 0, when a device that has recently come back
ecd2a9
+online fails again within
ecd2a9
+.I delay_watch_checks
ecd2a9
+checks, the next time it comes back online, it will marked and delayed, and not
ecd2a9
+used until it has passed
ecd2a9
+.I delay_wait_checks
ecd2a9
+checks. Default is
ecd2a9
+.I no
ecd2a9
 .
ecd2a9
 .SH "blacklist section"
ecd2a9
 The
ecd2a9
@@ -562,6 +581,10 @@ section:
ecd2a9
 .B reservation_key
ecd2a9
 .TP
ecd2a9
 .B deferred_remove
ecd2a9
+.TP
ecd2a9
+.B delay_watch_checks
ecd2a9
+.TP
ecd2a9
+.B delay_wait_checks
ecd2a9
 .RE
ecd2a9
 .PD
ecd2a9
 .LP
ecd2a9
@@ -654,6 +677,10 @@ section:
ecd2a9
 .B detect_prio
ecd2a9
 .TP
ecd2a9
 .B deferred_remove
ecd2a9
+.TP
ecd2a9
+.B delay_watch_checks
ecd2a9
+.TP
ecd2a9
+.B delay_wait_checks
ecd2a9
 .RE
ecd2a9
 .PD
ecd2a9
 .LP
ecd2a9
Index: multipath-tools-130222/libmultipath/checkers.c
ecd2a9
===================================================================
ecd2a9
--- multipath-tools-130222.orig/libmultipath/checkers.c
ecd2a9
+++ multipath-tools-130222/libmultipath/checkers.c
ecd2a9
@@ -16,7 +16,8 @@ char *checker_state_names[] = {
ecd2a9
       "up",
ecd2a9
       "shaky",
ecd2a9
       "ghost",
ecd2a9
-      "pending"
ecd2a9
+      "pending",
ecd2a9
+      "delayed"
ecd2a9
 };
ecd2a9
 
ecd2a9
 static LIST_HEAD(checkers);
ecd2a9
Index: multipath-tools-130222/libmultipath/config.c
ecd2a9
===================================================================
ecd2a9
--- multipath-tools-130222.orig/libmultipath/config.c
ecd2a9
+++ multipath-tools-130222/libmultipath/config.c
ecd2a9
@@ -341,6 +341,8 @@ merge_hwe (struct hwentry * dst, struct
ecd2a9
 	merge_num(retain_hwhandler);
ecd2a9
 	merge_num(detect_prio);
ecd2a9
 	merge_num(deferred_remove);
ecd2a9
+	merge_num(delay_watch_checks);
ecd2a9
+	merge_num(delay_wait_checks);
ecd2a9
 
ecd2a9
 	/*
ecd2a9
 	 * Make sure features is consistent with
ecd2a9
@@ -399,6 +401,8 @@ overwrite_hwe (struct hwentry * dst, str
ecd2a9
 	overwrite_num(retain_hwhandler);
ecd2a9
 	overwrite_num(detect_prio);
ecd2a9
 	overwrite_num(deferred_remove);
ecd2a9
+	overwrite_num(delay_watch_checks);
ecd2a9
+	overwrite_num(delay_wait_checks);
ecd2a9
 
ecd2a9
 	/*
ecd2a9
 	 * Make sure features is consistent with