@@ -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)
{
@@ -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);
@@ -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)
@@ -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;
@@ -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;
@@ -764,6 +768,32 @@ ble_except_wwid_handler(vector strvec)
}
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)
{
return alloc_ble_device(conf->blist_device);
@@ -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);
@@ -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;
@@ -1078,6 +1078,19 @@ snprint_blacklist_report (char * buff, int 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"
"- blacklist:\n");
if (snprint_blacklist_group(buff, len, &fwd, &conf->blist_wwid) == 0)
@@ -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;
@@ -70,6 +70,7 @@
# }
#}
#blacklist_exceptions {
+# property "(ID_SCSI_VPD|ID_WWN)"
#}
#devices {
# device {
@@ -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
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 | 105 +++++++++++++++++++++++++++++++++++--------- libmultipath/blacklist.h | 19 +++++--- libmultipath/config.c | 19 +++++++- libmultipath/config.h | 2 + libmultipath/dict.c | 36 ++++++++++++++- libmultipath/discovery.c | 3 ++ libmultipath/print.c | 31 +++++++++++++ multipath.conf.defaults | 1 + multipath/multipath.conf.5 | 19 +++++++- 9 files changed, 203 insertions(+), 32 deletions(-)