This option gives multipathd the ability to automatically resize a device when it detects that all of the path devices have changed. By default it is set to never, and multipathd will continue to work like it always has, where a users must manually resize a multipath device. Signed-off-by: Benjamin Marzinski <bmarzins@xxxxxxxxxx> --- libmultipath/config.c | 2 ++ libmultipath/config.h | 3 +++ libmultipath/configure.c | 1 + libmultipath/defaults.h | 1 + libmultipath/dict.c | 48 +++++++++++++++++++++++++++++++++++ libmultipath/dict.h | 1 + libmultipath/hwtable.c | 1 + libmultipath/propsel.c | 17 +++++++++++++ libmultipath/propsel.h | 1 + libmultipath/structs.h | 8 ++++++ multipath/multipath.conf.5.in | 16 ++++++++++++ multipathd/main.c | 24 +++++++++++++++++- 12 files changed, 122 insertions(+), 1 deletion(-) diff --git a/libmultipath/config.c b/libmultipath/config.c index 9d90f512..e6024955 100644 --- a/libmultipath/config.c +++ b/libmultipath/config.c @@ -464,6 +464,7 @@ merge_hwe (struct hwentry * dst, struct hwentry * src) merge_num(ghost_delay); merge_num(all_tg_pt); merge_num(recheck_wwid); + merge_num(auto_resize); merge_num(vpd_vendor_id); merge_num(san_path_err_threshold); merge_num(san_path_err_forget_rate); @@ -519,6 +520,7 @@ merge_mpe(struct mpentry *dst, struct mpentry *src) merge_num(skip_kpartx); merge_num(max_sectors_kb); merge_num(ghost_delay); + merge_num(auto_resize); merge_num(uid); merge_num(gid); merge_num(mode); diff --git a/libmultipath/config.h b/libmultipath/config.h index 197a567f..3be8e507 100644 --- a/libmultipath/config.h +++ b/libmultipath/config.h @@ -96,6 +96,7 @@ struct hwentry { int all_tg_pt; int vpd_vendor_id; int recheck_wwid; + int auto_resize; char * bl_product; vector pctable; @@ -135,6 +136,7 @@ struct mpentry { int skip_kpartx; int max_sectors_kb; int ghost_delay; + int auto_resize; uid_t uid; gid_t gid; mode_t mode; @@ -204,6 +206,7 @@ struct config { int skip_delegate; unsigned int sequence_nr; int recheck_wwid; + int auto_resize; char * selector; struct _vector uid_attrs; diff --git a/libmultipath/configure.c b/libmultipath/configure.c index d8094903..592761b2 100644 --- a/libmultipath/configure.c +++ b/libmultipath/configure.c @@ -355,6 +355,7 @@ int setup_map(struct multipath *mpp, char **params, struct vectors *vecs) select_max_sectors_kb(conf, mpp); select_ghost_delay(conf, mpp); select_flush_on_last_del(conf, mpp); + select_auto_resize(conf, mpp); sysfs_set_scsi_tmo(conf, mpp); marginal_pathgroups = conf->marginal_pathgroups; diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h index d01f9712..64b633f2 100644 --- a/libmultipath/defaults.h +++ b/libmultipath/defaults.h @@ -56,6 +56,7 @@ #define DEFAULT_UNKNOWN_FIND_MULTIPATHS_TIMEOUT 1 #define DEFAULT_ALL_TG_PT ALL_TG_PT_OFF #define DEFAULT_RECHECK_WWID RECHECK_WWID_OFF +#define DEFAULT_AUTO_RESIZE AUTO_RESIZE_NEVER /* Enable no foreign libraries by default */ #define DEFAULT_ENABLE_FOREIGN "NONE" diff --git a/libmultipath/dict.c b/libmultipath/dict.c index fc438947..037d717c 100644 --- a/libmultipath/dict.c +++ b/libmultipath/dict.c @@ -1670,6 +1670,50 @@ declare_hw_snprint(recheck_wwid, print_yes_no_undef) declare_def_range_handler(uxsock_timeout, DEFAULT_REPLY_TIMEOUT, INT_MAX) +static int +set_auto_resize(vector strvec, void *ptr, const char *file, int line_nr) +{ + char * buff; + int *int_ptr = (int *)ptr; + + buff = set_value(strvec); + if (!buff) + return 1; + + if (strcmp(buff, "never") == 0) + *int_ptr = AUTO_RESIZE_NEVER; + else if (strcmp(buff, "grow_only") == 0) + *int_ptr = AUTO_RESIZE_GROW_ONLY; + else if (strcmp(buff, "grow_shrink") == 0) + *int_ptr = AUTO_RESIZE_GROW_SHRINK; + else + condlog(1, "%s line %d, invalid value for %s: \"%s\"", + file, line_nr, (char*)VECTOR_SLOT(strvec, 0), buff); + + free(buff); + return 0; +} + +int +print_auto_resize(struct strbuf *buff, long v) +{ + if (!v) + return 0; + return append_strbuf_quoted(buff, + v == AUTO_RESIZE_GROW_ONLY ? "grow_only" : + v == AUTO_RESIZE_GROW_SHRINK ? "grow_shrink" : + "never"); +} + +declare_def_handler(auto_resize, set_auto_resize) +declare_def_snprint(auto_resize, print_auto_resize) +declare_ovr_handler(auto_resize, set_auto_resize) +declare_ovr_snprint(auto_resize, print_auto_resize) +declare_hw_handler(auto_resize, set_auto_resize) +declare_hw_snprint(auto_resize, print_auto_resize) +declare_mp_handler(auto_resize, set_auto_resize) +declare_mp_snprint(auto_resize, print_auto_resize) + static int hw_vpd_vendor_handler(struct config *conf, vector strvec, const char *file, int line_nr) @@ -2146,6 +2190,7 @@ init_keywords(vector keywords) install_keyword("remove_retries", &def_remove_retries_handler, &snprint_def_remove_retries); install_keyword("max_sectors_kb", &def_max_sectors_kb_handler, &snprint_def_max_sectors_kb); install_keyword("ghost_delay", &def_ghost_delay_handler, &snprint_def_ghost_delay); + install_keyword("auto_resize", &def_auto_resize_handler, &snprint_def_auto_resize); install_keyword("find_multipaths_timeout", &def_find_multipaths_timeout_handler, &snprint_def_find_multipaths_timeout); @@ -2227,6 +2272,7 @@ init_keywords(vector keywords) install_keyword("skip_kpartx", &hw_skip_kpartx_handler, &snprint_hw_skip_kpartx); install_keyword("max_sectors_kb", &hw_max_sectors_kb_handler, &snprint_hw_max_sectors_kb); install_keyword("ghost_delay", &hw_ghost_delay_handler, &snprint_hw_ghost_delay); + install_keyword("auto_resize", &hw_auto_resize_handler, &snprint_hw_auto_resize); install_keyword("all_tg_pt", &hw_all_tg_pt_handler, &snprint_hw_all_tg_pt); install_keyword("vpd_vendor", &hw_vpd_vendor_handler, &snprint_hw_vpd_vendor); install_keyword("recheck_wwid", &hw_recheck_wwid_handler, &snprint_hw_recheck_wwid); @@ -2273,6 +2319,7 @@ init_keywords(vector keywords) install_keyword("skip_kpartx", &ovr_skip_kpartx_handler, &snprint_ovr_skip_kpartx); install_keyword("max_sectors_kb", &ovr_max_sectors_kb_handler, &snprint_ovr_max_sectors_kb); install_keyword("ghost_delay", &ovr_ghost_delay_handler, &snprint_ovr_ghost_delay); + install_keyword("auto_resize", &ovr_auto_resize_handler, &snprint_ovr_auto_resize); install_keyword("all_tg_pt", &ovr_all_tg_pt_handler, &snprint_ovr_all_tg_pt); install_keyword("recheck_wwid", &ovr_recheck_wwid_handler, &snprint_ovr_recheck_wwid); install_keyword_multi("protocol", &protocol_handler, NULL); @@ -2319,5 +2366,6 @@ init_keywords(vector keywords) install_keyword("skip_kpartx", &mp_skip_kpartx_handler, &snprint_mp_skip_kpartx); install_keyword("max_sectors_kb", &mp_max_sectors_kb_handler, &snprint_mp_max_sectors_kb); install_keyword("ghost_delay", &mp_ghost_delay_handler, &snprint_mp_ghost_delay); + install_keyword("auto_resize", &mp_auto_resize_handler, &snprint_mp_auto_resize); install_sublevel_end(); } diff --git a/libmultipath/dict.h b/libmultipath/dict.h index 15d9cbac..7e2dfbe0 100644 --- a/libmultipath/dict.h +++ b/libmultipath/dict.h @@ -17,4 +17,5 @@ int print_no_path_retry(struct strbuf *buff, long v); int print_undef_off_zero(struct strbuf *buff, long v); int print_dev_loss(struct strbuf *buff, unsigned long v); int print_off_int_undef(struct strbuf *buff, long v); +int print_auto_resize(struct strbuf *buff, long v); #endif /* _DICT_H */ diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c index ae6aac79..27a8c9b4 100644 --- a/libmultipath/hwtable.c +++ b/libmultipath/hwtable.c @@ -75,6 +75,7 @@ .skip_kpartx = SKIP_KPARTX_OFF, .max_sectors_kb = MAX_SECTORS_KB_UNDEF, .ghost_delay = GHOST_DELAY_OFF, + .auto_resize = AUTO_RESIZE_NEVER, }, #endif diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c index 15abb9e5..2489c00c 100644 --- a/libmultipath/propsel.c +++ b/libmultipath/propsel.c @@ -1423,6 +1423,23 @@ out: return 0; } +int select_auto_resize (struct config *conf, struct multipath * mp) +{ + const char *origin; + STRBUF_ON_STACK(buff); + + mp_set_mpe(auto_resize); + mp_set_ovr(auto_resize); + mp_set_hwe(auto_resize); + mp_set_conf(auto_resize); + mp_set_default(auto_resize, DEFAULT_AUTO_RESIZE); +out: + if (print_auto_resize(&buff, mp->auto_resize) != 0) + condlog(3, "%s: auto_resize = %s %s", mp->alias, + get_strbuf_str(&buff), origin); + return 0; +} + int select_find_multipaths_timeout(struct config *conf, struct path *pp) { const char *origin; diff --git a/libmultipath/propsel.h b/libmultipath/propsel.h index 7203509e..e6941190 100644 --- a/libmultipath/propsel.h +++ b/libmultipath/propsel.h @@ -38,6 +38,7 @@ int select_marginal_path_err_rate_threshold(struct config *conf, struct multipat int select_marginal_path_err_recheck_gap_time(struct config *conf, struct multipath *mp); int select_marginal_path_double_failed_time(struct config *conf, struct multipath *mp); int select_ghost_delay(struct config *conf, struct multipath * mp); +int select_auto_resize(struct config *conf, struct multipath * mp); void reconcile_features_with_options(const char *id, char **features, int* no_path_retry, int *retain_hwhandler); diff --git a/libmultipath/structs.h b/libmultipath/structs.h index c20e99ce..b75e7778 100644 --- a/libmultipath/structs.h +++ b/libmultipath/structs.h @@ -179,6 +179,13 @@ enum queue_mode_states { QUEUE_MODE_RQ, }; +enum auto_resize_state { + AUTO_RESIZE_UNDEF = 0, + AUTO_RESIZE_NEVER, + AUTO_RESIZE_GROW_ONLY, + AUTO_RESIZE_GROW_SHRINK, +}; + #define PROTOCOL_UNSET -1 enum scsi_protocol { @@ -447,6 +454,7 @@ struct multipath { int ghost_delay; int ghost_delay_tick; int queue_mode; + int auto_resize; uid_t uid; gid_t gid; mode_t mode; diff --git a/multipath/multipath.conf.5.in b/multipath/multipath.conf.5.in index 41f3927e..c90383cf 100644 --- a/multipath/multipath.conf.5.in +++ b/multipath/multipath.conf.5.in @@ -1333,6 +1333,22 @@ The default is: \fBno\fR . . .TP +.B auto_resize +Controls when multipathd will automatically resize a multipath device. If set +to \fInever\fR, multipath devices must always be manually resized by either +running \fBmultipathd resize map <name>\fR or \fRmultipath -r <name>\fR. If +set to \fIgrow_only\fR, when multipathd detects that all of a multipath +device's paths have increased in size, it will automatically grow the multipath +device to the new size. If set to \fIgrow_shrink\fR, multipathd will also +automatically shrink the device once it detects all of its paths have decreased +in size. +.RS +.TP +The default is: \fBnever\fR +.RE +. +. +.TP .B enable_foreign Enables or disables foreign libraries (see section .I FOREIGN MULTIPATH SUPPORT diff --git a/multipathd/main.c b/multipathd/main.c index 3b4c5b09..ac733491 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -1633,7 +1633,6 @@ uev_update_path (struct uevent *uev, struct vectors * vecs) ro = uevent_get_disk_ro(uev); if (needs_ro_update(mpp, ro)) { condlog(2, "%s: update path write_protect to '%d' (uevent)", uev->kernel, ro); - if (mpp->wait_for_udev) mpp->wait_for_udev = 2; else { @@ -1648,6 +1647,29 @@ uev_update_path (struct uevent *uev, struct vectors * vecs) } } } + if (mpp->auto_resize != AUTO_RESIZE_NEVER && + !mpp->wait_for_udev) { + struct pathgroup *pgp; + struct path *pp2; + unsigned int i, j; + unsigned long long orig_size = mpp->size; + + if (!pp->size || pp->size == mpp->size || + (pp->size < mpp->size && + mpp->auto_resize == AUTO_RESIZE_GROW_ONLY)) + goto out; + + vector_foreach_slot(mpp->pg, pgp, i) + vector_foreach_slot (pgp->paths, pp2, j) + if (pp2->size && pp2->size != pp->size) + goto out; + retval = resize_map(mpp, pp->size, vecs); + if (retval == 2) + condlog(2, "%s: map removed during resize", pp->dev); + else if (retval == 0) + condlog(2, "%s: resized map from %llu to %llu", + mpp->alias, orig_size, pp->size); + } } out: lock_cleanup_pop(vecs->lock); -- 2.41.0