[lvm-devel] [RFC][PATCH 4/5] dmeventd filtering failed devices
Takahiro Yasui
tyasui at redhat.com
Wed Sep 30 00:28:18 UTC 2009
This patch filters out failed devices from the device list to prevent
those failed devices from being accessed by lvm commands, lvconvert
and vgreduce.
Signed-off-by: Takahiro Yasui <tyasui at redhat.com>
---
daemons/dmeventd/plugins/mirror/dmeventd_mirror.c | 112 +++++++++++++++++++++-
libdm/.exported_symbols | 1
libdm/libdevmapper.h | 1
libdm/libdm-deptree.c | 39 +++++++
4 files changed, 151 insertions(+), 2 deletions(-)
Index: LVM2.02.54-20090928/daemons/dmeventd/plugins/mirror/dmeventd_mirror.c
===================================================================
--- LVM2.02.54-20090928.orig/daemons/dmeventd/plugins/mirror/dmeventd_mirror.c
+++ LVM2.02.54-20090928/daemons/dmeventd/plugins/mirror/dmeventd_mirror.c
@@ -14,6 +14,7 @@
#include "lvm2cmd.h"
#include "errors.h"
+#include "kdev_t.h"
#include <libdevmapper.h>
#include <libdevmapper-event.h>
@@ -42,10 +43,12 @@ struct device {
char *dname; /* device name (ex: /dev/sda) */
unsigned int major;
unsigned int minor;
+ int failed;
};
struct device_info {
struct dm_list dev_all; /* all devices in the vg */
+ struct dm_list dev_failed; /* failed devices */
char filter_str[CMD_SIZE];
};
@@ -85,6 +88,9 @@ static void _build_filter_str(struct dev
int len = 0, size, ct = 0;
dm_list_iterate_items(dev, &devi->dev_all) {
+ if (dev->failed)
+ continue;
+
size = dm_snprintf(devi->filter_str+len, CMD_SIZE-len,
"%s\"a|%s$|\"",
ct++ ? "," : "filter=[", dev->dname);
@@ -106,10 +112,107 @@ err:
return;
}
+/*
+ * Register major:minor number of failed device. This function assumes to be
+ * called at most 9 times (8 mirror legs + 1 mirror log) and memory should
+ * be allocated beforehand. (360 byte = 40 byte * 9 for now)
+ */
+static void _register_failed_device(struct device_info *devi, char *dev_str)
+{
+ unsigned int major, minor;
+ struct device *dev;
+
+ if (!devi)
+ return;
+
+ if (sscanf(dev_str, "%u:%u", &major, &minor) != 2) {
+ syslog(LOG_ERR, "Unrecognized device number (%s)\n",
+ dev_str);
+ return;
+ }
+
+ if (!(dev = dm_malloc(sizeof(*dev))))
+ return;
+
+ dev->major = major;
+ dev->minor = minor;
+
+ dm_list_add(&devi->dev_failed, &dev->list);
+}
+
+static void _release_failed_list(struct device_info *devi)
+{
+ struct device *dev, *devt;
+
+ if (!devi)
+ return;
+
+ dm_list_iterate_items_safe(dev, devt, &devi->dev_failed) {
+ dm_list_del(&dev->list);
+ dm_free(dev);
+ }
+}
+
+static void _mark_device_disabled(struct device_info *devi,
+ unsigned int major, unsigned int minor)
+{
+ struct device *dev;
+
+ dm_list_iterate_items(dev, &devi->dev_all) {
+ if (dev->major == major && dev->minor == minor)
+ dev->failed = 1;
+ }
+}
+
+static void _walk_tree_and_disable_devices(struct dm_tree_node *node,
+ struct device_info *devi)
+{
+ struct dm_tree_node *child;
+ void *handle = NULL;
+ const struct dm_info *info;
+
+ while ((child = dm_tree_next_child(&handle, node, 0))) {
+ if (dm_tree_node_num_children(child, 0))
+ _walk_tree_and_disable_devices(child, devi);
+ else {
+ info = dm_tree_node_get_info(child);
+ _mark_device_disabled(devi, info->major, info->minor);
+ }
+ }
+}
+
+static void _disable_devices(struct device_info *devi, struct dm_tree *dtree,
+ unsigned int major, unsigned int minor)
+{
+ struct dm_tree_node *node;
+
+ if (!(node = dm_tree_find_node(dtree, major, minor))) {
+ syslog(LOG_ERR, "device (%u:%u) doesn't exist.\n",
+ major, minor);
+ return;
+ }
+
+ _walk_tree_and_disable_devices(node, devi);
+}
+
static void _create_filter(struct device_info *devi)
{
+ struct dm_tree *dtree;
+ struct device *dev;
+
if (!devi)
return;
+
+ if (!(dtree = dm_build_deptree())) {
+ syslog(LOG_ERR, "Failed to get device information\n");
+ return;
+ }
+
+ dm_list_iterate_items(dev, &devi->dev_failed)
+ _disable_devices(devi, dtree, dev->major, dev->minor);
+
+ dm_tree_free(dtree);
+
_build_filter_str(devi);
}
@@ -119,7 +222,7 @@ static void _destroy_filter(struct devic
devi->filter_str[0] = '\0';
}
-static int _get_mirror_event(char *params)
+static int _get_mirror_event(char *params, struct device_info *devi)
{
int i, r = ME_INSYNC;
char **args = NULL;
@@ -160,6 +263,7 @@ static int _get_mirror_event(char *param
for (i = 0; i < num_devs; i++)
if (dev_status_str[i] == 'D') {
syslog(LOG_ERR, "Mirror device, %s, has failed.\n", args[i]);
+ _register_failed_device(devi, args[i]);
r = ME_FAILURE;
}
@@ -167,6 +271,7 @@ static int _get_mirror_event(char *param
if (log_argc > 1 && log_status_str[0] == 'D') {
syslog(LOG_ERR, "Log device, %s, has failed.\n",
args[2 + num_devs + log_argc]);
+ _register_failed_device(devi, args[2 + num_devs + log_argc]);
r = ME_FAILURE;
}
@@ -278,7 +383,7 @@ void process_event(struct dm_task *dmt,
continue;
}
- switch(_get_mirror_event(params)) {
+ switch(_get_mirror_event(params, devi)) {
case ME_INSYNC:
/* FIXME: all we really know is that this
_part_ of the device is in sync
@@ -304,6 +409,8 @@ void process_event(struct dm_task *dmt,
/* FIXME Provide value then! */
syslog(LOG_INFO, "Unknown event received.\n");
}
+
+ _release_failed_list(devi);
} while (next);
pthread_mutex_unlock(&_event_mutex);
@@ -355,6 +462,7 @@ static struct device_info *alloc_device_
return NULL;
dm_list_init(&devi->dev_all);
+ dm_list_init(&devi->dev_failed);
return devi;
}
Index: LVM2.02.54-20090928/libdm/.exported_symbols
===================================================================
--- LVM2.02.54-20090928.orig/libdm/.exported_symbols
+++ LVM2.02.54-20090928/libdm/.exported_symbols
@@ -81,6 +81,7 @@ dm_tree_skip_lockfs
dm_tree_use_no_flush_suspend
dm_tree_set_cookie
dm_tree_get_cookie
+dm_build_deptree
dm_is_dm_major
dm_mknodes
dm_malloc_aux
Index: LVM2.02.54-20090928/libdm/libdevmapper.h
===================================================================
--- LVM2.02.54-20090928.orig/libdm/libdevmapper.h
+++ LVM2.02.54-20090928/libdm/libdevmapper.h
@@ -435,6 +435,7 @@ void dm_tree_node_set_read_ahead(struct
void dm_tree_set_cookie(struct dm_tree_node *node, uint32_t cookie);
uint32_t dm_tree_get_cookie(struct dm_tree_node *node);
+struct dm_tree *dm_build_deptree(void);
/*****************************************************************************
* Library functions
Index: LVM2.02.54-20090928/libdm/libdm-deptree.c
===================================================================
--- LVM2.02.54-20090928.orig/libdm/libdm-deptree.c
+++ LVM2.02.54-20090928/libdm/libdm-deptree.c
@@ -1948,3 +1948,42 @@ uint32_t dm_tree_get_cookie(struct dm_tr
{
return node->dtree->cookie;
}
+
+struct dm_tree *dm_build_deptree(void)
+{
+ struct dm_tree *dtree;
+ struct dm_names *names;
+ struct dm_task *dmt = NULL;
+ unsigned next = 0;
+
+ if (!(dtree = dm_tree_create()))
+ return NULL;
+
+ if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
+ goto err;
+
+ if (!dm_task_run(dmt))
+ goto err;
+
+ if (!(names = dm_task_get_names(dmt)))
+ goto err;
+
+ if (!names->dev)
+ goto err;
+
+ do {
+ names = (void *)names + next;
+ if (!dm_tree_add_dev(dtree,
+ (unsigned)MAJOR(names->dev),
+ (unsigned)MINOR(names->dev)))
+ goto err;
+ next = names->next;
+ } while (next);
+
+ return dtree;
+err:
+ if (dmt)
+ dm_task_destroy(dmt);
+ dm_tree_free(dtree);
+ return NULL;
+}
--
Takahiro Yasui
Hitachi Computer Products (America), Inc.
More information about the lvm-devel
mailing list