1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-23 21:35:29 +03:00
lvm2/daemons/dmeventd/plugins/mirror/dmeventd_mirror.c

291 lines
7.3 KiB
C
Raw Normal View History

2005-12-02 22:52:06 +03:00
/*
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "libdevmapper.h"
#include "libdevmapper-event.h"
#include "lvm2cmd.h"
#include "lvm-string.h"
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <syslog.h> /* FIXME Replace syslog with multilog */
/* FIXME Missing openlog? */
2005-12-02 22:52:06 +03:00
#define ME_IGNORE 0
#define ME_INSYNC 1
#define ME_FAILURE 2
/*
* register_device() is called first and performs initialisation.
* Only one device may be registered or unregistered at a time.
*/
static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER;
/*
* Number of active registrations.
*/
static int _register_count = 0;
static struct dm_pool *_mem_pool = NULL;
static void *_lvm_handle = NULL;
/*
* Currently only one event can be processed at a time.
*/
static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER;
2005-12-02 22:52:06 +03:00
static int _get_mirror_event(char *params)
{
int i, r = ME_INSYNC;
#define MAX_ARGS 30 /* should support at least 8-way mirrors */
/* FIXME Remove unnecessary limit. It tells you how many devices there are - use it! */
char *args[MAX_ARGS];
2005-12-02 22:52:06 +03:00
char *dev_status_str;
char *log_status_str;
char *sync_str;
char *p;
int log_argc, num_devs, num_failures=0;
/* FIXME Remove unnecessary limit - get num_devs here */
if (MAX_ARGS <= dm_split_words(params, MAX_ARGS, 0, args)) {
2005-12-02 22:52:06 +03:00
syslog(LOG_ERR, "Unable to split mirror parameters: Arg list too long");
return -E2BIG; /* FIXME Why? Unused */
2005-12-02 22:52:06 +03:00
}
/*
* Unused: 0 409600 mirror
* Used : 2 253:4 253:5 400/400 1 AA 3 cluster 253:3 A
*/
num_devs = atoi(args[0]);
/* FIXME *Now* split rest of args */
2005-12-02 22:52:06 +03:00
dev_status_str = args[3 + num_devs];
log_argc = atoi(args[4 + num_devs]);
log_status_str = args[4 + num_devs + log_argc];
sync_str = args[1 + num_devs];
/* Check for bad mirror devices */
for (i = 0; i < num_devs; i++)
2005-12-02 22:52:06 +03:00
if (dev_status_str[i] == 'D') {
syslog(LOG_ERR, "Mirror device, %s, has failed.\n", args[i+1]);
num_failures++;
}
/* Check for bad log device */
if (log_status_str[0] == 'D') {
syslog(LOG_ERR, "Log device, %s, has failed.\n",
args[3 + num_devs + log_argc]);
num_failures++;
}
if (num_failures) {
r = ME_FAILURE;
2005-12-02 22:52:06 +03:00
goto out;
}
2006-01-27 23:48:19 +03:00
p = strstr(sync_str, "/");
if (p) {
p[0] = '\0';
if (strcmp(sync_str, p+1))
r = ME_IGNORE;
2006-01-27 23:48:19 +03:00
p[0] = '/';
} else {
/*
* How the hell did we get this?
* Might mean all our parameters are screwed.
*/
syslog(LOG_ERR, "Unable to parse sync string.");
r = ME_IGNORE;
2005-12-02 22:52:06 +03:00
}
out:
return r;
2005-12-02 22:52:06 +03:00
}
2006-05-11 23:45:53 +04:00
static void _temporary_log_fn(int level, const char *file,
int line, const char *format)
2005-12-02 22:52:06 +03:00
{
2006-05-11 23:45:53 +04:00
if (!strncmp(format, "WARNING: ", 9) && (level < 5))
syslog(LOG_CRIT, "%s", format);
else
syslog(LOG_DEBUG, "%s", format);
2005-12-02 22:52:06 +03:00
}
static int _remove_failed_devices(const char *device)
{
int r;
#define CMD_SIZE 256 /* FIXME Use system restriction */
char cmd_str[CMD_SIZE];
char *vg = NULL, *lv = NULL, *layer = NULL;
2005-12-02 22:52:06 +03:00
if (strlen(device) > 200) /* FIXME Use real restriction */
return -ENAMETOOLONG; /* FIXME These return code distinctions are not used so remove them! */
2005-12-02 22:52:06 +03:00
if (!dm_split_lvm_name(_mem_pool, device, &vg, &lv, &layer)) {
syslog(LOG_ERR, "Unable to determine VG name from %s",
2005-12-02 22:52:06 +03:00
device);
return -ENOMEM; /* FIXME Replace with generic error return - reason for failure has already got logged */
2005-12-02 22:52:06 +03:00
}
/* FIXME Is any sanity-checking required on %s? */
if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "vgreduce --removemissing %s", vg)) {
2005-12-02 22:52:06 +03:00
/* 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");
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 */
2005-12-02 22:52:06 +03:00
}
r = lvm2_run(_lvm_handle, cmd_str);
2005-12-02 22:52:06 +03:00
dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */
return (r == 1) ? 0 : -1;
2005-12-02 22:52:06 +03:00
}
void process_event(const char *device, enum dm_event_type event)
{
struct dm_task *dmt;
void *next = NULL;
uint64_t start, length;
char *target_type = NULL;
char *params;
if (pthread_mutex_trylock(&_event_mutex)) {
syslog(LOG_NOTICE, "Another thread is handling an event. Waiting...");
pthread_mutex_lock(&_event_mutex);
}
2005-12-02 22:52:06 +03:00
/* FIXME Move inside libdevmapper */
if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) {
syslog(LOG_ERR, "Unable to create dm_task.\n");
goto fail;
}
if (!dm_task_set_name(dmt, device)) {
syslog(LOG_ERR, "Unable to set device name.\n");
goto fail;
}
if (!dm_task_run(dmt)) {
syslog(LOG_ERR, "Unable to run task.\n");
goto fail;
}
do {
next = dm_get_next_target(dmt, next, &start, &length,
&target_type, &params);
if (!target_type) {
syslog(LOG_INFO, "%s mapping lost.\n", device);
continue;
}
2005-12-02 22:52:06 +03:00
if (strcmp(target_type, "mirror")) {
syslog(LOG_INFO, "%s has unmirrored portion.\n", device);
continue;
}
switch(_get_mirror_event(params)) {
case ME_INSYNC:
/* FIXME: all we really know is that this
_part_ of the device is in sync
Also, this is not an error
*/
syslog(LOG_NOTICE, "%s is now in-sync\n", device);
break;
case ME_FAILURE:
syslog(LOG_ERR, "Device failure in %s\n", device);
if (_remove_failed_devices(device))
/* FIXME Why are all the error return codes unused? Get rid of them? */
2005-12-02 22:52:06 +03:00
syslog(LOG_ERR, "Failed to remove faulty devices in %s\n",
device);
2006-01-27 23:48:19 +03:00
/* Should check before warning user that device is now linear
2005-12-02 22:52:06 +03:00
else
syslog(LOG_NOTICE, "%s is now a linear device.\n",
device);
2006-01-27 23:48:19 +03:00
*/
2005-12-02 22:52:06 +03:00
break;
case ME_IGNORE:
break;
default:
/* FIXME Wrong: it can also return -E2BIG but it's never used! */
2005-12-02 22:52:06 +03:00
syslog(LOG_INFO, "Unknown event received.\n");
}
} while (next);
fail:
if (dmt)
dm_task_destroy(dmt);
pthread_mutex_unlock(&_event_mutex);
2005-12-02 22:52:06 +03:00
}
int register_device(const char *device)
{
int r = 0;
pthread_mutex_lock(&_register_mutex);
2006-05-11 23:45:53 +04:00
syslog(LOG_INFO, "Monitoring mirror device, %s for events\n", device);
/*
* Need some space for allocations. 1024 should be more
* than enough for what we need (device mapper name splitting)
*/
if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024)))
goto out;
if (!_lvm_handle) {
lvm2_log_fn(_temporary_log_fn);
if (!(_lvm_handle = lvm2_init())) {
dm_pool_destroy(_mem_pool);
_mem_pool = NULL;
goto out;
}
lvm2_log_level(_lvm_handle, LVM2_LOG_SUPPRESS);
/* FIXME Temporary: move to dmeventd core */
lvm2_run(_lvm_handle, "_memlock_inc");
}
_register_count++;
r = 1;
2005-12-02 22:52:06 +03:00
out:
pthread_mutex_unlock(&_register_mutex);
return r;
2005-12-02 22:52:06 +03:00
}
int unregister_device(const char *device)
{
pthread_mutex_lock(&_register_mutex);
if (!--_register_count) {
dm_pool_destroy(_mem_pool);
_mem_pool = NULL;
lvm2_run(_lvm_handle, "_memlock_dec");
lvm2_exit(_lvm_handle);
_lvm_handle = NULL;
}
2005-12-02 22:52:06 +03:00
pthread_mutex_unlock(&_register_mutex);
return 1;
2005-12-02 22:52:06 +03:00
}