--- 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