@@ -1105,7 +1105,7 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid,
/*
* at this point, we know we really got a new mp
*/
- mpp = add_map_with_path(vecs, pp1, 0);
+ mpp = add_map_with_path(vecs, pp1, 0, cmpp);
if (!mpp) {
orphan_path(pp1, "failed to create multipath device");
continue;
@@ -242,7 +242,38 @@ static bool update_pathvec_from_dm(vector pathvec, struct multipath *mpp,
return must_reload;
}
-int adopt_paths(vector pathvec, struct multipath *mpp)
+static bool set_path_max_sectors_kb(const struct path *pp, int max_sectors_kb)
+{
+ char buf[11];
+ ssize_t len;
+ int ret, current;
+ bool rc = false;
+
+ if (max_sectors_kb == MAX_SECTORS_KB_UNDEF)
+ return rc;
+
+ if (sysfs_attr_get_value(pp->udev, "queue/max_sectors_kb", buf, sizeof(buf)) <= 0
+ || sscanf(buf, "%d\n", ¤t) != 1)
+ current = MAX_SECTORS_KB_UNDEF;
+ if (current == max_sectors_kb)
+ return rc;
+
+ len = snprintf(buf, sizeof(buf), "%d", max_sectors_kb);
+ ret = sysfs_attr_set_value(pp->udev, "queue/max_sectors_kb", buf, len);
+ if (ret != len)
+ log_sysfs_attr_set_value(3, ret,
+ "failed setting max_sectors_kb on %s",
+ pp->dev);
+ else {
+ condlog(3, "%s: set max_sectors_kb to %d for %s", __func__,
+ max_sectors_kb, pp->dev);
+ rc = true;
+ }
+ return rc;
+}
+
+int adopt_paths(vector pathvec, struct multipath *mpp,
+ const struct multipath *current_mpp)
{
int i, ret;
struct path * pp;
@@ -285,9 +316,28 @@ int adopt_paths(vector pathvec, struct multipath *mpp)
continue;
}
- if (!find_path_by_devt(mpp->paths, pp->dev_t) &&
- store_path(mpp->paths, pp))
- goto err;
+ if (!find_path_by_devt(mpp->paths, pp->dev_t)) {
+
+ if (store_path(mpp->paths, pp))
+ goto err;
+ /*
+ * Setting max_sectors_kb on live paths is dangerous.
+ * But we can do it here on a path that isn't yet part
+ * of the map. If this value is lower than the current
+ * max_sectors_kb and the map is reloaded, the map's
+ * max_sectors_kb will be safely adjusted by the kernel.
+ *
+ * We must make sure that the path is not part of the
+ * map yet. Normally we can check this in mpp->paths.
+ * But if adopt_paths is called from coalesce_paths,
+ * we need to check the separate struct multipath that
+ * has been obtained from map_discovery().
+ */
+ if (!current_mpp ||
+ !mp_find_path_by_devt(current_mpp, pp->dev_t))
+ mpp->need_reload = mpp->need_reload ||
+ set_path_max_sectors_kb(pp, mpp->max_sectors_kb);
+ }
pp->mpp = mpp;
condlog(3, "%s: ownership set to %s",
@@ -693,7 +743,7 @@ find_existing_alias (struct multipath * mpp,
}
struct multipath *add_map_with_path(struct vectors *vecs, struct path *pp,
- int add_vec)
+ int add_vec, const struct multipath *current_mpp)
{
struct multipath * mpp;
struct config *conf = NULL;
@@ -721,7 +771,7 @@ struct multipath *add_map_with_path(struct vectors *vecs, struct path *pp,
goto out;
mpp->size = pp->size;
- if (adopt_paths(vecs->pathvec, mpp) || pp->mpp != mpp ||
+ if (adopt_paths(vecs->pathvec, mpp, current_mpp) || pp->mpp != mpp ||
find_slot(mpp->paths, pp) == -1)
goto out;
@@ -13,7 +13,8 @@ struct vectors {
void set_no_path_retry(struct multipath *mpp);
-int adopt_paths (vector pathvec, struct multipath * mpp);
+int adopt_paths (vector pathvec, struct multipath *mpp,
+ const struct multipath *current_mpp);
void orphan_path (struct path * pp, const char *reason);
void set_path_removed(struct path *pp);
@@ -28,7 +29,8 @@ void remove_maps (struct vectors * vecs);
void sync_map_state (struct multipath *);
struct multipath * add_map_with_path (struct vectors * vecs,
- struct path * pp, int add_vec);
+ struct path * pp, int add_vec,
+ const struct multipath *current_mpp);
void update_queue_mode_del_path(struct multipath *mpp);
void update_queue_mode_add_path(struct multipath *mpp);
int update_multipath_table (struct multipath *mpp, vector pathvec, int flags);
@@ -636,7 +636,7 @@ update_map (struct multipath *mpp, struct vectors *vecs, int new_map)
retry:
condlog(4, "%s: updating new map", mpp->alias);
- if (adopt_paths(vecs->pathvec, mpp)) {
+ if (adopt_paths(vecs->pathvec, mpp, NULL)) {
condlog(0, "%s: failed to adopt paths for new map update",
mpp->alias);
retries = -1;
@@ -1231,7 +1231,7 @@ rescan:
if (mpp) {
condlog(4,"%s: adopting all paths for path %s",
mpp->alias, pp->dev);
- if (adopt_paths(vecs->pathvec, mpp) || pp->mpp != mpp ||
+ if (adopt_paths(vecs->pathvec, mpp, NULL) || pp->mpp != mpp ||
find_slot(mpp->paths, pp) == -1)
goto fail; /* leave path added to pathvec */
@@ -1245,7 +1245,7 @@ rescan:
return 0;
}
condlog(4,"%s: creating new map", pp->dev);
- if ((mpp = add_map_with_path(vecs, pp, 1))) {
+ if ((mpp = add_map_with_path(vecs, pp, 1, NULL))) {
mpp->action = ACT_CREATE;
/*
* We don't depend on ACT_CREATE, as domap will
@@ -45,7 +45,7 @@ dmevents-test_OBJDEPS = $(multipathdir)/devmapper.o
dmevents-test_LIBDEPS = -lpthread -ldevmapper -lurcu
hwtable-test_TESTDEPS := test-lib.o
hwtable-test_OBJDEPS := $(multipathdir)/discovery.o $(multipathdir)/blacklist.o \
- $(multipathdir)/structs.o $(multipathdir)/propsel.o
+ $(multipathdir)/structs_vec.o $(multipathdir)/structs.o $(multipathdir)/propsel.o
hwtable-test_LIBDEPS := -ludev -lpthread -ldl
blacklist-test_TESTDEPS := test-log.o
blacklist-test_LIBDEPS := -ludev
@@ -152,6 +152,13 @@ int __wrap_sysfs_get_size(struct path *pp, unsigned long long *sz)
return 0;
}
+int __wrap_sysfs_attr_set_value(struct udev_device *dev, const char *attr_name,
+ const char * value, size_t value_len)
+{
+ condlog(5, "%s: %s", __func__, value);
+ return value_len;
+}
+
void *__wrap_udev_device_get_parent_with_subsystem_devtype(
struct udev_device *ud, const char *subsys, char *type)
{
@@ -400,7 +407,7 @@ struct multipath *__mock_multipath(struct vectors *vecs, struct path *pp)
/* pathinfo() call in adopt_paths */
mock_pathinfo(DI_CHECKER|DI_PRIO, &mop);
- mp = add_map_with_path(vecs, pp, 1);
+ mp = add_map_with_path(vecs, pp, 1, NULL);
assert_ptr_not_equal(mp, NULL);
/* TBD: mock setup_map() ... */
As explained in the previous commit, setting max_sectors_kb for paths that are members of a live map is dangerous. But as long as a path is not a member of a map, setting max_sectors_kb poses no risk. Set the parameter in adopt_paths(), for paths that aren't members of the map yet. In order to determine whether or not a path is currently member of the map, adopt_paths() needs to passed the current member list. If (and only if) it's called from coalesce_paths(), the passed struct multipath does not represent the current state of the map; adopt_paths() must therefore get a new argument current_mpp that represents the kernel state. We must still call sysfs_set_max_sectors_kb() from domap() in the ACT_CREATE case, because when adopt_paths is called from coalesce_paths() for a map that doesn't exist yet, mpp->max_sectors_kb is not set. Signed-off-by: Martin Wilck <mwilck@suse.com> --- libmultipath/configure.c | 2 +- libmultipath/structs_vec.c | 62 ++++++++++++++++++++++++++++++++++---- libmultipath/structs_vec.h | 6 ++-- multipathd/main.c | 6 ++-- tests/Makefile | 2 +- tests/test-lib.c | 9 +++++- 6 files changed, 73 insertions(+), 14 deletions(-)