File multipath-tools-reload-map-for-ro-changes of Package multipath-tools

commit 3b88c4374cf2a204e14ffdaf85b2dbfdc4a1391a
Author: Hannes Reinecke <hare@suse.de>
Date:   Thu Dec 4 14:20:06 2008 +0100

    Reload map for device read-only setting changes
    
    Whenever the read-only setting for a device changes we have
    to reload the map. This patch implements the required cli command
    and also a uevent handler if a uevent with 'DISK_RO=' setting
    has been received.
    
    References: 440959
    
    Signed-off-by: Hannes Reinecke <hare@suse.de>

diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index 3903b28..68178c3 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -672,3 +672,40 @@ out:
 	return NULL;
 }
 
+extern int reload_map(struct vectors *vecs, struct multipath *mpp)
+{
+	char params[PARAMS_SIZE];
+	int r;
+
+	update_mpp_paths(mpp, vecs->pathvec);
+
+	params[0] = '\0';
+	if (setup_map(mpp, params, PARAMS_SIZE)) {
+		condlog(0, "%s: failed to setup map", mpp->alias);
+		return 1;
+	}
+	select_action(mpp, vecs->mpvec, 1);
+
+	r = domap(mpp, params);
+	if (r == DOMAP_FAIL || r == DOMAP_RETRY) {
+		condlog(3, "%s: domap (%u) failure "
+			"for reload map", mpp->alias, r);
+		return 1;
+	}
+	if (mpp->no_path_retry != NO_PATH_RETRY_UNDEF) {
+		if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
+			dm_queue_if_no_path(mpp->alias, 0);
+		else
+			dm_queue_if_no_path(mpp->alias, 1);
+	}
+	if (mpp->pg_timeout != PGTIMEOUT_UNDEF) {
+		if (mpp->pg_timeout == -PGTIMEOUT_NONE)
+			dm_set_pg_timeout(mpp->alias,  0);
+		else
+			dm_set_pg_timeout(mpp->alias, mpp->pg_timeout);
+	}
+
+	return 0;
+}
+
+
diff --git a/libmultipath/configure.h b/libmultipath/configure.h
index ec2800d..d0c06f2 100644
--- a/libmultipath/configure.h
+++ b/libmultipath/configure.h
@@ -28,4 +28,5 @@ int domap (struct multipath * mpp, char * params);
 int reinstate_paths (struct multipath *mpp);
 int coalesce_paths (struct vectors *vecs, vector curmp, char * refwwid, int force_reload);
 char * get_refwwid (char * dev, enum devtypes dev_type, vector pathvec);
+int reload_map(struct vectors *vecs, struct multipath *mpp);
 
diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c
index 13986da..19a71ad 100644
--- a/libmultipath/uevent.c
+++ b/libmultipath/uevent.c
@@ -341,3 +341,23 @@ uevent_get_minor(struct uevent *uev)
 	return minor;
 }
 
+extern int
+uevent_get_disk_ro(struct uevent *uev)
+{
+	char *p, *q;
+	int i, ro = -1;
+
+	for (i = 0; uev->envp[i] != NULL; i++) {
+		if (!strncmp(uev->envp[i], "DISK_RO", 6) && strlen(uev->envp[i]) > 7) {
+			p = uev->envp[i] + 8;
+			ro = strtoul(p, &q, 10);
+			if (p == q) {
+				condlog(2, "invalid read_only setting '%s'", p);
+				ro = -1;
+			}
+			break;
+		}
+	}
+	return ro;
+}
+
diff --git a/libmultipath/uevent.h b/libmultipath/uevent.h
index 43d163b..ec6450b 100644
--- a/libmultipath/uevent.h
+++ b/libmultipath/uevent.h
@@ -23,5 +23,6 @@ int uevent_listen(int (*store_uev)(struct uevent *, void * trigger_data),
 		  void * trigger_data);
 int uevent_get_major(struct uevent *uev);
 int uevent_get_minor(struct uevent *uev);
+int uevent_get_disk_ro(struct uevent *uev);
 
 #endif /* _UEVENT_H */
diff --git a/multipathd/cli.c b/multipathd/cli.c
index 2545e89..acc8cab 100644
--- a/multipathd/cli.c
+++ b/multipathd/cli.c
@@ -156,6 +156,7 @@ load_keys (void)
 	r += add_key(keys, "reinstate", REINSTATE, 0);
 	r += add_key(keys, "fail", FAIL, 0);
 	r += add_key(keys, "resize", RESIZE, 0);
+	r += add_key(keys, "reload", RELOAD, 0);
 	r += add_key(keys, "paths", PATHS, 0);
 	r += add_key(keys, "maps", MAPS, 0);
 	r += add_key(keys, "multipaths", MAPS, 0);
@@ -427,6 +428,8 @@ cli_init (void) {
 	add_handler(RECONFIGURE, NULL);
 	add_handler(SUSPEND+MAP, NULL);
 	add_handler(RESUME+MAP, NULL);
+	add_handler(RESIZE+MAP, NULL);
+	add_handler(RELOAD+MAP, NULL);
 	add_handler(REINSTATE+PATH, NULL);
 	add_handler(FAIL+PATH, NULL);
 
diff --git a/multipathd/cli.h b/multipathd/cli.h
index be14395..1fa4862 100644
--- a/multipathd/cli.h
+++ b/multipathd/cli.h
@@ -8,6 +8,7 @@ enum {
 	__REINSTATE,
 	__FAIL,
 	__RESIZE,
+	__RELOAD,
 	__PATHS,
 	__MAPS,
 	__PATH,
@@ -33,6 +34,7 @@ enum {
 #define REINSTATE	(1 << __REINSTATE)
 #define FAIL		(1 << __FAIL)
 #define RESIZE		(1 << __RESIZE)
+#define RELOAD		(1 << __RELOAD)
 #define PATHS		(1 << __PATHS)
 #define MAPS		(1 << __MAPS)
 #define PATH		(1 << __PATH)
diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c
index 4f639b6..819dd87 100644
--- a/multipathd/cli_handlers.c
+++ b/multipathd/cli_handlers.c
@@ -460,6 +460,28 @@ out:
 	return err;
 }
 
+int
+cli_reload(void *v, char **reply, int *len, void *data)
+{
+	struct vectors * vecs = (struct vectors *)data;
+	char * mapname = get_keyparam(v, MAP);
+	struct multipath *mpp;
+	int minor;
+
+	condlog(2, "%s: reload map (operator)", mapname);
+	if (sscanf(mapname, "dm-%d", &minor) == 1)
+		mpp = find_mp_by_minor(vecs->mpvec, minor);
+	else
+		mpp = find_mp_by_alias(vecs->mpvec, mapname);
+
+	if (!mpp) {
+		condlog(0, "%s: invalid map name. cannot reload", mapname);
+		return 1;
+	}
+
+	return reload_map(vecs, mpp);
+}
+
 int resize_map(struct multipath *mpp, unsigned long long size,
 	       struct vectors * vecs)
 {
diff --git a/multipathd/cli_handlers.h b/multipathd/cli_handlers.h
index b65f259..6e92a07 100644
--- a/multipathd/cli_handlers.h
+++ b/multipathd/cli_handlers.h
@@ -17,6 +17,7 @@ int cli_del_map (void * v, char ** reply, int * len, void * data);
 int cli_switch_group(void * v, char ** reply, int * len, void * data);
 int cli_reconfigure(void * v, char ** reply, int * len, void * data);
 int cli_resize(void * v, char ** reply, int * len, void * data);
+int cli_reload(void * v, char ** reply, int * len, void * data);
 int cli_suspend(void * v, char ** reply, int * len, void * data);
 int cli_resume(void * v, char ** reply, int * len, void * data);
 int cli_reinstate(void * v, char ** reply, int * len, void * data);
diff --git a/multipathd/main.c b/multipathd/main.c
index 444494e..c60d075 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -572,6 +572,43 @@ out:
 }
 
 static int
+uev_update_path (struct uevent *uev, struct vectors * vecs)
+{
+	struct sysfs_device * dev;
+	int retval, ro;
+
+	dev = sysfs_device_get(uev->devpath);
+	if (!dev) {
+		condlog(2, "%s: not found in sysfs", uev->devpath);
+		return 1;
+	}
+	ro = uevent_get_disk_ro(uev);
+
+	if (ro >= 0) {
+		struct path * pp;
+
+		condlog(2, "%s: update path write_protect to '%d' (uevent)",
+			uev->kernel, ro);
+		pp = find_path_by_dev(vecs->pathvec, uev->kernel);
+		if (!pp) {
+			condlog(0, "%s: spurious uevent, path not found",
+				uev->kernel);
+			return 1;
+		}
+		if (pp->mpp)
+			retval = reload_map(vecs, pp->mpp);
+
+		condlog(2, "%s: map %s reloaded (retval %d)",
+			uev->kernel, pp->mpp->alias, retval);
+
+	}
+
+	sysfs_device_put(dev);
+
+	return retval;
+}
+
+static int
 map_discovery (struct vectors * vecs)
 {
 	struct multipath * mpp;
@@ -688,6 +725,10 @@ uev_trigger (struct uevent * uev, void * trigger_data)
 		r = uev_remove_path(uev, vecs);
 		goto out;
 	}
+	if (!strncmp(uev->action, "change", 6)) {
+		r = uev_update_path(uev, vecs);
+		goto out;
+	}
 
 out:
 	unlock(vecs->lock);
@@ -731,6 +772,7 @@ uxlsnrloop (void * ap)
 	set_handler_callback(SUSPEND+MAP, cli_suspend);
 	set_handler_callback(RESUME+MAP, cli_resume);
 	set_handler_callback(RESIZE+MAP, cli_resize);
+	set_handler_callback(RELOAD+MAP, cli_reload);
 	set_handler_callback(REINSTATE+PATH, cli_reinstate);
 	set_handler_callback(FAIL+PATH, cli_fail);
 
openSUSE Build Service is sponsored by