Reload map for device read-only setting changes
authorHannes Reinecke <hare@suse.de>
Thu, 4 Dec 2008 13:20:06 +0000 (14:20 +0100)
committerHannes Reinecke <hare@suse.de>
Wed, 18 May 2011 13:49:36 +0000 (15:49 +0200)
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.

Signed-off-by: Hannes Reinecke <hare@suse.de>
libmultipath/configure.c
libmultipath/configure.h
libmultipath/uevent.c
libmultipath/uevent.h
multipathd/cli.c
multipathd/cli.h
multipathd/cli_handlers.c
multipathd/cli_handlers.h
multipathd/main.c

index f568287..99d4515 100644 (file)
@@ -716,3 +716,38 @@ 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;
+}
index 07261d8..6c1c493 100644 (file)
@@ -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);
 
index 3ae0bf2..e6674ee 100644 (file)
@@ -431,6 +431,26 @@ 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;
+}
+
 extern char *
 uevent_get_dm_name(struct uevent *uev)
 {
index 192f94a..46596fd 100644 (file)
@@ -30,6 +30,7 @@ int uevent_dispatch(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);
 char *uevent_get_dm_name(struct uevent *uev);
 
 #endif /* _UEVENT_H */
index e4d766a..3a9be1b 100644 (file)
@@ -161,6 +161,7 @@ load_keys (void)
        r += add_key(keys, "fail", FAIL, 0);
        r += add_key(keys, "resize", RESIZE, 0);
        r += add_key(keys, "reset", RESET, 0);
+       r += add_key(keys, "reload", RELOAD, 0);
        r += add_key(keys, "disablequeueing", DISABLEQ, 0);
        r += add_key(keys, "restorequeueing", RESTOREQ, 0);
        r += add_key(keys, "paths", PATHS, 0);
@@ -443,6 +444,7 @@ cli_init (void) {
        add_handler(RESUME+MAP, NULL);
        add_handler(RESIZE+MAP, NULL);
        add_handler(RESET+MAP, NULL);
+       add_handler(RELOAD+MAP, NULL);
        add_handler(DISABLEQ+MAP, NULL);
        add_handler(RESTOREQ+MAP, NULL);
        add_handler(DISABLEQ+MAPS, NULL);
index 918800e..1eff2d1 100644 (file)
@@ -9,6 +9,7 @@ enum {
        __FAIL,
        __RESIZE,
        __RESET,
+       __RELOAD,
        __DISABLEQ,
        __RESTOREQ,
        __PATHS,
@@ -40,6 +41,7 @@ enum {
 #define FAIL           (1 << __FAIL)
 #define RESIZE         (1 << __RESIZE)
 #define RESET          (1 << __RESET)
+#define RELOAD         (1 << __RELOAD)
 #define DISABLEQ       (1 << __DISABLEQ)
 #define RESTOREQ       (1 << __RESTOREQ)
 #define PATHS          (1 << __PATHS)
index ddb80b6..6c1b5dd 100644 (file)
@@ -500,6 +500,28 @@ cli_del_map (void * v, char ** reply, int * len, void * data)
        return rc;
 }
 
+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)
 {
index 9ce5e65..60195ca 100644 (file)
@@ -19,6 +19,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_disable_queueing(void * v, char ** reply, int * len, void * data);
 int cli_disable_all_queueing(void * v, char ** reply, int * len, void * data);
 int cli_restore_queueing(void * v, char ** reply, int * len, void * data);
index 775ecd1..2451960 100644 (file)
@@ -636,6 +636,43 @@ fail:
 }
 
 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;
@@ -749,6 +786,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);
@@ -811,6 +852,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(RESET+MAP, cli_reassign);
        set_handler_callback(REINSTATE+PATH, cli_reinstate);
        set_handler_callback(FAIL+PATH, cli_fail);