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