This adds support for the retain_attached_hw_handler feature. When this is set to "yes", if the kernel has already attached a hardware handler to the multipath path devices, multipath will use that one, instead of its configured one. If no hardware handler is already attached, multipath use its configured one, if any. To properly ignore this on older kernels, I had to makes some changes to the version checking code. Signed-off-by: Benjamin Marzinski <bmarzins@xxxxxxxxxx> --- libmultipath/config.c | 5 ++- libmultipath/config.h | 4 +- libmultipath/configure.c | 7 +++- libmultipath/defaults.h | 1 libmultipath/devmapper.c | 34 +++------------------ libmultipath/devmapper.h | 8 ++++- libmultipath/dict.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++ libmultipath/dmparser.c | 3 + libmultipath/propsel.c | 29 +++++++++++++++++- libmultipath/propsel.h | 1 libmultipath/structs.h | 7 ++++ 11 files changed, 138 insertions(+), 35 deletions(-) Index: multipath-tools-120821/libmultipath/config.c =================================================================== --- multipath-tools-120821.orig/libmultipath/config.c +++ multipath-tools-120821/libmultipath/config.c @@ -326,6 +326,7 @@ merge_hwe (struct hwentry * dst, struct merge_num(fast_io_fail); merge_num(dev_loss); merge_num(user_friendly_names); + merge_num(retain_hwhandler); return 0; } @@ -385,6 +386,7 @@ store_hwe (vector hwtable, struct hwentr hwe->fast_io_fail = dhwe->fast_io_fail; hwe->dev_loss = dhwe->dev_loss; hwe->user_friendly_names = dhwe->user_friendly_names; + hwe->retain_hwhandler = dhwe->retain_hwhandler; if (dhwe->bl_product && !(hwe->bl_product = set_param_str(dhwe->bl_product))) goto out; @@ -501,7 +503,7 @@ load_config (char * file) conf->verbosity = DEFAULT_VERBOSITY; conf->udev = udev_new(); - conf->dmrq = dm_drv_get_rq(); + dm_drv_version(conf->version, TGT_MPATH); conf->dev_type = DEV_NONE; conf->minio = DEFAULT_MINIO; conf->minio_rq = DEFAULT_MINIO_RQ; @@ -517,6 +519,7 @@ load_config (char * file) conf->checkint = DEFAULT_CHECKINT; conf->max_checkint = MAX_CHECKINT(conf->checkint); conf->fast_io_fail = 5; + conf->retain_hwhandler = DEFAULT_RETAIN_HWHANDLER; /* * preload default hwtable Index: multipath-tools-120821/libmultipath/config.h =================================================================== --- multipath-tools-120821.orig/libmultipath/config.h +++ multipath-tools-120821/libmultipath/config.h @@ -45,6 +45,7 @@ struct hwentry { int fast_io_fail; unsigned int dev_loss; int user_friendly_names; + int retain_hwhandler; char * bl_product; }; @@ -74,7 +75,6 @@ struct mpentry { }; struct config { - int dmrq; int verbosity; int dry_run; int list; @@ -108,6 +108,8 @@ struct config { mode_t mode; uint32_t cookie; int reassign_maps; + int retain_hwhandler; + unsigned int version[3]; char * dev; struct udev * udev; Index: multipath-tools-120821/libmultipath/defaults.h =================================================================== --- multipath-tools-120821.orig/libmultipath/defaults.h +++ multipath-tools-120821/libmultipath/defaults.h @@ -15,6 +15,7 @@ #define DEFAULT_USER_FRIENDLY_NAMES 0 #define DEFAULT_VERBOSITY 2 #define DEFAULT_REASSIGN_MAPS 1 +#define DEFAULT_RETAIN_HWHANDLER RETAIN_HWHANDLER_OFF #define DEFAULT_CHECKINT 5 #define MAX_CHECKINT(a) (a << 2) Index: multipath-tools-120821/libmultipath/dict.c =================================================================== --- multipath-tools-120821.orig/libmultipath/dict.c +++ multipath-tools-120821/libmultipath/dict.c @@ -629,6 +629,29 @@ wwids_file_handler(vector strvec) return 0; } +static int +def_retain_hwhandler_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->retain_hwhandler = RETAIN_HWHANDLER_OFF; + else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || + (strlen(buff) == 1 && !strcmp(buff, "1"))) + conf->retain_hwhandler = RETAIN_HWHANDLER_ON; + else + conf->retain_hwhandler = RETAIN_HWHANDLER_UNDEF; + + FREE(buff); + return 0; +} + /* * blacklist block handlers */ @@ -1250,6 +1273,33 @@ hw_names_handler(vector strvec) return 0; } +static int +hw_retain_hwhandler_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->retain_hwhandler = RETAIN_HWHANDLER_OFF; + else if ((strlen(buff) == 3 && !strcmp(buff, "yes")) || + (strlen(buff) == 1 && !strcmp(buff, "1"))) + hwe->retain_hwhandler = RETAIN_HWHANDLER_ON; + else + hwe->user_friendly_names = RETAIN_HWHANDLER_UNDEF; + + FREE(buff); + return 0; +} + /* * multipaths block handlers */ @@ -2274,6 +2324,19 @@ snprint_hw_user_friendly_names (char * b } static int +snprint_hw_retain_hwhandler_handler(char * buff, int len, void * data) +{ + struct hwentry * hwe = (struct hwentry *)data; + + if (hwe->retain_hwhandler == RETAIN_HWHANDLER_ON) + return snprintf(buff, len, "yes"); + else if (hwe->retain_hwhandler == RETAIN_HWHANDLER_OFF) + return snprintf(buff, len, "no"); + else + return 0; +} + +static int snprint_def_polling_interval (char * buff, int len, void * data) { return snprintf(buff, len, "%i", conf->checkint); @@ -2599,6 +2662,15 @@ snprint_def_reservation_key(char * buff, } static int +snprint_def_retain_hwhandler_handler(char * buff, int len, void * data) +{ + if (conf->retain_hwhandler == RETAIN_HWHANDLER_ON) + return snprintf(buff, len, "yes"); + else + return snprintf(buff, len, "no"); +} + +static int snprint_ble_simple (char * buff, int len, void * data) { struct blentry * ble = (struct blentry *)data; @@ -2662,6 +2734,7 @@ init_keywords(void) install_keyword("wwids_file", &wwids_file_handler, &snprint_def_wwids_file); install_keyword("log_checker_err", &def_log_checker_err_handler, &snprint_def_log_checker_err); install_keyword("reservation_key", &def_reservation_key_handler, &snprint_def_reservation_key); + install_keyword("retain_attached_hw_handler", &def_retain_hwhandler_handler, &snprint_def_retain_hwhandler_handler); __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); @@ -2723,6 +2796,7 @@ init_keywords(void) install_keyword("fast_io_fail_tmo", &hw_fast_io_fail_handler, &snprint_hw_fast_io_fail); install_keyword("dev_loss_tmo", &hw_dev_loss_handler, &snprint_hw_dev_loss); install_keyword("user_friendly_names", &hw_names_handler, &snprint_hw_user_friendly_names); + install_keyword("retain_attached_hw_handler", &hw_retain_hwhandler_handler, &snprint_hw_retain_hwhandler_handler); install_sublevel_end(); install_keyword_root("multipaths", &multipaths_handler); Index: multipath-tools-120821/libmultipath/structs.h =================================================================== --- multipath-tools-120821.orig/libmultipath/structs.h +++ multipath-tools-120821/libmultipath/structs.h @@ -99,6 +99,12 @@ enum user_friendly_names_states { USER_FRIENDLY_NAMES_ON, }; +enum retain_hwhandler_states { + RETAIN_HWHANDLER_UNDEF, + RETAIN_HWHANDLER_OFF, + RETAIN_HWHANDLER_ON, +}; + struct scsi_idlun { int dev_id; int host_unique_id; @@ -188,6 +194,7 @@ struct multipath { int flush_on_last_del; int attribute_flags; int fast_io_fail; + int retain_hwhandler; unsigned int dev_loss; uid_t uid; gid_t gid; Index: multipath-tools-120821/libmultipath/configure.c =================================================================== --- multipath-tools-120821.orig/libmultipath/configure.c +++ multipath-tools-120821/libmultipath/configure.c @@ -76,6 +76,7 @@ setup_map (struct multipath * mpp, char select_fast_io_fail(mpp); select_dev_loss(mpp); select_reservation_key(mpp); + select_retain_hwhandler(mpp); sysfs_set_scsi_tmo(mpp); /* @@ -217,8 +218,10 @@ select_action (struct multipath * mpp, v mpp->alias); return; } - if (!cmpp->selector || strncmp(cmpp->hwhandler, mpp->hwhandler, - strlen(mpp->hwhandler))) { + if (mpp->retain_hwhandler != RETAIN_HWHANDLER_ON && + (strlen(cmpp->hwhandler) != strlen(mpp->hwhandler) || + strncmp(cmpp->hwhandler, mpp->hwhandler, + strlen(mpp->hwhandler)))) { mpp->action = ACT_RELOAD; condlog(3, "%s: set ACT_RELOAD (hwhandler change)", mpp->alias); Index: multipath-tools-120821/libmultipath/dmparser.c =================================================================== --- multipath-tools-120821.orig/libmultipath/dmparser.c +++ multipath-tools-120821/libmultipath/dmparser.c @@ -56,6 +56,7 @@ assemble_map (struct multipath * mp, cha int nr_priority_groups, initial_pg_nr; char * p, * f; char no_path_retry[] = "queue_if_no_path"; + char retain_hwhandler[] = "retain_attached_hw_handler"; struct pathgroup * pgp; struct path * pp; @@ -81,6 +82,8 @@ assemble_map (struct multipath * mp, cha } else { add_feature(&f, no_path_retry); } + if (mp->retain_hwhandler == RETAIN_HWHANDLER_ON) + add_feature(&f, retain_hwhandler); shift = snprintf(p, freechar, "%s %s %i %i", f, mp->hwhandler, Index: multipath-tools-120821/libmultipath/propsel.c =================================================================== --- multipath-tools-120821.orig/libmultipath/propsel.c +++ multipath-tools-120821/libmultipath/propsel.c @@ -513,7 +513,9 @@ select_minio_bio (struct multipath * mp) extern int select_minio (struct multipath * mp) { - if (conf->dmrq) + unsigned int minv_dmrq[3] = {1, 1, 0}; + + if (VERSION_GE(conf->version, minv_dmrq)) return select_minio_rq(mp); else return select_minio_bio(mp); @@ -674,3 +676,28 @@ select_reservation_key (struct multipath return 0; } +extern int +select_retain_hwhandler (struct multipath * mp) +{ + unsigned int minv_dm_retain[3] = {1, 5, 0}; + + if (!VERSION_GE(conf->version, minv_dm_retain)) { + mp->retain_hwhandler = RETAIN_HWHANDLER_OFF; + condlog(3, "%s: retain_attached_hw_hander disabled (requires kernel version >= 1.5.0)", mp->alias); + return 0; + } + + if (mp->hwe && mp->hwe->retain_hwhandler) { + mp->retain_hwhandler = mp->hwe->retain_hwhandler; + condlog(3, "%s: retain_attached_hw_handler = %d (controller default)", mp->alias, mp->retain_hwhandler); + return 0; + } + if (conf->retain_hwhandler) { + mp->retain_hwhandler = conf->retain_hwhandler; + condlog(3, "%s: retain_attached_hw_handler = %d (config file default)", mp->alias, mp->retain_hwhandler); + return 0; + } + mp->retain_hwhandler = 0; + condlog(3, "%s: retain_attached_hw_handler = %d (compiled in default)", mp->alias, mp->retain_hwhandler); + return 0; +} Index: multipath-tools-120821/libmultipath/propsel.h =================================================================== --- multipath-tools-120821.orig/libmultipath/propsel.h +++ multipath-tools-120821/libmultipath/propsel.h @@ -18,3 +18,4 @@ int select_gid(struct multipath *mp); int select_fast_io_fail(struct multipath *mp); int select_dev_loss(struct multipath *mp); int select_reservation_key(struct multipath *mp); +int select_retain_hwhandler (struct multipath * mp); Index: multipath-tools-120821/libmultipath/devmapper.c =================================================================== --- multipath-tools-120821.orig/libmultipath/devmapper.c +++ multipath-tools-120821/libmultipath/devmapper.c @@ -98,12 +98,6 @@ dm_init(void) { dm_log_init_verbose(conf ? conf->verbosity + 3 : 0); } -#define VERSION_GE(v, minv) ( \ - (v[0] > minv[0]) || \ - ((v[0] == minv[0]) && (v[1] > minv[1])) || \ - ((v[0] == minv[0]) && (v[1] == minv[1]) && (v[2] >= minv[2])) \ -) - static int dm_lib_prereq (void) { @@ -126,7 +120,7 @@ dm_lib_prereq (void) return 1; } -static int +int dm_drv_version (unsigned int * version, char * str) { int r = 2; @@ -135,6 +129,10 @@ dm_drv_version (unsigned int * version, struct dm_versions *last_target; unsigned int *v; + version[0] = 0; + version[1] = 0; + version[2] = 0; + if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS))) return 1; @@ -169,28 +167,6 @@ out: return r; } -int -dm_drv_get_rq (void) -{ - unsigned int minv_dmrq[3] = {1, 1, 0}; - unsigned int version[3] = {0, 0, 0}; - unsigned int * v = version; - - if (dm_drv_version(v, TGT_MPATH)) { - /* in doubt return least capable */ - return 0; - } - - /* test request based multipath capability */ - if VERSION_GE(v, minv_dmrq) { - condlog(3, "activate request-based multipathing mode " - "(driver >= v%u.%u.%u)", - minv_dmrq[0], minv_dmrq[1], minv_dmrq[2]); - return 1; - } - return 0; -} - static int dm_drv_prereq (void) { Index: multipath-tools-120821/libmultipath/devmapper.h =================================================================== --- multipath-tools-120821.orig/libmultipath/devmapper.h +++ multipath-tools-120821/libmultipath/devmapper.h @@ -8,7 +8,7 @@ void dm_init(void); int dm_prereq (void); -int dm_drv_get_rq (void); +int dm_drv_version (unsigned int * version, char * str); int dm_simplecmd_flush (int, const char *, int); int dm_simplecmd_noflush (int, const char *); int dm_addmap_create (struct multipath *mpp, char *params); @@ -46,4 +46,10 @@ int dm_setgeometry(struct multipath *mpp void udev_wait(unsigned int c); void udev_set_sync_support(int c); +#define VERSION_GE(v, minv) ( \ + (v[0] > minv[0]) || \ + ((v[0] == minv[0]) && (v[1] > minv[1])) || \ + ((v[0] == minv[0]) && (v[1] == minv[1]) && (v[2] >= minv[2])) \ +) + #endif /* _DEVMAPPER_H */ -- dm-devel mailing list dm-devel@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/dm-devel