1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

Add mirror dmeventd library

This commit is contained in:
Alasdair Kergon 2005-12-02 19:52:06 +00:00
parent c6b966c8ee
commit 06f62ad1e4
12 changed files with 799 additions and 5 deletions

View File

@ -24,8 +24,13 @@ endif
SUBDIRS += lib tools daemons
ifeq ("@DMEVENTD@", "yes")
SUBDIRS += dmeventd
endif
ifeq ($(MAKECMDGOALS),distclean)
SUBDIRS += daemons/clvmd \
dmeventd \
lib/format1 \
lib/format_pool \
lib/locking \
@ -40,13 +45,15 @@ include make.tmpl
daemons: lib
lib: include
tools: lib
po: tools daemons
dmeventd: tools
po: tools daemons dmeventd
ifeq ("@INTL@", "yes")
lib.pofile: include.pofile
tools.pofile: lib.pofile
daemons.pofile: lib.pofile
po.pofile: tools.pofile daemons.pofile
dmeventd.pofile: tools.pofile
po.pofile: tools.pofile daemons.pofile dmeventd.pofile
pofile: po.pofile
endif

View File

@ -1,5 +1,6 @@
Version 2.02.02
Version 2.02.02 -
====================================
Add mirror dmeventd library.
Add some activation logic to remove_mirror_images().
lvconvert can remove specified PVs from a mirror.
lvconvert turns an existing LV into a mirror.

33
configure vendored
View File

@ -310,7 +310,7 @@ ac_includes_default="\
#endif"
ac_default_prefix=/usr
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CPP EGREP ALLOCA LIBOBJS POW_LIB MSGFMT MODPROBE_CMD JOBS STATIC_LINK LVM1 POOL SNAPSHOTS MIRRORS OWNER GROUP COPTIMISE_FLAG CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LDDEPS SOFLAG LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX CMDLIB LOCALEDIR CONFDIR STATICDIR INTL_PACKAGE INTL CLVMD CLUSTER FSADM LTLIBOBJS'
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CPP EGREP ALLOCA LIBOBJS POW_LIB MSGFMT MODPROBE_CMD JOBS STATIC_LINK LVM1 POOL SNAPSHOTS MIRRORS OWNER GROUP COPTIMISE_FLAG CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LDDEPS SOFLAG LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX CMDLIB LOCALEDIR CONFDIR STATICDIR INTL_PACKAGE INTL CLVMD CLUSTER FSADM DMEVENTD LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@ -858,6 +858,7 @@ Optional Features:
--disable-o_direct Disable O_DIRECT
--enable-cmdlib Build shared command library
--enable-fsadm Enable fsadm
--enable-dmeventd Enable dmeventd
--enable-nls Enable Native Language Support
Optional Packages:
@ -7428,6 +7429,25 @@ fi;
echo "$as_me:$LINENO: result: $FSADM" >&5
echo "${ECHO_T}$FSADM" >&6
################################################################################
echo "$as_me:$LINENO: checking whether to use dmeventd" >&5
echo $ECHO_N "checking whether to use dmeventd... $ECHO_C" >&6
# Check whether --enable-dmeventd or --disable-dmeventd was given.
if test "${enable_dmeventd+set}" = set; then
enableval="$enable_dmeventd"
DMEVENTD=$enableval
fi;
echo "$as_me:$LINENO: result: $DMEVENTD" >&5
echo "${ECHO_T}$DMEVENTD" >&6
if test x$DMEVENTD = xyes && test x$MIRRORS != xinternal; then
{ { echo "$as_me:$LINENO: error: --enable-dmeventd currently requires --with-mirrors=internal
" >&5
echo "$as_me: error: --enable-dmeventd currently requires --with-mirrors=internal
" >&2;}
{ (exit 1); exit 1; }; }
fi
################################################################################
if [ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ];
then exec_prefix="";
@ -10853,10 +10873,11 @@ fi
################################################################################
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/snapshot/Makefile man/Makefile po/Makefile tools/Makefile tools/version.h tools/fsadm/Makefile test/mm/Makefile test/device/Makefile test/format1/Makefile test/regex/Makefile test/filters/Makefile"
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile dmeventd/Makefile dmeventd/mirror/Makefile doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/snapshot/Makefile man/Makefile po/Makefile tools/Makefile tools/version.h tools/fsadm/Makefile test/mm/Makefile test/device/Makefile test/format1/Makefile test/regex/Makefile test/filters/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
@ -11412,6 +11433,8 @@ do
"make.tmpl" ) CONFIG_FILES="$CONFIG_FILES make.tmpl" ;;
"daemons/Makefile" ) CONFIG_FILES="$CONFIG_FILES daemons/Makefile" ;;
"daemons/clvmd/Makefile" ) CONFIG_FILES="$CONFIG_FILES daemons/clvmd/Makefile" ;;
"dmeventd/Makefile" ) CONFIG_FILES="$CONFIG_FILES dmeventd/Makefile" ;;
"dmeventd/mirror/Makefile" ) CONFIG_FILES="$CONFIG_FILES dmeventd/mirror/Makefile" ;;
"doc/Makefile" ) CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
"include/Makefile" ) CONFIG_FILES="$CONFIG_FILES include/Makefile" ;;
"lib/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;;
@ -11576,6 +11599,7 @@ s,@INTL@,$INTL,;t t
s,@CLVMD@,$CLVMD,;t t
s,@CLUSTER@,$CLUSTER,;t t
s,@FSADM@,$FSADM,;t t
s,@DMEVENTD@,$DMEVENTD,;t t
s,@LTLIBOBJS@,$LTLIBOBJS,;t t
CEOF
@ -11855,3 +11879,8 @@ if test x$FSADM == xyes; then
{ echo "$as_me:$LINENO: WARNING: fsadm support is untested" >&5
echo "$as_me: WARNING: fsadm support is untested" >&2;}
fi
if test x$DMEVENTD == xyes; then
{ echo "$as_me:$LINENO: WARNING: dmeventd support is untested" >&5
echo "$as_me: WARNING: dmeventd support is untested" >&2;}
fi

View File

@ -355,6 +355,20 @@ AC_ARG_ENABLE(fsadm, [ --enable-fsadm Enable fsadm],
FSADM=$enableval)
AC_MSG_RESULT($FSADM)
################################################################################
dnl -- enable dmeventd handling
AC_MSG_CHECKING(whether to use dmeventd)
AC_ARG_ENABLE(dmeventd, [ --enable-dmeventd Enable the device-mapper event daemon],
DMEVENTD=$enableval)
AC_MSG_RESULT($DMEVENTD)
dnl -- dmeventd currently requires internal mirror support
if test x$DMEVENTD = xyes && test x$MIRRORS != xinternal; then
AC_MSG_ERROR(
--enable-dmeventd currently requires --with-mirrors=internal
)
fi
################################################################################
dnl -- Mess with default exec_prefix
if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
@ -563,6 +577,7 @@ AC_SUBST(INTL)
AC_SUBST(CLVMD)
AC_SUBST(CLUSTER)
AC_SUBST(FSADM)
AC_SUBST(DMEVENTD)
################################################################################
dnl -- First and last lines should not contain files to generate in order to
@ -572,6 +587,8 @@ Makefile \
make.tmpl \
daemons/Makefile \
daemons/clvmd/Makefile \
dmeventd/Makefile \
dmeventd/mirror/Makefile \
doc/Makefile \
include/Makefile \
lib/Makefile \
@ -599,3 +616,7 @@ fi
if test x$FSADM == xyes; then
AC_MSG_WARN(fsadm support is untested)
fi
if test x$DMEVENTD == xyes; then
AC_MSG_WARN(dmeventd support is untested)
fi

View File

@ -0,0 +1,22 @@
#
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
#
# This file is part of the 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 General Public License v.2.
#
# You should have received a copy of the GNU 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
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
SUBDIRS += mirror
include $(top_srcdir)/make.tmpl

View File

@ -0,0 +1,3 @@
process_event
register_device
unregister_device

View File

@ -0,0 +1,32 @@
#
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
#
# This file is part of the 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 General Public License v.2.
#
# You should have received a copy of the GNU 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
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
CFLAGS += -I${top_srcdir}/tools -I${top_srcdir}/include
CLDFLAGS += -ldevmapper -llvm2cmd
SOURCES = dmeventd_mirror.c
LIB_SHARED = libdevmapper-event-lvm2mirror.so
include $(top_srcdir)/make.tmpl
install: libdevmapper-event-lvm2mirror.so
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
$(libdir)/$<.$(LIB_VERSION)
$(LN_S) -f $(libdir)/$<.$(LIB_VERSION) $(libdir)/$<

View File

@ -0,0 +1,311 @@
/*
* 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>
/* FIXME Replace syslog with multilog */
#include <syslog.h>
#define ME_IGNORE 0
#define ME_INSYNC 1
#define ME_FAILURE 2
static int _get_mirror_event(char *params)
{
int i, rtn = ME_INSYNC;
int max_args = 30; /* should support at least 8-way mirrors */
char *args[max_args];
char *dev_status_str;
char *log_status_str;
char *sync_str;
char *p;
int log_argc, num_devs, num_failures=0;
if (max_args <= split_words(params, max_args, args)) {
syslog(LOG_ERR, "Unable to split mirror parameters: Arg list too long");
return -E2BIG;
}
/*
* Unused: 0 409600 mirror
* Used : 2 253:4 253:5 400/400 1 AA 3 cluster 253:3 A
*/
num_devs = atoi(args[0]);
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];
syslog(LOG_DEBUG, " num_devs = %d", num_devs);
syslog(LOG_DEBUG, " dev_status_str: %s", dev_status_str);
syslog(LOG_DEBUG, " log_argc = %d", log_argc);
syslog(LOG_DEBUG, " log_status_str: %s", log_status_str);
syslog(LOG_DEBUG, " sync_str: %s", sync_str);
/* Check for bad mirror devices */
for (i = 0; i < num_devs; i++) {
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) {
rtn = ME_FAILURE;
goto out;
}
for(p = strstr(sync_str, "/"), i = (p - sync_str) - 1;
p && (i >= 0);
i--) {
syslog(LOG_DEBUG, "p[%d] (%c) ?= sync_str[%d] (%c)",
i+1, p[i+1], i, sync_str[i]);
if(p[i+1] != sync_str[i]){
rtn = ME_IGNORE;
break;
}
}
out:
return rtn;
}
/* dmname_to_lvmname
* @dmname: the device mapper name
* @vg: the returned vg name
* @lv: the returned lv name
*
* Caller must free strings when finished
*
* Returns: 0, -ENOMEM, -EINVAL
*/
/* FIXME Replace with split_dm_name */
static int _dmname_to_lvmname(char *dmname, char **vg, char **lv)
{
int rtn = 0;
char *ptr1, *ptr2;
// syslog(LOG_DEBUG, "Entering dmname_to_lvmname\n");
for((ptr1 = dmname); (ptr2 = strstr(ptr1, "/")); ptr2++, (ptr1 = ptr2));
for(; (ptr2 = strstr(ptr1, "-")) && (ptr2[1] == '-'); ptr2+=2, ptr1 = ptr2);
if (!ptr2)
return -EINVAL;
ptr2[0] = '\0';
if(!(*vg = strdup(ptr1))) {
rtn = -ENOMEM;
goto fail;
}
ptr1 = ptr2+1;
if(!(*lv = strdup(ptr1))) {
rtn = -ENOMEM;
free(*vg);
}
fail:
ptr2[0] = '-';
// syslog(LOG_DEBUG, "Exiting dmname_to_lvmname\n");
return rtn;
}
static void _temporary_log_fn(int level, const char *file, int line, const char *format)
{
syslog(LOG_DEBUG, "%s", format);
}
static int _remove_failed_devices(const char *device)
{
int r;
void *handle;
int cmd_size = 256; /* FIXME Use system restriction */
char cmd_str[cmd_size];
char *vg = NULL, *lv = NULL;
// syslog(LOG_DEBUG, "Entering remove_failed_device\n");
if (strlen(device) > 200)
return -ENAMETOOLONG;
if ((r = _dmname_to_lvmname(device, &vg, &lv))) {
syslog(LOG_ERR,
"Unable to determine LVM name for %s",
device);
return r;
}
/* FIXME Is any sanity-checking required on %s? */
syslog(LOG_INFO, "vgreduce --removemissing %s\n", vg);
if (cmd_size <= snprintf(cmd_str, cmd_size, "vgreduce --removemissing %s", vg)) {
/* 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");
return -ENAMETOOLONG;
}
lvm2_log_fn(_temporary_log_fn);
handle = lvm2_init();
lvm2_log_level(handle, 1);
r = lvm2_run(handle, cmd_str);
syslog(LOG_INFO, "lvconvert -m0 %s/%s\n", vg, lv);
if (cmd_size <= snprintf(cmd_str, cmd_size, "lvconvert -m0 %s/%s\n", 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");
return -ENAMETOOLONG;
}
r = lvm2_run(handle, cmd_str);
// syslog(LOG_DEBUG, "Exiting remove_failed_device\n");
free(vg);
free(lv);
return (r == 1)? 0: -1;
}
void process_event(const char *device, enum dm_event_type event)
{
int pid;
struct dm_task *dmt;
void *next = NULL;
uint64_t start, length;
char *target_type = NULL;
char *params;
/* FIXME Too late to fork here under low memory! */
/* FIXME This should run within a dmeventd thread instead. */
pid = fork();
if (pid > 0)
return;
/*
* Fork twice to prevent the process from
* becoming a zombie after exiting.
*/
pid = fork();
if(pid > 0) {
exit(EXIT_SUCCESS);
} else if (pid < 0) {
openlog("dmeventd (mirror_dso)", LOG_PID, LOG_DAEMON);
syslog(LOG_ERR, "Fork new process to handle device failure");
syslog(LOG_ERR, "Handling failure anyway (a harmless zombie process will result)");
} else {
setsid();
openlog("dmeventd (mirror_dso)", LOG_PID, LOG_DAEMON);
}
syslog(LOG_NOTICE, "An event occurred on %s\n", device);
/* 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 (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))
syslog(LOG_ERR, "Failed to remove faulty devices in %s\n",
device);
else
syslog(LOG_NOTICE, "%s is now a linear device.\n",
device);
break;
case ME_IGNORE:
break;
default:
syslog(LOG_INFO, "Unknown event received.\n");
}
} while (next);
fail:
if (dmt)
dm_task_destroy(dmt);
exit(0);
}
int register_device(const char *device)
{
syslog(LOG_INFO, "[%s] %s(%d) - Device: %s\n",
__FILE__, __func__, __LINE__, device);
return 1;
}
int unregister_device(const char *device)
{
syslog(LOG_INFO, "[%s] %s(%d) - Device: %s\n",
__FILE__, __func__, __LINE__, device);
return 1;
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/

22
dmeventd/Makefile.in Normal file
View File

@ -0,0 +1,22 @@
#
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
#
# This file is part of the 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 General Public License v.2.
#
# You should have received a copy of the GNU 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
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
SUBDIRS += mirror
include $(top_srcdir)/make.tmpl

View File

@ -0,0 +1,3 @@
process_event
register_device
unregister_device

View File

@ -0,0 +1,32 @@
#
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
#
# This file is part of the 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 General Public License v.2.
#
# You should have received a copy of the GNU 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
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
CFLAGS += -I${top_srcdir}/tools -I${top_srcdir}/include
CLDFLAGS += -ldevmapper -llvm2cmd
SOURCES = dmeventd_mirror.c
LIB_SHARED = libdevmapper-event-lvm2mirror.so
include $(top_srcdir)/make.tmpl
install: libdevmapper-event-lvm2mirror.so
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
$(libdir)/$<.$(LIB_VERSION)
$(LN_S) -f $(libdir)/$<.$(LIB_VERSION) $(libdir)/$<

View File

@ -0,0 +1,311 @@
/*
* 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>
/* FIXME Replace syslog with multilog */
#include <syslog.h>
#define ME_IGNORE 0
#define ME_INSYNC 1
#define ME_FAILURE 2
static int _get_mirror_event(char *params)
{
int i, rtn = ME_INSYNC;
int max_args = 30; /* should support at least 8-way mirrors */
char *args[max_args];
char *dev_status_str;
char *log_status_str;
char *sync_str;
char *p;
int log_argc, num_devs, num_failures=0;
if (max_args <= split_words(params, max_args, args)) {
syslog(LOG_ERR, "Unable to split mirror parameters: Arg list too long");
return -E2BIG;
}
/*
* Unused: 0 409600 mirror
* Used : 2 253:4 253:5 400/400 1 AA 3 cluster 253:3 A
*/
num_devs = atoi(args[0]);
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];
syslog(LOG_DEBUG, " num_devs = %d", num_devs);
syslog(LOG_DEBUG, " dev_status_str: %s", dev_status_str);
syslog(LOG_DEBUG, " log_argc = %d", log_argc);
syslog(LOG_DEBUG, " log_status_str: %s", log_status_str);
syslog(LOG_DEBUG, " sync_str: %s", sync_str);
/* Check for bad mirror devices */
for (i = 0; i < num_devs; i++) {
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) {
rtn = ME_FAILURE;
goto out;
}
for(p = strstr(sync_str, "/"), i = (p - sync_str) - 1;
p && (i >= 0);
i--) {
syslog(LOG_DEBUG, "p[%d] (%c) ?= sync_str[%d] (%c)",
i+1, p[i+1], i, sync_str[i]);
if(p[i+1] != sync_str[i]){
rtn = ME_IGNORE;
break;
}
}
out:
return rtn;
}
/* dmname_to_lvmname
* @dmname: the device mapper name
* @vg: the returned vg name
* @lv: the returned lv name
*
* Caller must free strings when finished
*
* Returns: 0, -ENOMEM, -EINVAL
*/
/* FIXME Replace with split_dm_name */
static int _dmname_to_lvmname(char *dmname, char **vg, char **lv)
{
int rtn = 0;
char *ptr1, *ptr2;
// syslog(LOG_DEBUG, "Entering dmname_to_lvmname\n");
for((ptr1 = dmname); (ptr2 = strstr(ptr1, "/")); ptr2++, (ptr1 = ptr2));
for(; (ptr2 = strstr(ptr1, "-")) && (ptr2[1] == '-'); ptr2+=2, ptr1 = ptr2);
if (!ptr2)
return -EINVAL;
ptr2[0] = '\0';
if(!(*vg = strdup(ptr1))) {
rtn = -ENOMEM;
goto fail;
}
ptr1 = ptr2+1;
if(!(*lv = strdup(ptr1))) {
rtn = -ENOMEM;
free(*vg);
}
fail:
ptr2[0] = '-';
// syslog(LOG_DEBUG, "Exiting dmname_to_lvmname\n");
return rtn;
}
static void _temporary_log_fn(int level, const char *file, int line, const char *format)
{
syslog(LOG_DEBUG, "%s", format);
}
static int _remove_failed_devices(const char *device)
{
int r;
void *handle;
int cmd_size = 256; /* FIXME Use system restriction */
char cmd_str[cmd_size];
char *vg = NULL, *lv = NULL;
// syslog(LOG_DEBUG, "Entering remove_failed_device\n");
if (strlen(device) > 200)
return -ENAMETOOLONG;
if ((r = _dmname_to_lvmname(device, &vg, &lv))) {
syslog(LOG_ERR,
"Unable to determine LVM name for %s",
device);
return r;
}
/* FIXME Is any sanity-checking required on %s? */
syslog(LOG_INFO, "vgreduce --removemissing %s\n", vg);
if (cmd_size <= snprintf(cmd_str, cmd_size, "vgreduce --removemissing %s", vg)) {
/* 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");
return -ENAMETOOLONG;
}
lvm2_log_fn(_temporary_log_fn);
handle = lvm2_init();
lvm2_log_level(handle, 1);
r = lvm2_run(handle, cmd_str);
syslog(LOG_INFO, "lvconvert -m0 %s/%s\n", vg, lv);
if (cmd_size <= snprintf(cmd_str, cmd_size, "lvconvert -m0 %s/%s\n", 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");
return -ENAMETOOLONG;
}
r = lvm2_run(handle, cmd_str);
// syslog(LOG_DEBUG, "Exiting remove_failed_device\n");
free(vg);
free(lv);
return (r == 1)? 0: -1;
}
void process_event(const char *device, enum dm_event_type event)
{
int pid;
struct dm_task *dmt;
void *next = NULL;
uint64_t start, length;
char *target_type = NULL;
char *params;
/* FIXME Too late to fork here under low memory! */
/* FIXME This should run within a dmeventd thread instead. */
pid = fork();
if (pid > 0)
return;
/*
* Fork twice to prevent the process from
* becoming a zombie after exiting.
*/
pid = fork();
if(pid > 0) {
exit(EXIT_SUCCESS);
} else if (pid < 0) {
openlog("dmeventd (mirror_dso)", LOG_PID, LOG_DAEMON);
syslog(LOG_ERR, "Fork new process to handle device failure");
syslog(LOG_ERR, "Handling failure anyway (a harmless zombie process will result)");
} else {
setsid();
openlog("dmeventd (mirror_dso)", LOG_PID, LOG_DAEMON);
}
syslog(LOG_NOTICE, "An event occurred on %s\n", device);
/* 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 (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))
syslog(LOG_ERR, "Failed to remove faulty devices in %s\n",
device);
else
syslog(LOG_NOTICE, "%s is now a linear device.\n",
device);
break;
case ME_IGNORE:
break;
default:
syslog(LOG_INFO, "Unknown event received.\n");
}
} while (next);
fail:
if (dmt)
dm_task_destroy(dmt);
exit(0);
}
int register_device(const char *device)
{
syslog(LOG_INFO, "[%s] %s(%d) - Device: %s\n",
__FILE__, __func__, __LINE__, device);
return 1;
}
int unregister_device(const char *device)
{
syslog(LOG_INFO, "[%s] %s(%d) - Device: %s\n",
__FILE__, __func__, __LINE__, device);
return 1;
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/