libmultipath: support MPATH_UDEV_NO_PATHS_FLAG on map creation
authorMartin Wilck <mwilck@suse.com>
Sat, 2 Sep 2017 22:38:38 +0000 (00:38 +0200)
committerChristophe Varoqui <christophe.varoqui@opensvc.com>
Wed, 20 Sep 2017 15:45:08 +0000 (17:45 +0200)
Some vendor kernels (e.g. SUSE) have supported loading multipath
maps without valid paths for a long time. Without that feature,
problems can occur in failover scenarios when multipathd tries
to (re)load maps after device failure/removal, because multipathd's
attempts to reload the configuration may fail unnecessarily.
The discussion in the kernel community is ongoing
(see e.g. https://patchwork.kernel.org/patch/4579551/).

One corner case of this is creation of a map with only failed
paths. Such maps can be created if the kernel patch mentioned above
is applied. The current udev rules for dm-multipath can't detect
this situation. This patch fixes that by setting
DM_SUBSYSTEM_UDEV_FLAG2, which is already used for the "map reload"
case with no valid paths. Thus no additional udev rules are required
to detect this situation.

Signed-off-by: Martin Wilck <mwilck@suse.com>
libmultipath/devmapper.c

index e701e80..7a3390a 100644 (file)
@@ -300,12 +300,14 @@ dm_device_remove (const char *name, int needsync, int deferred_remove) {
 
 static int
 dm_addmap (int task, const char *target, struct multipath *mpp,
-          char * params, int ro, int skip_kpartx) {
+          char * params, int ro, uint16_t udev_flags) {
        int r = 0;
        struct dm_task *dmt;
        char *prefixed_uuid = NULL;
        uint32_t cookie = 0;
-       uint16_t udev_flags = DM_UDEV_DISABLE_LIBRARY_FALLBACK | ((skip_kpartx == SKIP_KPARTX_ON)? MPATH_UDEV_NO_KPARTX_FLAG : 0);
+
+       /* Need to add this here to allow 0 to be passed in udev_flags */
+       udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
 
        if (!(dmt = libmp_dm_task_create (task)))
                return 0;
@@ -371,15 +373,27 @@ addout:
        return r;
 }
 
+static uint16_t build_udev_flags(const struct multipath *mpp, int reload)
+{
+       /* DM_UDEV_DISABLE_LIBRARY_FALLBACK is added in dm_addmap */
+       return  (mpp->skip_kpartx == SKIP_KPARTX_ON ?
+                MPATH_UDEV_NO_KPARTX_FLAG : 0) |
+               (mpp->nr_active == 0 ?
+                MPATH_UDEV_NO_PATHS_FLAG : 0) |
+               (reload && !mpp->force_udev_reload ?
+                MPATH_UDEV_RELOAD_FLAG : 0);
+}
+
 int dm_addmap_create (struct multipath *mpp, char * params)
 {
        int ro;
+       uint16_t udev_flags = build_udev_flags(mpp, 0);
 
        for (ro = 0; ro <= 1; ro++) {
                int err;
 
                if (dm_addmap(DM_DEVICE_CREATE, TGT_MPATH, mpp, params, ro,
-                             mpp->skip_kpartx))
+                             udev_flags))
                        return 1;
                /*
                 * DM_DEVICE_CREATE is actually DM_DEV_CREATE + DM_TABLE_LOAD.
@@ -405,11 +419,7 @@ int dm_addmap_create (struct multipath *mpp, char * params)
 int dm_addmap_reload(struct multipath *mpp, char *params, int flush)
 {
        int r = 0;
-       uint16_t udev_flags = ((mpp->force_udev_reload)?
-                              0 : MPATH_UDEV_RELOAD_FLAG) |
-                             ((mpp->skip_kpartx == SKIP_KPARTX_ON)?
-                              MPATH_UDEV_NO_KPARTX_FLAG : 0) |
-                             ((mpp->nr_active)? 0 : MPATH_UDEV_NO_PATHS_FLAG);
+       uint16_t udev_flags = build_udev_flags(mpp, 1);
 
        /*
         * DM_DEVICE_RELOAD cannot wait on a cookie, as
@@ -419,12 +429,12 @@ int dm_addmap_reload(struct multipath *mpp, char *params, int flush)
         */
        if (!mpp->force_readonly)
                r = dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp, params,
-                             ADDMAP_RW, SKIP_KPARTX_OFF);
+                             ADDMAP_RW, 0);
        if (!r) {
                if (!mpp->force_readonly && errno != EROFS)
                        return 0;
                r = dm_addmap(DM_DEVICE_RELOAD, TGT_MPATH, mpp,
-                             params, ADDMAP_RO, SKIP_KPARTX_OFF);
+                             params, ADDMAP_RO, 0);
        }
        if (r)
                r = dm_simplecmd(DM_DEVICE_RESUME, mpp->alias, !flush,