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 <[email protected]>
---
 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


Reply via email to