multipath: Implement 'property' blacklist
authorHannes Reinecke <hare@suse.de>
Tue, 16 Jul 2013 07:13:13 +0000 (09:13 +0200)
committerChristophe Varoqui <christophe.varoqui@opensvc.com>
Tue, 16 Jul 2013 19:50:42 +0000 (21:50 +0200)
Multipath can only handle device properly which support the VPD
page 0x83. Originally this was ensured by 'scsi_id', which would
not present an ID_SERIAL value in these cases.
With the move to udev 'ID_SERIAL' is now always present, so
multipath would try to attach to _all_ SCSI devices.
This patch implements an 'property' blacklist, which allows to
blacklist a device based on the existence of udev properties.
Any device not providing the udev property from the whitelist
will be ignored.
The default whitelist is set to '(ID_WWN|ID_SCSI_VPD)'.

Signed-off-by: Hannes Reinecke <hare@suse.de>
libmultipath/blacklist.c
libmultipath/blacklist.h
libmultipath/config.c
libmultipath/config.h
libmultipath/dict.c
libmultipath/discovery.c
libmultipath/print.c
multipath.conf.defaults
multipath/multipath.conf.5

index 49a40f9..d597350 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright (c) 2004, 2005 Christophe Varoqui
  */
 #include <stdio.h>
+#include <libudev.h>
 
 #include "checkers.h"
 #include "memory.h"
@@ -96,7 +97,7 @@ set_ble_device (vector blist, char * vendor, char * product, int origin)
 }
 
 int
-_blacklist_exceptions (vector elist, char * str)
+_blacklist_exceptions (vector elist, const char * str)
 {
        int i;
        struct blentry * ele;
@@ -109,7 +110,7 @@ _blacklist_exceptions (vector elist, char * str)
 }
 
 int
-_blacklist (vector blist, char * str)
+_blacklist (vector blist, const char * str)
 {
        int i;
        struct blentry * ble;
@@ -175,6 +176,12 @@ setup_default_blist (struct config * conf)
        if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT))
                return 1;
 
+       str = STRDUP("(ID_SCSI_VPD|ID_WWN)");
+       if (!str)
+               return 1;
+       if (store_ble(conf->elist_property, str, ORIGIN_DEFAULT))
+               return 1;
+
        vector_foreach_slot (conf->hwtable, hwe, i) {
                if (hwe->bl_product) {
                        if (_blacklist_device(conf->blist_device, hwe->vendor,
@@ -196,16 +203,20 @@ setup_default_blist (struct config * conf)
        return 0;
 }
 
-#define LOG_BLIST(M) \
-       if (vendor && product)                                           \
-               condlog(3, "%s: (%s:%s) %s", dev, vendor, product, (M)); \
-       else if (wwid)                                                   \
-               condlog(3, "%s: (%s) %s", dev, wwid, (M));               \
-       else                                                             \
-               condlog(3, "%s: %s", dev, (M))
+#define LOG_BLIST(M,S)                                                 \
+       if (vendor && product)                                          \
+               condlog(3, "%s: (%s:%s) %s %s",                         \
+                       dev, vendor, product, (M), (S));                \
+       else if (wwid)                                                  \
+               condlog(3, "%s: %s %s %s", dev, (M), wwid, (S));        \
+       else if (env)                                                   \
+               condlog(3, "%s: %s %s %s", dev, (M), env, (S));         \
+       else                                                            \
+               condlog(3, "%s: %s %s", dev, (M), (S))
 
 void
-log_filter (char *dev, char *vendor, char *product, char *wwid, int r)
+log_filter (const char *dev, char *vendor, char *product, char *wwid,
+           const char *env, int r)
 {
        /*
         * Try to sort from most likely to least.
@@ -214,22 +225,31 @@ log_filter (char *dev, char *vendor, char *product, char *wwid, int r)
        case MATCH_NOTHING:
                break;
        case MATCH_DEVICE_BLIST:
-               LOG_BLIST("vendor/product blacklisted");
+               LOG_BLIST("vendor/product", "blacklisted");
                break;
        case MATCH_WWID_BLIST:
-               LOG_BLIST("wwid blacklisted");
+               LOG_BLIST("wwid", "blacklisted");
                break;
        case MATCH_DEVNODE_BLIST:
-               LOG_BLIST("device node name blacklisted");
+               LOG_BLIST("device node name", "blacklisted");
+               break;
+       case MATCH_PROPERTY_BLIST:
+               LOG_BLIST("udev property", "blacklisted");
                break;
        case MATCH_DEVICE_BLIST_EXCEPT:
-               LOG_BLIST("vendor/product whitelisted");
+               LOG_BLIST("vendor/product", "whitelisted");
                break;
        case MATCH_WWID_BLIST_EXCEPT:
-               LOG_BLIST("wwid whitelisted");
+               LOG_BLIST("wwid", "whitelisted");
                break;
        case MATCH_DEVNODE_BLIST_EXCEPT:
-               LOG_BLIST("device node name whitelisted");
+               LOG_BLIST("device node name", "whitelisted");
+               break;
+       case MATCH_PROPERTY_BLIST_EXCEPT:
+               LOG_BLIST("udev property", "whitelisted");
+               break;
+       case MATCH_PROPERTY_BLIST_MISSING:
+               LOG_BLIST("blacklisted,", "udev property missing");
                break;
        }
 }
@@ -250,7 +270,7 @@ int
 filter_device (vector blist, vector elist, char * vendor, char * product)
 {
        int r = _filter_device(blist, elist, vendor, product);
-       log_filter(NULL, vendor, product, NULL, r);
+       log_filter(NULL, vendor, product, NULL, NULL, r);
        return r;
 }
 
@@ -270,7 +290,7 @@ int
 filter_devnode (vector blist, vector elist, char * dev)
 {
        int r = _filter_devnode(blist, elist, dev);
-       log_filter(dev, NULL, NULL, NULL, r);
+       log_filter(dev, NULL, NULL, NULL, NULL, r);
        return r;
 }
 
@@ -290,7 +310,7 @@ int
 filter_wwid (vector blist, vector elist, char * wwid)
 {
        int r = _filter_wwid(blist, elist, wwid);
-       log_filter(NULL, NULL, NULL, wwid, r);
+       log_filter(NULL, NULL, NULL, wwid, NULL, r);
        return r;
 }
 
@@ -314,10 +334,55 @@ int
 filter_path (struct config * conf, struct path * pp)
 {
        int r=_filter_path(conf, pp);
-       log_filter(pp->dev, pp->vendor_id, pp->product_id, pp->wwid, r);
+       log_filter(pp->dev, pp->vendor_id, pp->product_id, pp->wwid, NULL, r);
        return r;
 }
 
+int
+_filter_property (struct config *conf, const char *env)
+{
+       if (_blacklist_exceptions(conf->elist_property, env))
+               return MATCH_PROPERTY_BLIST_EXCEPT;
+       if (_blacklist(conf->blist_property, env))
+               return MATCH_PROPERTY_BLIST;
+
+       return 0;
+}
+
+int
+filter_property(struct config * conf, struct udev_device * udev)
+{
+       const char *devname = udev_device_get_sysname(udev);
+       struct udev_list_entry *list_entry;
+       int r;
+
+       if (!udev)
+               return 0;
+
+       udev_list_entry_foreach(list_entry,
+                               udev_device_get_properties_list_entry(udev)) {
+               const char *env;
+
+               env = udev_list_entry_get_name(list_entry);
+               if (!env)
+                       continue;
+
+               r = _filter_property(conf, env);
+               if (r) {
+                       log_filter(devname, NULL, NULL, NULL, env, r);
+                       return r;
+               }
+       }
+
+       /*
+        * This is the inverse of the 'normal' matching;
+        * the environment variable _has_ to match.
+        */
+       log_filter(devname, NULL, NULL, NULL, NULL,
+                  MATCH_PROPERTY_BLIST_MISSING);
+       return MATCH_PROPERTY_BLIST_MISSING;
+}
+
 void
 free_blacklist (vector blist)
 {
index cdbebef..0e90e9a 100644 (file)
@@ -1,15 +1,19 @@
 #ifndef _BLACKLIST_H
 #define _BLACKLIST_H
 
+#include <libudev.h>
 #include "regex.h"
 
-#define MATCH_NOTHING       0
-#define MATCH_WWID_BLIST    1
-#define MATCH_DEVICE_BLIST  2
-#define MATCH_DEVNODE_BLIST 3
-#define MATCH_WWID_BLIST_EXCEPT    -MATCH_WWID_BLIST
-#define MATCH_DEVICE_BLIST_EXCEPT  -MATCH_DEVICE_BLIST
-#define MATCH_DEVNODE_BLIST_EXCEPT -MATCH_DEVNODE_BLIST
+#define MATCH_NOTHING        0
+#define MATCH_WWID_BLIST     1
+#define MATCH_DEVICE_BLIST   2
+#define MATCH_DEVNODE_BLIST  3
+#define MATCH_PROPERTY_BLIST 4
+#define MATCH_PROPERTY_BLIST_MISSING 5
+#define MATCH_WWID_BLIST_EXCEPT     -MATCH_WWID_BLIST
+#define MATCH_DEVICE_BLIST_EXCEPT   -MATCH_DEVICE_BLIST
+#define MATCH_DEVNODE_BLIST_EXCEPT  -MATCH_DEVNODE_BLIST
+#define MATCH_PROPERTY_BLIST_EXCEPT -MATCH_PROPERTY_BLIST
 
 struct blentry {
        char * str;
@@ -31,6 +35,7 @@ int filter_devnode (vector, vector, char *);
 int filter_wwid (vector, vector, char *);
 int filter_device (vector, vector, char *, char *);
 int filter_path (struct config *, struct path *);
+int filter_property(struct config *, struct udev_device *);
 int store_ble (vector, char *, int);
 int set_ble_device (vector, char *, char *, int);
 void free_blacklist (vector);
index 8013a07..9b7adda 100644 (file)
@@ -513,10 +513,12 @@ free_config (struct config * conf)
 
        free_blacklist(conf->blist_devnode);
        free_blacklist(conf->blist_wwid);
+       free_blacklist(conf->blist_property);
        free_blacklist_device(conf->blist_device);
 
        free_blacklist(conf->elist_devnode);
        free_blacklist(conf->elist_wwid);
+       free_blacklist(conf->elist_property);
        free_blacklist_device(conf->elist_device);
 
        free_mptable(conf->mptable);
@@ -619,8 +621,12 @@ load_config (char * file, struct udev *udev)
                if (!conf->blist_device)
                        goto out;
        }
-       if (setup_default_blist(conf))
-               goto out;
+       if (conf->blist_property == NULL) {
+               conf->blist_property = vector_alloc();
+
+               if (!conf->blist_property)
+                       goto out;
+       }
 
        if (conf->elist_devnode == NULL) {
                conf->elist_devnode = vector_alloc();
@@ -642,6 +648,15 @@ load_config (char * file, struct udev *udev)
                        goto out;
        }
 
+       if (conf->elist_property == NULL) {
+               conf->elist_property = vector_alloc();
+
+               if (!conf->elist_property)
+                       goto out;
+       }
+       if (setup_default_blist(conf))
+               goto out;
+
        if (conf->mptable == NULL) {
                conf->mptable = vector_alloc();
                if (!conf->mptable)
index ca65f88..9c467e8 100644 (file)
@@ -136,9 +136,11 @@ struct config {
        vector blist_devnode;
        vector blist_wwid;
        vector blist_device;
+       vector blist_property;
        vector elist_devnode;
        vector elist_wwid;
        vector elist_device;
+       vector elist_property;
 };
 
 struct config * conf;
index 0408e03..0bf9587 100644 (file)
@@ -691,8 +691,10 @@ blacklist_handler(vector strvec)
        conf->blist_devnode = vector_alloc();
        conf->blist_wwid = vector_alloc();
        conf->blist_device = vector_alloc();
+       conf->blist_property = vector_alloc();
 
-       if (!conf->blist_devnode || !conf->blist_wwid || !conf->blist_device)
+       if (!conf->blist_devnode || !conf->blist_wwid ||
+           !conf->blist_device || !conf->blist_property)
                return 1;
 
        return 0;
@@ -704,8 +706,10 @@ blacklist_exceptions_handler(vector strvec)
        conf->elist_devnode = vector_alloc();
        conf->elist_wwid = vector_alloc();
        conf->elist_device = vector_alloc();
+       conf->elist_property = vector_alloc();
 
-       if (!conf->elist_devnode || !conf->elist_wwid || !conf->elist_device)
+       if (!conf->elist_devnode || !conf->elist_wwid ||
+           !conf->elist_device || !conf->elist_property)
                return 1;
 
        return 0;
@@ -763,6 +767,32 @@ ble_except_wwid_handler(vector strvec)
        return store_ble(conf->elist_wwid, buff, ORIGIN_CONFIG);
 }
 
+static int
+ble_property_handler(vector strvec)
+{
+       char * buff;
+
+       buff = set_value(strvec);
+
+       if (!buff)
+               return 1;
+
+       return store_ble(conf->blist_property, buff, ORIGIN_CONFIG);
+}
+
+static int
+ble_except_property_handler(vector strvec)
+{
+       char * buff;
+
+       buff = set_value(strvec);
+
+       if (!buff)
+               return 1;
+
+       return store_ble(conf->elist_property, buff, ORIGIN_CONFIG);
+}
+
 static int
 ble_device_handler(vector strvec)
 {
@@ -2830,6 +2860,7 @@ init_keywords(void)
        install_keyword_root("blacklist", &blacklist_handler);
        install_keyword_multi("devnode", &ble_devnode_handler, &snprint_ble_simple);
        install_keyword_multi("wwid", &ble_wwid_handler, &snprint_ble_simple);
+       install_keyword_multi("property", &ble_property_handler, &snprint_ble_simple);
        install_keyword_multi("device", &ble_device_handler, NULL);
        install_sublevel();
        install_keyword("vendor", &ble_vendor_handler, &snprint_bled_vendor);
@@ -2838,6 +2869,7 @@ init_keywords(void)
        install_keyword_root("blacklist_exceptions", &blacklist_exceptions_handler);
        install_keyword_multi("devnode", &ble_except_devnode_handler, &snprint_ble_simple);
        install_keyword_multi("wwid", &ble_except_wwid_handler, &snprint_ble_simple);
+       install_keyword_multi("property", &ble_except_property_handler, &snprint_ble_simple);
        install_keyword_multi("device", &ble_except_device_handler, NULL);
        install_sublevel();
        install_keyword("vendor", &ble_except_vendor_handler, &snprint_bled_vendor);
index c264c82..f305aa7 100644 (file)
@@ -82,6 +82,9 @@ path_discover (vector pathvec, struct config * conf,
        if (!devname)
                return 0;
 
+       if (filter_property(conf, udevice) > 0)
+               return 0;
+
        if (filter_devnode(conf->blist_devnode, conf->elist_devnode,
                           (char *)devname) > 0)
                return 0;
index b6d08b7..7feeb26 100644 (file)
@@ -1076,6 +1076,19 @@ snprint_blacklist_report (char * buff, int len)
        if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_devnode) == 0)
                return len;
 
+       if ((len - fwd - threshold) <= 0)
+               return len;
+       fwd += snprintf(buff + fwd, len - fwd, "udev property rules:\n"
+                                              "- blacklist:\n");
+       if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_property))
+               return len;
+
+       if ((len - fwd - threshold) <= 0)
+               return len;
+       fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
+       if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_property) == 0)
+               return len;
+
        if ((len - fwd - threshold) <= 0)
                return len;
        fwd += snprintf(buff + fwd, len - fwd, "wwid rules:\n"
@@ -1143,6 +1156,15 @@ snprint_blacklist (char * buff, int len)
                if (fwd > len)
                        return len;
        }
+       vector_foreach_slot (conf->blist_property, ble, i) {
+               kw = find_keyword(rootkw->sub, "property");
+               if (!kw)
+                       return 0;
+               fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
+                                      kw, ble);
+               if (fwd > len)
+                       return len;
+       }
        rootkw = find_keyword(rootkw->sub, "device");
        if (!rootkw)
                return 0;
@@ -1211,6 +1233,15 @@ snprint_blacklist_except (char * buff, int len)
                if (fwd > len)
                        return len;
        }
+       vector_foreach_slot (conf->elist_property, ele, i) {
+               kw = find_keyword(rootkw->sub, "property");
+               if (!kw)
+                       return 0;
+               fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
+                                      kw, ele);
+               if (fwd > len)
+                       return len;
+       }
        rootkw = find_keyword(rootkw->sub, "device");
        if (!rootkw)
                return 0;
index cd13369..3add441 100644 (file)
@@ -68,6 +68,7 @@
 #      }
 #}
 #blacklist_exceptions {
+#      property "(ID_SCSI_VPD|ID_WWN)"
 #}
 #devices {
 #      device {
index a937db9..0fd3035 100644 (file)
@@ -422,6 +422,9 @@ The \fIWorld Wide Identification\fR of a device.
 .B devnode
 Regular expression of the device nodes to be excluded.
 .TP
+.B property
+Regular expresion of the udev property to be excluded.
+.TP
 .B device
 Subsection for the device description. This subsection recognizes the
 .I vendor
@@ -446,8 +449,12 @@ The following keywords are recognized:
 .B wwid
 The \fIWorld Wide Identification\fR of a device.
 .TP
+.B property
+Regular expresion of the udev property to be whitelisted. Defaults to
+.I (ID_WWN|ID_SCSI_VPD)
+.TP
 .B devnode
-Regular expression of the device nodes to be excluded.
+Regular expression of the device nodes to be whitelisted.
 .TP
 .B device
 Subsection for the device description. This subsection recognizes the
@@ -457,6 +464,16 @@ and
 keywords. For a full description of these keywords please see the
 .I devices
 section description.
+.LP
+The
+.I property
+blacklist and whitelist handling is different from the usual handling
+in the sense that the whitelist
+.B has
+to be set, otherwise the device will be blacklisted.
+In these cases the message
+.I blacklisted, udev property missing
+will be displayed.
 .SH "multipaths section"
 The only recognized attribute for the
 .B multipaths