summaryrefslogtreecommitdiff
path: root/lib/device/dev-mpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/device/dev-mpath.c')
-rw-r--r--lib/device/dev-mpath.c181
1 files changed, 170 insertions, 11 deletions
diff --git a/lib/device/dev-mpath.c b/lib/device/dev-mpath.c
index cbbad9dc9..6eed03c5b 100644
--- a/lib/device/dev-mpath.c
+++ b/lib/device/dev-mpath.c
@@ -17,12 +17,14 @@
#include "lib/activate/activate.h"
#include "lib/commands/toolcontext.h"
#include "lib/device/device_id.h"
+#include "lib/datastruct/str_list.h"
#ifdef UDEV_SYNC_SUPPORT
#include <libudev.h>
#include "lib/device/dev-ext-udev-constants.h"
#endif
#include <dirent.h>
+#include <ctype.h>
#define MPATH_PREFIX "mpath-"
@@ -35,15 +37,167 @@
* If dm-3 is not an mpath device, then the constant "1" is stored in
* the hash table with the key of the dm minor number.
*/
-static struct dm_pool *_hash_mem;
+static struct dm_pool *_wwid_mem;
static struct dm_hash_table *_minor_hash_tab;
static struct dm_hash_table *_wwid_hash_tab;
+static struct dm_list _ignored;
+static struct dm_list _ignored_exceptions;
#define MAX_WWID_LINE 512
-/*
- * do we need to check the multipath.conf blacklist?
- */
+static void _read_blacklist_file(const char *path)
+{
+ FILE *fp;
+ char line[MAX_WWID_LINE];
+ char wwid[MAX_WWID_LINE];
+ char *word, *p;
+ int section_black = 0;
+ int section_exceptions = 0;
+ int found_quote;
+ int found_three;
+ int i, j;
+
+ if (!(fp = fopen(path, "r")))
+ return;
+
+ while (fgets(line, sizeof(line), fp)) {
+ word = NULL;
+
+ /* skip initial white space on the line */
+ for (i = 0; i < MAX_WWID_LINE; i++) {
+ if ((line[i] == '\n') || (line[i] == '\0'))
+ break;
+ if (isspace(line[i]))
+ continue;
+ word = &line[i];
+ break;
+ }
+
+ if (!word || word[0] == '#')
+ continue;
+
+ /* identify the start of the section we want to read */
+ if (strchr(word, '{')) {
+ if (!strncmp(word, "blacklist_exceptions", 20))
+ section_exceptions = 1;
+ else if (!strncmp(word, "blacklist", 9))
+ section_black = 1;
+ continue;
+ }
+ /* identify the end of the section we've been reading */
+ if (strchr(word, '}')) {
+ section_exceptions = 0;
+ section_black = 0;
+ continue;
+ }
+ /* skip lines that are not in a section we want */
+ if (!section_black && !section_exceptions)
+ continue;
+
+ /*
+ * read a wwid from the blacklist{_exceptions} section.
+ * does not recognize other non-wwid entries in the
+ * section, and skips those (should the entire mp
+ * config filtering be disabled if non-wwids are seen?
+ */
+ if (!(p = strstr(word, "wwid")))
+ continue;
+
+ i += 4; /* skip "wwid" */
+
+ /*
+ * copy wwid value from the line.
+ * the wwids copied here need to match the
+ * wwids read from /etc/multipath/wwids,
+ * which are matched to wwids from sysfs.
+ */
+
+ memset(wwid, 0, sizeof(wwid));
+ found_quote = 0;
+ found_three = 0;
+ j = 0;
+
+ for (; i < MAX_WWID_LINE; i++) {
+ if ((line[i] == '\n') || (line[i] == '\0'))
+ break;
+ if (!j && isspace(line[i]))
+ continue;
+ if (isspace(line[i]))
+ break;
+ /* quotes around wwid are optional */
+ if ((line[i] == '"') && !found_quote) {
+ found_quote = 1;
+ continue;
+ }
+ /* second quote is end of wwid */
+ if ((line[i] == '"') && found_quote)
+ break;
+ /* ignore first "3" in wwid */
+ if ((line[i] == '3') && !found_three) {
+ found_three = 1;
+ continue;
+ }
+
+ wwid[j] = line[i];
+ j++;
+ }
+
+ if (j < 8)
+ continue;
+
+ log_debug("multipath wwid %s in %s %s",
+ wwid, section_exceptions ? "blacklist_exceptions" : "blacklist", path);
+
+ if (section_exceptions) {
+ if (!str_list_add(_wwid_mem, &_ignored_exceptions, dm_pool_strdup(_wwid_mem, wwid)))
+ stack;
+ } else {
+ if (!str_list_add(_wwid_mem, &_ignored, dm_pool_strdup(_wwid_mem, wwid)))
+ stack;
+ }
+ }
+
+ if (fclose(fp))
+ stack;
+}
+
+static void _read_wwid_exclusions(void)
+{
+ char path[PATH_MAX] = { 0 };
+ DIR *dir;
+ struct dirent *de;
+ struct dm_str_list *sl, *sl2;
+ int rem_count = 0;
+
+ _read_blacklist_file("/etc/multipath.conf");
+
+ if ((dir = opendir("/etc/multipath/conf.d"))) {
+ while ((de = readdir(dir))) {
+ if (de->d_name[0] == '.')
+ continue;
+ snprintf(path, PATH_MAX-1, "/etc/multipath/conf.d/%s", de->d_name);
+ _read_blacklist_file(path);
+ }
+ closedir(dir);
+ }
+
+ /* for each wwid in ignored_exceptions, remove it from ignored */
+
+ dm_list_iterate_items_safe(sl, sl2, &_ignored) {
+ if (str_list_match_item(&_ignored_exceptions, sl->str))
+ str_list_del(&_ignored, sl->str);
+ }
+
+ /* for each wwid in ignored, remove it from wwid_hash */
+
+ dm_list_iterate_items(sl, &_ignored) {
+ dm_hash_remove_binary(_wwid_hash_tab, sl->str, strlen(sl->str));
+ rem_count++;
+ }
+
+ if (rem_count)
+ log_debug("multipath config ignored %d wwids", rem_count);
+}
static void _read_wwid_file(const char *config_wwids_file)
{
@@ -93,6 +247,9 @@ int dev_mpath_init(const char *config_wwids_file)
struct dm_hash_table *minor_tab;
struct dm_hash_table *wwid_tab;
+ dm_list_init(&_ignored);
+ dm_list_init(&_ignored_exceptions);
+
if (!(mem = dm_pool_create("mpath", 256))) {
log_error("mpath pool creation failed.");
return 0;
@@ -104,7 +261,7 @@ int dev_mpath_init(const char *config_wwids_file)
return 0;
}
- _hash_mem = mem;
+ _wwid_mem = mem;
_minor_hash_tab = minor_tab;
/* multipath_wwids_file="" disables the use of the file */
@@ -116,16 +273,18 @@ int dev_mpath_init(const char *config_wwids_file)
if (!(wwid_tab = dm_hash_create(110))) {
log_error("mpath hash table creation failed.");
dm_hash_destroy(_minor_hash_tab);
- dm_pool_destroy(_hash_mem);
+ dm_pool_destroy(_wwid_mem);
_minor_hash_tab = NULL;
- _hash_mem = NULL;
+ _wwid_mem = NULL;
return 0;
}
_wwid_hash_tab = wwid_tab;
- if (config_wwids_file)
+ if (config_wwids_file) {
_read_wwid_file(config_wwids_file);
+ _read_wwid_exclusions();
+ }
return 1;
}
@@ -136,12 +295,12 @@ void dev_mpath_exit(void)
dm_hash_destroy(_minor_hash_tab);
if (_wwid_hash_tab)
dm_hash_destroy(_wwid_hash_tab);
- if (_hash_mem)
- dm_pool_destroy(_hash_mem);
+ if (_wwid_mem)
+ dm_pool_destroy(_wwid_mem);
_minor_hash_tab = NULL;
_wwid_hash_tab = NULL;
- _hash_mem = NULL;
+ _wwid_mem = NULL;
}