Setting a device handler only works if retain_attached_hw_handler is 'no', or if the kernel didn't auto-assign a handler. If this is not the case, don't even attempt to set a different handler. This requires reading the sysfs "dh_state" path attribute. For internal consistency, this attribute must be updated after domap(). Signed-off-by: Martin Wilck <mwilck@xxxxxxxx> --- libmultipath/configure.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++- libmultipath/discovery.c | 4 ++++ libmultipath/propsel.c | 15 ++++++++++++++ libmultipath/structs.h | 2 ++ 4 files changed, 72 insertions(+), 1 deletion(-) diff --git a/libmultipath/configure.c b/libmultipath/configure.c index 74b6f52a..55dbb261 100644 --- a/libmultipath/configure.c +++ b/libmultipath/configure.c @@ -275,15 +275,21 @@ int setup_map(struct multipath *mpp, char *params, int params_size) /* * properties selectors + * + * Ordering matters for some properties: + * - features after no_path_retry and retain_hwhandler + * - hwhandler after retain_hwhandler + * No guarantee that this list is complete, check code in + * propsel.c if in doubt. */ conf = get_multipath_config(); select_pgfailback(conf, mpp); select_pgpolicy(conf, mpp); select_selector(conf, mpp); - select_hwhandler(conf, mpp); select_no_path_retry(conf, mpp); select_retain_hwhandler(conf, mpp); select_features(conf, mpp); + select_hwhandler(conf, mpp); select_rr_weight(conf, mpp); select_minio(conf, mpp); select_mode(conf, mpp); @@ -706,6 +712,48 @@ fail: return 1; } +static void +check_dh_state_changed(struct multipath *mp) +{ + struct config *conf; + struct path newp, *pp; + struct pathgroup *pg; + int i, j; + + conf = get_multipath_config(); + + vector_foreach_slot (mp->pg, pg, j) { + vector_foreach_slot (pg->paths, pp, i) { + if (!pp->udev || !strlen(pp->dh_state) || + (conf->retain_hwhandler == RETAIN_HWHANDLER_ON && + strcmp(pp->dh_state, "detached"))) + continue; + + memset(&newp, 0, sizeof(newp)); + memcpy(newp.dev, pp->dev, sizeof(newp.dev)); + newp.udev = udev_device_ref(pp->udev); + + if (pathinfo(&newp, conf, DI_SYSFS) == PATHINFO_OK) { + if (strncmp(newp.dh_state, pp->dh_state, + SCSI_DH_SIZE)) { + condlog(3, "%s: dh_state changed from %s to %s", + pp->dev, + pp->dh_state, + newp.dh_state); + memcpy(pp->dh_state, newp.dh_state, + SCSI_DH_SIZE); + } + } else + condlog(1, "%s: failed to update dh_state", + pp->dev); + + udev_device_unref(newp.udev); + } + } + + put_multipath_config(conf); +} + /* * Return value: */ @@ -828,6 +876,8 @@ int domap(struct multipath *mpp, char *params, int is_daemon) } } dm_setgeometry(mpp); + + check_dh_state_changed(mpp); return DOMAP_OK; } return DOMAP_FAIL; diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c index 663c8eaa..8c0c6a9f 100644 --- a/libmultipath/discovery.c +++ b/libmultipath/discovery.c @@ -1188,6 +1188,10 @@ scsi_sysfs_pathinfo (struct path * pp, vector hwtable) condlog(3, "%s: tgt_node_name = %s", pp->dev, pp->tgt_node_name); + if (sysfs_attr_get_value(parent, "dh_state", + pp->dh_state, sizeof(pp->dh_state)) >= 0) + condlog(3, "%s: dh_state = %s", pp->dev, pp->dh_state); + return 0; } diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c index d609394e..d1b3d416 100644 --- a/libmultipath/propsel.c +++ b/libmultipath/propsel.c @@ -345,7 +345,22 @@ out: int select_hwhandler(struct config *conf, struct multipath *mp) { char *origin; + struct path *pp; + char handler[SCSI_DH_SIZE+2]; + int i; + if (mp->retain_hwhandler != RETAIN_HWHANDLER_OFF) { + vector_foreach_slot(mp->paths, pp, i) { + if (strlen(pp->dh_state) && + strcmp(pp->dh_state, "detached")) { + snprintf(handler, sizeof(handler), + "1 %s", pp->dh_state); + mp->hwhandler = handler; + origin = "(setting: retained by kernel driver)"; + goto out; + } + } + } mp_set_hwe(hwhandler); mp_set_conf(hwhandler); mp_set_default(hwhandler, DEFAULT_HWHANDLER); diff --git a/libmultipath/structs.h b/libmultipath/structs.h index 8ea984d9..4203e2b0 100644 --- a/libmultipath/structs.h +++ b/libmultipath/structs.h @@ -22,6 +22,7 @@ #define SCSI_PRODUCT_SIZE 17 #define SCSI_REV_SIZE 5 #define SCSI_STATE_SIZE 19 +#define SCSI_DH_SIZE 9 /* must hold "detached" */ #define NO_PATH_RETRY_UNDEF 0 #define NO_PATH_RETRY_FAIL -1 @@ -205,6 +206,7 @@ struct path { char rev[SCSI_REV_SIZE]; char serial[SERIAL_SIZE]; char tgt_node_name[NODE_NAME_SIZE]; + char dh_state[SCSI_DH_SIZE]; unsigned long long size; unsigned int checkint; unsigned int tick; -- 2.13.1 -- dm-devel mailing list dm-devel@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/dm-devel