Blame SOURCES/0136-RHBZ-1304687-wait-for-map-add.patch

4728c8
---
4728c8
 libmultipath/config.c      |    1 
4728c8
 libmultipath/config.h      |    2 
4728c8
 libmultipath/configure.c   |    4 +
4728c8
 libmultipath/defaults.h    |    1 
4728c8
 libmultipath/dict.c        |   25 ++++++++
4728c8
 libmultipath/structs.h     |    2 
4728c8
 multipath.conf.defaults    |    1 
4728c8
 multipath/multipath.conf.5 |    8 ++
4728c8
 multipathd/cli_handlers.c  |   65 ++++++++++++++++++----
4728c8
 multipathd/main.c          |  132 +++++++++++++++++++++++++++++++++++++++++++--
4728c8
 multipathd/main.h          |    1 
4728c8
 11 files changed, 229 insertions(+), 13 deletions(-)
4728c8
4728c8
Index: multipath-tools-130222/libmultipath/configure.c
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/configure.c
4728c8
+++ multipath-tools-130222/libmultipath/configure.c
4728c8
@@ -701,6 +701,10 @@ domap (struct multipath * mpp, char * pa
4728c8
 			 */
4728c8
 			if (mpp->action != ACT_CREATE)
4728c8
 				mpp->action = ACT_NOTHING;
4728c8
+			else {
4728c8
+				mpp->wait_for_udev = 1;
4728c8
+				mpp->uev_wait_tick = conf->uev_wait_timeout;
4728c8
+			}
4728c8
 		}
4728c8
 		dm_setgeometry(mpp);
4728c8
 		return DOMAP_OK;
4728c8
Index: multipath-tools-130222/libmultipath/structs.h
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/structs.h
4728c8
+++ multipath-tools-130222/libmultipath/structs.h
4728c8
@@ -217,6 +217,8 @@ struct multipath {
4728c8
 	int bestpg;
4728c8
 	int queuedio;
4728c8
 	int action;
4728c8
+	int wait_for_udev;
4728c8
+	int uev_wait_tick;
4728c8
 	int pgfailback;
4728c8
 	int failback_tick;
4728c8
 	int rr_weight;
4728c8
Index: multipath-tools-130222/multipathd/cli_handlers.c
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/multipathd/cli_handlers.c
4728c8
+++ multipath-tools-130222/multipathd/cli_handlers.c
4728c8
@@ -548,6 +548,11 @@ cli_reload(void *v, char **reply, int *l
4728c8
 		condlog(0, "%s: invalid map name. cannot reload", mapname);
4728c8
 		return 1;
4728c8
 	}
4728c8
+	if (mpp->wait_for_udev) {
4728c8
+		condlog(2, "%s: device not fully created, failing reload",
4728c8
+			mpp->alias);
4728c8
+		return 1;
4728c8
+	}
4728c8
 
4728c8
 	return reload_map(vecs, mpp, 0);
4728c8
 }
4728c8
@@ -592,6 +597,12 @@ cli_resize(void *v, char **reply, int *l
4728c8
 		return 1;
4728c8
 	}
4728c8
 
4728c8
+	if (mpp->wait_for_udev) {
4728c8
+		condlog(2, "%s: device not fully created, failing resize",
4728c8
+			mpp->alias);
4728c8
+		return 1;
4728c8
+	}
4728c8
+
4728c8
 	pgp = VECTOR_SLOT(mpp->pg, 0);
4728c8
 
4728c8
 	if (!pgp){
4728c8
@@ -756,6 +767,12 @@ cli_reconfigure(void * v, char ** reply,
4728c8
 {
4728c8
 	struct vectors * vecs = (struct vectors *)data;
4728c8
 
4728c8
+	if (need_to_delay_reconfig(vecs)) {
4728c8
+		conf->delayed_reconfig = 1;
4728c8
+		condlog(2, "delaying reconfigure (operator)");
4728c8
+		return 0;
4728c8
+	}
4728c8
+
4728c8
 	condlog(2, "reconfigure (operator)");
4728c8
 
4728c8
 	return reconfigure(vecs);
4728c8
@@ -766,17 +783,25 @@ cli_suspend(void * v, char ** reply, int
4728c8
 {
4728c8
 	struct vectors * vecs = (struct vectors *)data;
4728c8
 	char * param = get_keyparam(v, MAP);
4728c8
-	int r = dm_simplecmd_noflush(DM_DEVICE_SUSPEND, param, 0);
4728c8
+	int r;
4728c8
+	struct multipath * mpp;
4728c8
 
4728c8
 	param = convert_dev(param, 0);
4728c8
-	condlog(2, "%s: suspend (operator)", param);
4728c8
+	mpp = find_mp_by_alias(vecs->mpvec, param);
4728c8
+	if (!mpp)
4728c8
+		return 1;
4728c8
 
4728c8
-	if (!r) /* error */
4728c8
+	if (mpp->wait_for_udev) {
4728c8
+		condlog(2, "%s: device not fully created, failing suspend",
4728c8
+			mpp->alias);
4728c8
 		return 1;
4728c8
+	}
4728c8
 
4728c8
-	struct multipath * mpp = find_mp_by_alias(vecs->mpvec, param);
4728c8
+	r = dm_simplecmd_noflush(DM_DEVICE_SUSPEND, param, 0);
4728c8
 
4728c8
-	if (!mpp)
4728c8
+	condlog(2, "%s: suspend (operator)", param);
4728c8
+
4728c8
+	if (!r) /* error */
4728c8
 		return 1;
4728c8
 
4728c8
 	dm_get_info(param, &mpp->dmi);
4728c8
@@ -788,17 +813,25 @@ cli_resume(void * v, char ** reply, int
4728c8
 {
4728c8
 	struct vectors * vecs = (struct vectors *)data;
4728c8
 	char * param = get_keyparam(v, MAP);
4728c8
-	int r = dm_simplecmd_noflush(DM_DEVICE_RESUME, param, 0);
4728c8
+	int r;
4728c8
+	struct multipath * mpp;
4728c8
 
4728c8
 	param = convert_dev(param, 0);
4728c8
-	condlog(2, "%s: resume (operator)", param);
4728c8
+	mpp = find_mp_by_alias(vecs->mpvec, param);
4728c8
+	if (!mpp)
4728c8
+		return 1;
4728c8
 
4728c8
-	if (!r) /* error */
4728c8
+	if (mpp->wait_for_udev) {
4728c8
+		condlog(2, "%s: device not fully created, failing resume",
4728c8
+			mpp->alias);
4728c8
 		return 1;
4728c8
+	}
4728c8
 
4728c8
-	struct multipath * mpp = find_mp_by_alias(vecs->mpvec, param);
4728c8
+	r = dm_simplecmd_noflush(DM_DEVICE_RESUME, param, 0);
4728c8
 
4728c8
-	if (!mpp)
4728c8
+	condlog(2, "%s: resume (operator)", param);
4728c8
+
4728c8
+	if (!r) /* error */
4728c8
 		return 1;
4728c8
 
4728c8
 	dm_get_info(param, &mpp->dmi);
4728c8
@@ -831,9 +864,21 @@ cli_reinstate(void * v, char ** reply, i
4728c8
 int
4728c8
 cli_reassign (void * v, char ** reply, int * len, void * data)
4728c8
 {
4728c8
+	struct vectors * vecs = (struct vectors *)data;
4728c8
 	char * param = get_keyparam(v, MAP);
4728c8
+	struct multipath *mpp;
4728c8
 
4728c8
 	param = convert_dev(param, 0);
4728c8
+	mpp = find_mp_by_alias(vecs->mpvec, param);
4728c8
+	if (!mpp)
4728c8
+		return 1;
4728c8
+
4728c8
+	if (mpp->wait_for_udev) {
4728c8
+		condlog(2, "%s: device not fully created, failing reassign",
4728c8
+			mpp->alias);
4728c8
+		return 1;
4728c8
+	}
4728c8
+
4728c8
 	condlog(3, "%s: reset devices (operator)", param);
4728c8
 
4728c8
 	dm_reassign(param);
4728c8
Index: multipath-tools-130222/libmultipath/config.h
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/config.h
4728c8
+++ multipath-tools-130222/libmultipath/config.h
4728c8
@@ -142,6 +142,8 @@ struct config {
4728c8
 	int retrigger_tries;
4728c8
 	int retrigger_delay;
4728c8
 	int new_bindings_in_boot;
4728c8
+	int delayed_reconfig;
4728c8
+	int uev_wait_timeout;
4728c8
 	unsigned int version[3];
4728c8
 
4728c8
 	char * dev;
4728c8
Index: multipath-tools-130222/multipathd/main.c
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/multipathd/main.c
4728c8
+++ multipath-tools-130222/multipathd/main.c
4728c8
@@ -251,6 +251,47 @@ flush_map(struct multipath * mpp, struct
4728c8
 	return 0;
4728c8
 }
4728c8
 
4728c8
+int
4728c8
+update_map (struct multipath *mpp, struct vectors *vecs)
4728c8
+{
4728c8
+	int retries = 3;
4728c8
+	char params[PARAMS_SIZE] = {0};
4728c8
+
4728c8
+retry:
4728c8
+	condlog(4, "%s: updating new map", mpp->alias);
4728c8
+	if (adopt_paths(vecs->pathvec, mpp, 1)) {
4728c8
+		condlog(0, "%s: failed to adopt paths for new map update",
4728c8
+			mpp->alias);
4728c8
+		retries = -1;
4728c8
+		goto fail;
4728c8
+	}
4728c8
+	verify_paths(mpp, vecs, NULL);
4728c8
+	mpp->flush_on_last_del = FLUSH_UNDEF;
4728c8
+	mpp->action = ACT_RELOAD;
4728c8
+
4728c8
+	if (setup_map(mpp, params, PARAMS_SIZE)) {
4728c8
+		condlog(0, "%s: failed to setup new map in update", mpp->alias);
4728c8
+		retries = -1;
4728c8
+		goto fail;
4728c8
+	}
4728c8
+	if (domap(mpp, params) <= 0 && retries-- > 0) {
4728c8
+		condlog(0, "%s: map_udate sleep", mpp->alias);
4728c8
+		sleep(1);
4728c8
+		goto retry;
4728c8
+	}
4728c8
+	dm_lib_release();
4728c8
+
4728c8
+fail:
4728c8
+	if (setup_multipath(vecs, mpp))
4728c8
+		return 1;
4728c8
+
4728c8
+	sync_map_state(mpp);
4728c8
+
4728c8
+	if (retries < 0)
4728c8
+		condlog(0, "%s: failed reload in new map update", mpp->alias);
4728c8
+	return 0;
4728c8
+}
4728c8
+
4728c8
 static int
4728c8
 uev_add_map (struct uevent * uev, struct vectors * vecs)
4728c8
 {
4728c8
@@ -293,6 +334,20 @@ ev_add_map (char * dev, char * alias, st
4728c8
 	mpp = find_mp_by_alias(vecs->mpvec, alias);
4728c8
 
4728c8
 	if (mpp) {
4728c8
+		if (mpp->wait_for_udev > 1) {
4728c8
+			if (update_map(mpp, vecs))
4728c8
+			/* setup multipathd removed the map */
4728c8
+				return 1;
4728c8
+		}
4728c8
+		if (mpp->wait_for_udev) {
4728c8
+			mpp->wait_for_udev = 0;
4728c8
+			if (conf->delayed_reconfig &&
4728c8
+			    !need_to_delay_reconfig(vecs)) {
4728c8
+				condlog(2, "reconfigure (delayed)");
4728c8
+				reconfigure(vecs);
4728c8
+				return 0;
4728c8
+			}
4728c8
+		}
4728c8
 		/*
4728c8
 		 * Not really an error -- we generate our own uevent
4728c8
 		 * if we create a multipath mapped device as a result
4728c8
@@ -471,7 +526,14 @@ ev_add_path (struct path * pp, struct ve
4728c8
 		condlog(0, "%s: failed to get path uid", pp->dev);
4728c8
 		goto fail; /* leave path added to pathvec */
4728c8
 	}
4728c8
-	mpp = pp->mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid);
4728c8
+	mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid);
4728c8
+	if (mpp && mpp->wait_for_udev) {
4728c8
+		mpp->wait_for_udev = 2;
4728c8
+		orphan_path(pp);
4728c8
+		return 0;
4728c8
+	}
4728c8
+
4728c8
+	pp->mpp = mpp;
4728c8
 rescan:
4728c8
 	if (mpp) {
4728c8
 		if ((!pp->size) || (mpp->size != pp->size)) {
4728c8
@@ -670,6 +732,12 @@ ev_remove_path (struct path *pp, struct
4728c8
 				" removal of path %s", mpp->alias, pp->dev);
4728c8
 			goto fail;
4728c8
 		}
4728c8
+
4728c8
+		if (mpp->wait_for_udev) {
4728c8
+			mpp->wait_for_udev = 2;
4728c8
+			goto out;
4728c8
+		}
4728c8
+
4728c8
 		/*
4728c8
 		 * reload the map
4728c8
 		 */
4728c8
@@ -731,6 +799,11 @@ uev_update_path (struct uevent *uev, str
4728c8
 		condlog(2, "%s: update path write_protect to '%d' (uevent)",
4728c8
 			uev->kernel, ro);
4728c8
 		if (pp->mpp) {
4728c8
+			if (pp->mpp->wait_for_udev) {
4728c8
+				pp->mpp->wait_for_udev = 2;
4728c8
+				return 0;
4728c8
+			}
4728c8
+
4728c8
 			retval = reload_map(vecs, pp->mpp, 0);
4728c8
 
4728c8
 			condlog(2, "%s: map %s reloaded (retval %d)",
4728c8
@@ -1063,6 +1136,33 @@ followover_should_failback(struct path *
4728c8
 }
4728c8
 
4728c8
 static void
4728c8
+missing_uev_wait_tick(struct vectors *vecs)
4728c8
+{
4728c8
+	struct multipath * mpp;
4728c8
+	unsigned int i;
4728c8
+	int timed_out = 0;
4728c8
+
4728c8
+	vector_foreach_slot (vecs->mpvec, mpp, i) {
4728c8
+		if (mpp->wait_for_udev && --mpp->uev_wait_tick <= 0) {
4728c8
+			timed_out = 1;
4728c8
+			condlog(0, "%s: timeout waiting on creation uevent. enabling reloads", mpp->alias);
4728c8
+			if (mpp->wait_for_udev > 1 && update_map(mpp, vecs)) {
4728c8
+				/* update_map removed map */
4728c8
+				i--;
4728c8
+				continue;
4728c8
+			}
4728c8
+			mpp->wait_for_udev = 0;
4728c8
+		}
4728c8
+	}
4728c8
+
4728c8
+	if (timed_out && conf->delayed_reconfig &&
4728c8
+	    !need_to_delay_reconfig(vecs)) {
4728c8
+		condlog(2, "reconfigure (delayed)");
4728c8
+		reconfigure(vecs);
4728c8
+	}
4728c8
+}
4728c8
+
4728c8
+static void
4728c8
 defered_failback_tick (vector mpvec)
4728c8
 {
4728c8
 	struct multipath * mpp;
4728c8
@@ -1316,6 +1416,9 @@ check_path (struct vectors * vecs, struc
4728c8
 
4728c8
 	pp->state = newstate;
4728c8
 
4728c8
+
4728c8
+	if (pp->mpp->wait_for_udev)
4728c8
+		return;
4728c8
 	/*
4728c8
 	 * path prio refreshing
4728c8
 	 */
4728c8
@@ -1369,6 +1472,7 @@ checkerloop (void *ap)
4728c8
 		if (vecs->mpvec) {
4728c8
 			defered_failback_tick(vecs->mpvec);
4728c8
 			retry_count_tick(vecs->mpvec);
4728c8
+			missing_uev_wait_tick(vecs);
4728c8
 		}
4728c8
 		if (count)
4728c8
 			count--;
4728c8
@@ -1465,6 +1569,22 @@ configure (struct vectors * vecs, int st
4728c8
 }
4728c8
 
4728c8
 int
4728c8
+need_to_delay_reconfig(struct vectors * vecs)
4728c8
+{
4728c8
+	struct multipath *mpp;
4728c8
+	int i;
4728c8
+
4728c8
+	if (!VECTOR_SIZE(vecs->mpvec))
4728c8
+		return 0;
4728c8
+
4728c8
+	vector_foreach_slot(vecs->mpvec, mpp, i) {
4728c8
+		if (mpp->wait_for_udev)
4728c8
+			return 1;
4728c8
+	}
4728c8
+	return 0;
4728c8
+}
4728c8
+
4728c8
+int
4728c8
 reconfigure (struct vectors * vecs)
4728c8
 {
4728c8
 	struct config * old = conf;
4728c8
@@ -1544,12 +1664,18 @@ void
4728c8
 handle_signals(void)
4728c8
 {
4728c8
 	if (reconfig_sig && running_state == DAEMON_RUNNING) {
4728c8
-		condlog(2, "reconfigure (signal)");
4728c8
 		pthread_cleanup_push(cleanup_lock,
4728c8
 				&gvecs->lock);
4728c8
 		lock(gvecs->lock);
4728c8
 		pthread_testcancel();
4728c8
-		reconfigure(gvecs);
4728c8
+		if (need_to_delay_reconfig(gvecs)) {
4728c8
+			conf->delayed_reconfig = 1;
4728c8
+			condlog(2, "delaying reconfigure (signal)");
4728c8
+		}
4728c8
+		else {
4728c8
+			condlog(2, "reconfigure (signal)");
4728c8
+			reconfigure(gvecs);
4728c8
+		}
4728c8
 		lock_cleanup_pop(gvecs->lock);
4728c8
 	}
4728c8
 	if (log_reset_sig) {
4728c8
Index: multipath-tools-130222/multipathd/main.h
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/multipathd/main.h
4728c8
+++ multipath-tools-130222/multipathd/main.h
4728c8
@@ -18,6 +18,7 @@ extern pid_t daemon_pid;
4728c8
 
4728c8
 void exit_daemon(void);
4728c8
 const char * daemon_status(void);
4728c8
+int need_to_delay_reconfig (struct vectors *);
4728c8
 int reconfigure (struct vectors *);
4728c8
 int ev_add_path (struct path *, struct vectors *);
4728c8
 int ev_remove_path (struct path *, struct vectors *);
4728c8
Index: multipath-tools-130222/libmultipath/config.c
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/config.c
4728c8
+++ multipath-tools-130222/libmultipath/config.c
4728c8
@@ -676,6 +676,7 @@ load_config (char * file, struct udev *u
4728c8
 	conf->retrigger_tries = DEFAULT_RETRIGGER_TRIES;
4728c8
 	conf->retrigger_delay = DEFAULT_RETRIGGER_DELAY;
4728c8
 	conf->new_bindings_in_boot = 0;
4728c8
+	conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT;
4728c8
 
4728c8
 	/*
4728c8
 	 * preload default hwtable
4728c8
Index: multipath-tools-130222/libmultipath/defaults.h
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/defaults.h
4728c8
+++ multipath-tools-130222/libmultipath/defaults.h
4728c8
@@ -23,6 +23,7 @@
4728c8
 #define DEFAULT_DELAY_CHECKS DELAY_CHECKS_OFF
4728c8
 #define DEFAULT_RETRIGGER_DELAY 10
4728c8
 #define DEFAULT_RETRIGGER_TRIES 3
4728c8
+#define DEFAULT_UEV_WAIT_TIMEOUT 30
4728c8
 
4728c8
 #define DEFAULT_CHECKINT	5
4728c8
 #define MAX_CHECKINT(a)		(a << 2)
4728c8
Index: multipath-tools-130222/libmultipath/dict.c
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/libmultipath/dict.c
4728c8
+++ multipath-tools-130222/libmultipath/dict.c
4728c8
@@ -872,6 +872,24 @@ def_retrigger_delay_handler(vector strve
4728c8
 }
4728c8
 
4728c8
 static int
4728c8
+def_uev_wait_timeout_handler(vector strvec)
4728c8
+{
4728c8
+	char *buff;
4728c8
+
4728c8
+	buff = set_value(strvec);
4728c8
+
4728c8
+	if (!buff)
4728c8
+		return 1;
4728c8
+
4728c8
+	conf->uev_wait_timeout = atoi(buff);
4728c8
+	if (conf->uev_wait_timeout <= 0)
4728c8
+		conf->uev_wait_timeout = DEFAULT_UEV_WAIT_TIMEOUT;
4728c8
+	FREE(buff);
4728c8
+
4728c8
+	return 0;
4728c8
+}
4728c8
+
4728c8
+static int
4728c8
 def_new_bindings_in_boot_handler(vector strvec)
4728c8
 {
4728c8
 	char * buff;
4728c8
@@ -3261,6 +3279,12 @@ snprint_def_retrigger_delay (char * buff
4728c8
 }
4728c8
 
4728c8
 static int
4728c8
+snprint_def_uev_wait_timeout (char * buff, int len, void * data)
4728c8
+{
4728c8
+	return snprintf(buff, len, "%i", conf->uev_wait_timeout);
4728c8
+}
4728c8
+
4728c8
+static int
4728c8
 snprint_def_new_bindings_in_boot(char * buff, int len, void * data)
4728c8
 {
4728c8
 	if (conf->new_bindings_in_boot == 1)
4728c8
@@ -3345,6 +3369,7 @@ init_keywords(void)
4728c8
 	install_keyword("delay_wait_checks", &def_delay_wait_checks_handler, &snprint_def_delay_wait_checks);
4728c8
 	install_keyword("retrigger_tries", &def_retrigger_tries_handler, &snprint_def_retrigger_tries);
4728c8
 	install_keyword("retrigger_delay", &def_retrigger_delay_handler, &snprint_def_retrigger_delay);
4728c8
+	install_keyword("missing_uev_wait_timeout", &def_uev_wait_timeout_handler, &snprint_def_uev_wait_timeout);
4728c8
 	install_keyword("new_bindings_in_boot", &def_new_bindings_in_boot_handler, &snprint_def_new_bindings_in_boot);
4728c8
 	__deprecated install_keyword("default_selector", &def_selector_handler, NULL);
4728c8
 	__deprecated install_keyword("default_path_grouping_policy", &def_pgpolicy_handler, NULL);
4728c8
Index: multipath-tools-130222/multipath.conf.defaults
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/multipath.conf.defaults
4728c8
+++ multipath-tools-130222/multipath.conf.defaults
4728c8
@@ -29,6 +29,7 @@
4728c8
 #	config_dir "/etc/multipath/conf.d"
4728c8
 #	delay_watch_checks no
4728c8
 #	delay_wait_checks no
4728c8
+#	missing_uev_wait_timeout 30
4728c8
 #}
4728c8
 #blacklist {
4728c8
 #	devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
4728c8
Index: multipath-tools-130222/multipath/multipath.conf.5
4728c8
===================================================================
4728c8
--- multipath-tools-130222.orig/multipath/multipath.conf.5
4728c8
+++ multipath-tools-130222/multipath/multipath.conf.5
4728c8
@@ -478,6 +478,14 @@ used until it has passed
4728c8
 .I delay_wait_checks
4728c8
 checks. Default is
4728c8
 .I no
4728c8
+.TP
4728c8
+.B missing_uev_wait_timeout
4728c8
+Controls how many seconds multipathd will wait, after a new multipath device
4728c8
+is created, to receive a change event from udev for the device, before
4728c8
+automatically enabling device reloads. Usually multipathd will delay reloads
4728c8
+on a device until it receives a change uevent from the initial table load. The
4728c8
+default is
4728c8
+.I 30
4728c8
 .
4728c8
 .SH "blacklist section"
4728c8
 The