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