[lvm-devel] [RFC][PATCH 3/5] add filtering function to dmeventd
Takahiro Yasui
tyasui at redhat.com
Wed Sep 30 00:28:15 UTC 2009
This patch adds a device structure to maintain a device list in dmeventd.
When dmeventd detects an error, a filter string is generated and passed to
lvconvert and vgreduce commands by "--config" option.
Signed-off-by: Takahiro Yasui <tyasui at redhat.com>
---
daemons/dmeventd/plugins/mirror/dmeventd_mirror.c | 205 +++++++++++++++++++++-
1 file changed, 196 insertions(+), 9 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
@@ -32,6 +32,23 @@
#define ME_INSYNC 1
#define ME_FAILURE 2
+#define CMD_SIZE 256 /* FIXME Use system restriction */
+
+/*
+ * private data structure
+ */
+struct device {
+ struct dm_list list;
+ char *dname; /* device name (ex: /dev/sda) */
+ unsigned int major;
+ unsigned int minor;
+};
+
+struct device_info {
+ struct dm_list dev_all; /* all devices in the vg */
+ char filter_str[CMD_SIZE];
+};
+
/*
* register_device() is called first and performs initialisation.
* Only one device may be registered or unregistered at a time.
@@ -51,6 +68,57 @@ static void *_lvm_handle = NULL;
*/
static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#define DEVICE_FILTER_STR(devi) \
+ ((devi) && strlen((devi)->filter_str) ? (devi)->filter_str : "")
+
+#define DEVICE_CONFIG_PREP_STR(devi) \
+ ((devi) && strlen((devi)->filter_str) ? "--config devices{" : "")
+
+#define DEVICE_CONFIG_POST_STR(devi) \
+ ((devi) && strlen((devi)->filter_str) ? "}" : "")
+
+
+static void _build_filter_str(struct device_info *devi)
+{
+ struct device *dev;
+ int len = 0, size, ct = 0;
+
+ dm_list_iterate_items(dev, &devi->dev_all) {
+ size = dm_snprintf(devi->filter_str+len, CMD_SIZE-len,
+ "%s\"a|%s$|\"",
+ ct++ ? "," : "filter=[", dev->dname);
+ if (size < 0)
+ goto err;
+ len += size;
+ }
+
+ size = dm_snprintf(devi->filter_str+len, CMD_SIZE-len,
+ "%s\"r|.*|\"]", ct ? "," : "");
+ if (size < 0)
+ goto err;
+
+ return;
+
+err:
+ syslog(LOG_ERR, "Unable to form filter string");
+ devi->filter_str[0] = '\0';
+ return;
+}
+
+static void _create_filter(struct device_info *devi)
+{
+ if (!devi)
+ return;
+ _build_filter_str(devi);
+}
+
+static void _destroy_filter(struct device_info *devi)
+{
+ if (devi)
+ devi->filter_str[0] = '\0';
+}
+
static int _get_mirror_event(char *params)
{
int i, r = ME_INSYNC;
@@ -138,10 +206,9 @@ static void _temporary_log_fn(int level,
syslog(LOG_DEBUG, "%s", format);
}
-static int _remove_failed_devices(const char *device)
+static int _remove_failed_devices(const char *device, struct device_info *devi)
{
int r;
-#define CMD_SIZE 256 /* FIXME Use system restriction */
char cmd_str[CMD_SIZE];
char *vg = NULL, *lv = NULL, *layer = NULL;
@@ -154,10 +221,15 @@ static int _remove_failed_devices(const
return -ENOMEM; /* FIXME Replace with generic error return - reason for failure has already got logged */
}
+ _create_filter(devi);
+
/* FIXME Is any sanity-checking required on %s? */
- if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "lvconvert --config devices{ignore_suspended_devices=1} --repair --use-policies %s/%s", vg, lv)) {
+ if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "lvconvert --repair --use-policies "
+ "--config devices{ignore_suspended_devices=1\\ %s} %s/%s",
+ DEVICE_FILTER_STR(devi), vg, lv)) {
/* this error should be caught above, but doesn't hurt to check again */
syslog(LOG_ERR, "Unable to form LVM command: Device name too long");
+ _destroy_filter(devi);
dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */
return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */
}
@@ -165,24 +237,28 @@ static int _remove_failed_devices(const
r = lvm2_run(_lvm_handle, cmd_str);
if (r == ECMD_PROCESSED) {
- snprintf(cmd_str, CMD_SIZE, "vgreduce --removemissing %s", vg);
+ snprintf(cmd_str, CMD_SIZE, "vgreduce --removemissing %s%s%s %s",
+ DEVICE_CONFIG_PREP_STR(devi), DEVICE_FILTER_STR(devi),
+ DEVICE_CONFIG_POST_STR(devi), vg);
if (lvm2_run(_lvm_handle, cmd_str) != 1)
syslog(LOG_ERR, "Unable to remove failed PVs from VG %s", vg);
}
+ _destroy_filter(devi);
dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */
return (r == ECMD_PROCESSED) ? 0 : -1;
}
void process_event(struct dm_task *dmt,
enum dm_event_mask event __attribute((unused)),
- void **unused __attribute((unused)))
+ void **private)
{
void *next = NULL;
uint64_t start, length;
char *target_type = NULL;
char *params;
const char *device = dm_task_get_name(dmt);
+ struct device_info *devi = *private;
if (pthread_mutex_trylock(&_event_mutex)) {
syslog(LOG_NOTICE, "Another thread is handling an event. Waiting...");
@@ -212,7 +288,7 @@ void process_event(struct dm_task *dmt,
break;
case ME_FAILURE:
syslog(LOG_ERR, "Device failure in %s\n", device);
- if (_remove_failed_devices(device))
+ if (_remove_failed_devices(device, devi))
/* FIXME Why are all the error return codes unused? Get rid of them? */
syslog(LOG_ERR, "Failed to remove faulty devices in %s\n",
device);
@@ -233,18 +309,122 @@ void process_event(struct dm_task *dmt,
pthread_mutex_unlock(&_event_mutex);
}
+static int _fetch_string(char **ptr, char **src, const int delimiter)
+{
+ char *p;
+ size_t len;
+
+ if (!(p = strchr(*src, delimiter)))
+ return 0;
+ *p = '\0';
+
+ len = strlen(*src);
+ if (len && !(*ptr = dm_strdup(*src))) {
+ *p = delimiter;
+ return 0;
+ }
+
+ *p = delimiter;
+ *src = p + 1;
+
+ return 1;
+}
+
+static int _fetch_number(unsigned int *ptr, char **src, const int delimiter)
+{
+ char *p;
+
+ if (!(p = strchr(*src, delimiter)))
+ return 0;
+ *p = '\0';
+
+ *ptr = strtoul(*src, NULL, 10);
+
+ *p = delimiter;
+ *src = p + 1;
+
+ return 1;
+}
+
+static struct device_info *alloc_device_info(void)
+{
+ struct device_info *devi;
+
+ devi = dm_malloc(sizeof(*devi));
+ if (!devi)
+ return NULL;
+
+ dm_list_init(&devi->dev_all);
+
+ return devi;
+}
+
+static int set_device_info(struct device_info *devi, char *dev_list)
+{
+ struct device *dev;
+ char *p = dev_list;
+
+ /* format: {/dev/sdx,major:minor;}[1,] */
+ while (strchr(p, ';')) {
+ dev = dm_malloc(sizeof(*dev));
+ if (!dev)
+ return 0;
+ memset(dev, 0, sizeof(*dev));
+
+ if (!_fetch_string(&dev->dname, &p, ',') ||
+ !_fetch_number(&dev->major, &p, ':') ||
+ !_fetch_number(&dev->minor, &p, ';')) {
+ if (dev->dname)
+ dm_free(dev->dname);
+ dm_free(dev);
+ return 0;
+ }
+ dm_list_add(&devi->dev_all, &dev->list);
+ }
+
+ return 1;
+}
+
+static void free_device_info(struct device_info *devi)
+{
+ struct device *dev, *devt;
+
+ if (!devi)
+ return;
+
+ dm_list_iterate_items_safe(dev, devt, &devi->dev_all) {
+ dm_list_del(&dev->list);
+ dm_free(dev->dname);
+ dm_free(dev);
+ }
+
+ dm_free(devi);
+}
+
int register_device(const char *device,
const char *uuid __attribute((unused)),
int major __attribute((unused)),
int minor __attribute((unused)),
- void **priv_ptr __attribute((unused)),
- void *priv_data __attribute((unused)))
+ void **priv_ptr, void *priv_data)
{
+ struct device_info *devi;
int r = 0;
pthread_mutex_lock(&_register_mutex);
- syslog(LOG_INFO, "Monitoring mirror device %s for events\n", device);
+ /*
+ * allocate device_info
+ */
+ if (priv_data) {
+ devi = alloc_device_info();
+ if (!devi)
+ goto out;
+
+ *priv_ptr = devi;
+
+ if (!set_device_info(devi, priv_data))
+ goto out;
+ }
/*
* Need some space for allocations. 1024 should be more
@@ -265,10 +445,15 @@ int register_device(const char *device,
lvm2_run(_lvm_handle, "_memlock_inc");
}
+ syslog(LOG_INFO, "Monitoring mirror device %s for events\n", device);
+
_register_count++;
r = 1;
out:
+ if (!r)
+ free_device_info(*priv_ptr);
+
pthread_mutex_unlock(&_register_mutex);
return r;
@@ -293,6 +478,8 @@ int unregister_device(const char *device
_lvm_handle = NULL;
}
+ free_device_info(*priv_ptr);
+
pthread_mutex_unlock(&_register_mutex);
return 1;
--
Takahiro Yasui
Hitachi Computer Products (America), Inc.
More information about the lvm-devel
mailing list