1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-10-09 23:33:17 +03:00

Compare commits

...

77 Commits

Author SHA1 Message Date
Alasdair Kergon
ed43dc842b A setgeometry implementation. [untested] 2006-02-20 23:55:58 +00:00
Alasdair Kergon
49d4db6cd2 post-release 2006-02-08 23:24:02 +00:00
Alasdair Kergon
ea80ab2cae post-release
fix dmeventd build
2006-02-08 23:23:19 +00:00
Alasdair Kergon
382e808b8d fix mirror log parm count 2006-02-08 14:14:13 +00:00
Alasdair Kergon
846befa7e0 release 2006-02-07 16:33:48 +00:00
Alasdair Kergon
74dd29f843 add clustered log uuid 2006-02-06 20:18:10 +00:00
Alasdair Kergon
b0473bffcb remove a dmeventd_mirror syslog message 2006-02-06 19:34:45 +00:00
Alasdair Kergon
24dd9ab1a7 Change prefix for clustered log from "clustered " to "clustered_" 2006-02-06 19:32:18 +00:00
Alasdair Kergon
49d3037e87 fix tabs 2006-02-03 21:34:11 +00:00
Alasdair Kergon
37ad2bd4e8 tweak clvmd makefile 2006-02-03 21:31:00 +00:00
Alasdair Kergon
7d7b332b02 Temporary device_exists() fixes. 2006-02-03 19:44:59 +00:00
Alasdair Kergon
ac033b8612 Use supplied full dso name. 2006-02-03 19:41:34 +00:00
Alasdair Kergon
a7b98dfe25 suspend using existing LV metadata; vgreduce then needs partial flag 2006-02-03 19:36:20 +00:00
Alasdair Kergon
7fb7c86c46 fix libdevmapper-event-mirror liblvm2cmd link search path 2006-02-03 14:48:38 +00:00
Alasdair Kergon
ed036598a9 Add exported functions to set uid, gid and mode. [Bastian Blank] 2006-02-03 14:23:22 +00:00
Alasdair Kergon
160bb70cdf Add %.so: %.a make template rule. 2006-02-02 19:16:47 +00:00
Alasdair Kergon
c2e61f3c21 autoconf LIB_SUFFIX 2006-02-02 18:39:23 +00:00
Alasdair Kergon
18218467f3 remove unnecessary 0 in format string 2006-02-02 17:23:04 +00:00
Alasdair Kergon
17e298ad2a Only do lockfs filesystem sync when suspending snapshots.
Switchover library building to use LIB_SUFFIX.
2006-01-31 14:52:30 +00:00
Alasdair Kergon
d031a374f9 Rename _log to dm_log and export.
Fix misc compile-time warnings.
2006-01-31 14:50:38 +00:00
Alasdair Kergon
55f69c98cb Add dm_tree_skip_lockfs. 2006-01-30 23:36:04 +00:00
Alasdair Kergon
71f2e4306d Tidy some comments/messages. 2006-01-27 20:52:21 +00:00
Alasdair Kergon
f8af23a025 Fix renamed dso. 2006-01-27 20:51:36 +00:00
Alasdair Kergon
4ef55a6cd3 dmeventd thread termination fix 2006-01-27 20:50:01 +00:00
Alasdair Kergon
312f866723 some init_client cleanup 2006-01-27 20:49:13 +00:00
Alasdair Kergon
0ebe1f6dec More dmeventd mirror cleanups. 2006-01-27 20:48:19 +00:00
Alasdair Kergon
2ad92e0e6e Remove avoidable dmeventd mirror forking. 2006-01-27 20:47:20 +00:00
Alasdair Kergon
ac8823cdcf Fix libdevmapper event daemon_running status. 2006-01-27 20:46:06 +00:00
Alasdair Kergon
77565f7ee4 Replace deprecated signal functions. 2006-01-27 20:45:17 +00:00
Alasdair Kergon
d656d90fa8 Use split_dm_name in dmeventd mirror code. 2006-01-27 20:43:52 +00:00
Alasdair Kergon
175b3b0834 When suspending, dmeventd deregistration needs to use existing details
not precommitted ones.
2006-01-27 20:39:37 +00:00
Alasdair Kergon
7477e6b714 Fix dmeventd sharedlib path & start tidying registration code. 2006-01-27 20:13:12 +00:00
Alasdair Kergon
cd6568db69 fix dmevent registration return codes 2006-01-27 20:01:45 +00:00
Alasdair Kergon
6aff325fb2 Add config file setting: dmeventd/mirror_library 2006-01-27 19:05:05 +00:00
Alasdair Kergon
0d603cfe9c Rename register_dev; fix missing initialisation; reduce number of ifdefs. 2006-01-27 18:38:14 +00:00
Alasdair Kergon
34a1f14a17 Fix dm_strdup debug definition. 2006-01-11 15:40:54 +00:00
Alasdair Kergon
efe1c8a070 Fix dm_strdup debug definition. 2006-01-10 22:19:41 +00:00
Alasdair Kergon
1575844344 Fix hash function to avoid using a negative array offset. 2006-01-09 20:35:24 +00:00
Alasdair Kergon
221ac1c208 vgreduce remove mirror images
adjust block_on_error version no detection for RHEL4U3
2006-01-04 18:09:52 +00:00
Alasdair Kergon
57442db759 Don't inline _find in hash.c and tidy signed/unsigned etc. 2006-01-04 16:07:27 +00:00
Alasdair Kergon
5fdb3e7cd6 Fix libdevmapper.h #endif 2006-01-04 16:05:44 +00:00
Alasdair Kergon
96f259726c Fix dmsetup version driver version 2006-01-03 20:53:57 +00:00
Alasdair Kergon
4936efba5e Always print warning if activation is disabled. 2005-12-22 16:13:38 +00:00
Alasdair Kergon
d5a3559a2f Add --mirrorsonly arg to vgreduce. (Doesn't handle mirrors yet.) 2005-12-21 21:21:45 +00:00
Alasdair Kergon
114a1c7f52 some fixes 2005-12-21 20:24:22 +00:00
Alasdair Kergon
ce5265c203 fix libdevmapper-event include 2005-12-21 19:45:16 +00:00
Alasdair Kergon
1a575d926f vgreduce replaces active LVs with error segment before removing them. 2005-12-21 18:51:50 +00:00
Alasdair Kergon
85c818a39e read/write loop fixes 2005-12-19 22:56:47 +00:00
Alasdair Kergon
4ffa2defe4 fixme 2005-12-19 22:36:04 +00:00
Alasdair Kergon
8825157fbb Change dm_tree_node_add_mirror_target_log parm order 2005-12-19 21:03:17 +00:00
Alasdair Kergon
966d608dc5 Set block_on_error parameter if available.
Add target_version.
2005-12-19 21:01:39 +00:00
Alasdair Kergon
b808c89471 Add details to format1 'Invalid LV in extent map' error message. 2005-12-19 16:28:35 +00:00
Alasdair Kergon
75d4e6490f ability to pass log flags to libdevmapper 2005-12-13 15:57:32 +00:00
Alasdair Kergon
a82775f544 Add sync, nosync and block_on_error mirror log parameters.
Add hweight32.
2005-12-13 15:49:27 +00:00
Alasdair Kergon
6a22ad0171 comments 2005-12-13 13:34:31 +00:00
Alasdair Kergon
c854e88186 comment 2005-12-13 13:32:19 +00:00
Alasdair Kergon
d02203060c Fix lvscan snapshot full display.
dmeventd fixes
2005-12-08 17:49:34 +00:00
Alasdair Kergon
cf703b0433 Fix dmeventd build. 2005-12-05 11:16:48 +00:00
Alasdair Kergon
c0197a72d3 fix exports 2005-12-02 21:00:33 +00:00
Alasdair Kergon
e5a543e283 More dmeventd support. 2005-12-02 20:35:07 +00:00
Alasdair Kergon
b8b029b7d3 Add mirror dmeventd library 2005-12-02 19:52:06 +00:00
Alasdair Kergon
370f368b1a post-release 2005-12-02 17:24:06 +00:00
Alasdair Kergon
8288b45b4f 1.02.02 2005-12-02 15:44:18 +00:00
Alasdair Kergon
fe529faf8e dmeventd 2005-12-02 15:41:14 +00:00
Alasdair Kergon
ab931b177d dmeventd updates 2005-12-02 15:39:16 +00:00
Alasdair Kergon
9aa3465513 Export dm_task_update_nodes.
Use names instead of numbers in messages when ioctls fail.
2005-12-01 23:11:41 +00:00
Alasdair Kergon
6c70fc1a6c Add some FIXMEs to libdm-event. 2005-11-30 18:35:03 +00:00
Alasdair Kergon
1ccc39962a more lvconvert mirror code 2005-11-29 18:20:23 +00:00
Alasdair Kergon
99c941fc85 Allow signed mirrors arguments.
Move create_mirror_log() into toollib.
2005-11-28 21:00:37 +00:00
Alasdair Kergon
19729fdcc2 Determine parallel PVs to avoid with ALLOC_NORMAL allocation. (untested) 2005-11-28 20:01:00 +00:00
Alasdair Kergon
02e17998ce alloc avoids parallel pvs when supplied 2005-11-24 21:23:55 +00:00
Alasdair Kergon
459e00c67a preparation for parallel_areas changes to allocation code 2005-11-24 20:58:44 +00:00
Alasdair Kergon
292f665650 Fix lv_empty. 2005-11-24 18:46:51 +00:00
Alasdair Kergon
93bbb79569 _find_parallel_space -> _find_segment_space 2005-11-24 18:00:47 +00:00
Alasdair Kergon
273e724f2b post_release 2005-11-23 18:45:30 +00:00
Alasdair Kergon
5d2615c56f post-release 2005-11-23 18:44:59 +00:00
Alasdair Kergon
bfaaf21330 2.02.01 2005-11-23 18:42:45 +00:00
67 changed files with 4289 additions and 2803 deletions

View File

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

View File

@@ -1 +1 @@
2.02.01-cvs (2005-11-10) 2.02.03-cvs (2006-02-08)

View File

@@ -1,4 +1,31 @@
Version 2.02.01 - Version 2.02.03 -
===================================
Fix dmeventd build.
Version 2.02.02 - 7th February 2006
===================================
Add %.so: %.a make template rule.
Switchover library building to use LIB_SUFFIX.
Only do lockfs filesystem sync when suspending snapshots.
Always print warning if activation is disabled.
vgreduce removes mirror images.
Add --mirrorsonly to vgreduce.
vgreduce replaces active LVs with error segment before removing them.
Set block_on_error parameter if available.
Add target_version.
Add details to format1 'Invalid LV in extent map' error message.
Fix lvscan snapshot full display.
Bring lvdisplay man page example into line.
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.
Allow signed mirrors arguments.
Move create_mirror_log() into toollib.
Determine parallel PVs to avoid with ALLOC_NORMAL allocation.
Fix lv_empty.
Version 2.02.01 - 23rd November 2005
==================================== ====================================
Fix lvdisplay cmdline to accept snapshots. Fix lvdisplay cmdline to accept snapshots.
Fix open RO->RW promotion. Fix open RO->RW promotion.

View File

@@ -1,5 +1,30 @@
Version 1.02.04 -
============================
Add setgeometry.
Version 1.02.03 - 7 Feb 2006
============================
Add exported functions to set uid, gid and mode.
Rename _log to dm_log and export.
Add dm_tree_skip_lockfs.
Fix dm_strdup debug definition.
Fix hash function to avoid using a negative array offset.
Don't inline _find in hash.c and tidy signed/unsigned etc.
Fix libdevmapper.h #endif.
Fix dmsetup version driver version.
Add sync, nosync and block_on_error mirror log parameters.
Add hweight32.
Fix dmeventd build.
Version 1.02.02 - 2 Dec 2005
============================
dmeventd added.
Export dm_task_update_nodes.
Use names instead of numbers in messages when ioctls fail.
Version 1.02.01 - 23 Nov 2005 Version 1.02.01 - 23 Nov 2005
============================= =============================
Resume snapshot-origins last.
Drop leading zeros from dm_format_dev. Drop leading zeros from dm_format_dev.
Suppress attempt to reload identical table. Suppress attempt to reload identical table.
Additional LVM- prefix matching for transitional period. Additional LVM- prefix matching for transitional period.

2595
configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -35,7 +35,7 @@ case "$host_os" in
CLDNOWHOLEARCHIVE="-Wl,-no-whole-archive" CLDNOWHOLEARCHIVE="-Wl,-no-whole-archive"
LDDEPS="$LDDEPS .export.sym" LDDEPS="$LDDEPS .export.sym"
LDFLAGS="$LDFLAGS -Wl,--export-dynamic" LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
SOFLAG="-shared" LIB_SUFFIX="so"
DEVMAPPER=yes DEVMAPPER=yes
ODIRECT=yes ODIRECT=yes
SELINUX=yes SELINUX=yes
@@ -49,7 +49,7 @@ case "$host_os" in
CLDNOWHOLEARCHIVE= CLDNOWHOLEARCHIVE=
LDDEPS="$LDDEPS" LDDEPS="$LDDEPS"
LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS"
SOFLAG="-dynamiclib" LIB_SUFFIX="dylib"
DEVMAPPER=yes DEVMAPPER=yes
ODIRECT=no ODIRECT=no
SELINUX=no SELINUX=no
@@ -355,6 +355,23 @@ AC_ARG_ENABLE(fsadm, [ --enable-fsadm Enable fsadm],
FSADM=$enableval) FSADM=$enableval)
AC_MSG_RESULT($FSADM) 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
if test x$DMEVENTD = xyes; then
CFLAGS="$CFLAGS -DDMEVENTD"
fi
################################################################################ ################################################################################
dnl -- Mess with default exec_prefix dnl -- Mess with default exec_prefix
if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]]; if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
@@ -545,7 +562,7 @@ AC_SUBST(CLDWHOLEARCHIVE)
AC_SUBST(CLDNOWHOLEARCHIVE) AC_SUBST(CLDNOWHOLEARCHIVE)
AC_SUBST(LDDEPS) AC_SUBST(LDDEPS)
AC_SUBST(LDFLAGS) AC_SUBST(LDFLAGS)
AC_SUBST(SOFLAG) AC_SUBST(LIB_SUFFIX)
AC_SUBST(LIBS) AC_SUBST(LIBS)
AC_SUBST(LVM_VERSION) AC_SUBST(LVM_VERSION)
AC_SUBST(LVM1_FALLBACK) AC_SUBST(LVM1_FALLBACK)
@@ -563,6 +580,7 @@ AC_SUBST(INTL)
AC_SUBST(CLVMD) AC_SUBST(CLVMD)
AC_SUBST(CLUSTER) AC_SUBST(CLUSTER)
AC_SUBST(FSADM) AC_SUBST(FSADM)
AC_SUBST(DMEVENTD)
################################################################################ ################################################################################
dnl -- First and last lines should not contain files to generate in order to dnl -- First and last lines should not contain files to generate in order to
@@ -572,6 +590,8 @@ Makefile \
make.tmpl \ make.tmpl \
daemons/Makefile \ daemons/Makefile \
daemons/clvmd/Makefile \ daemons/clvmd/Makefile \
dmeventd/Makefile \
dmeventd/mirror/Makefile \
doc/Makefile \ doc/Makefile \
include/Makefile \ include/Makefile \
lib/Makefile \ lib/Makefile \
@@ -599,3 +619,7 @@ fi
if test x$FSADM == xyes; then if test x$FSADM == xyes; then
AC_MSG_WARN(fsadm support is untested) AC_MSG_WARN(fsadm support is untested)
fi fi
if test x$DMEVENTD == xyes; then
AC_MSG_WARN(dmeventd support is untested)
fi

View File

@@ -53,10 +53,19 @@ endif
TARGETS = \ TARGETS = \
clvmd clvmd
include $(top_srcdir)/make.tmpl LVMLIBS = -llvm
ifeq ("@DMEVENTD@", "yes")
LVMLIBS += -ldevmapper-event -lpthread
endif
ifeq ("@DEVMAPPER@", "yes")
LVMLIBS += -ldevmapper
endif
CFLAGS += -D_REENTRANT -fno-strict-aliasing CFLAGS += -D_REENTRANT -fno-strict-aliasing
LIBS += -ldevmapper -llvm -lpthread
include $(top_srcdir)/make.tmpl
INSTALL_TARGETS = \ INSTALL_TARGETS = \
install_clvmd install_clvmd

View File

@@ -1,3 +1,5 @@
process_event dm_event_register
register_device dm_event_unregister
unregister_device dm_event_get_registered_device
dm_event_set_timeout
dm_event_get_timeout

View File

@@ -1,14 +1,13 @@
# #
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. # Copyright (C) 2005 Red Hat, Inc. All rights reserved.
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
# #
# This file is part of the device-mapper userspace tools. # This file is part of the device-mapper userspace tools.
# #
# This copyrighted material is made available to anyone wishing to use, # This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions # modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2. # of the GNU Lesser General Public License v.2.1.
# #
# You should have received a copy of the GNU General Public License # 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, # along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
@@ -16,36 +15,41 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@ top_srcdir = @top_srcdir@
VPATH = @srcdir@ VPATH = @srcdir@
TARGETS = dmevent dmeventd SOURCES = libdevmapper-event.c \
INSTALL_TYPE = install_dynamic dmeventd.c
SOURCES = noop.c LIB_STATIC = libdevmapper-event.a
CLEAN_TARGETS = dmevent.o dmeventd.o
ifeq ("@LIB_SUFFIX@","dylib") ifeq ("@LIB_SUFFIX@","dylib")
LIB_SHARED = libdmeventdnoop.dylib LIB_SHARED = libdevmapper-event.dylib
else else
LIB_SHARED = libdmeventdnoop.so LIB_SHARED = libdevmapper-event.so
endif endif
LDFLAGS += -ldl -ldevmapper -lmultilog
include ../make.tmpl include ../make.tmpl
libdmeventdnoop.so: noop.o CLDFLAGS += -ldl -ldevmapper -lpthread
dmevent: dmevent.o $(interfacedir)/libdevmapper.$(LIB_SUFFIX) $(top_srcdir)/lib/event/libdmevent.$(LIB_SUFFIX) .PHONY: install_dynamic install_static
$(CC) -o $@ dmevent.o $(LDFLAGS) \
-L$(interfacedir) -L$(DESTDIR)/lib -L$(top_srcdir)/lib/event -L$(top_srcdir)/multilog $(LIBS)
dmeventd: dmeventd.o $(interfacedir)/libdevmapper.$(LIB_SUFFIX) $(top_srcdir)/lib/event/libdmevent.$(LIB_SUFFIX) INSTALL_TYPE = install_dynamic
$(CC) -o $@ dmeventd.o $(LDFLAGS) \
-L$(interfacedir) -L$(DESTDIR)/lib -L$(top_srcdir)/lib/event -L$(top_srcdir)/multilog -lpthread -ldmevent $(LIBS) ifeq ("@STATIC_LINK@", "yes")
INSTALL_TYPE += install_static
endif
install: $(INSTALL_TYPE) install: $(INSTALL_TYPE)
.PHONY: install_dynamic install_dynamic: libdevmapper-event.$(LIB_SUFFIX)
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
$(libdir)/libdevmapper-event.$(LIB_SUFFIX).$(LIB_VERSION)
$(LN_S) -f libdevmapper-event.$(LIB_SUFFIX).$(LIB_VERSION) \
$(libdir)/libdevmapper-event.$(LIB_SUFFIX)
$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper-event.h \
$(includedir)/libdevmapper-event.h
install_dynamic: dmeventd install_static: libdevmapper-event.a
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) dmeventd $(sbindir)/dmeventd $(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
$(libdir)/libdevmapper-event.a.$(LIB_VERSION)
$(LN_S) -f libdevmapper-event.a.$(LIB_VERSION) $(libdir)/libdevmapper-event.a

View File

@@ -1,240 +0,0 @@
/*
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* 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 "libdm-event.h"
#include "libmultilog.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
static enum event_type events = ALL_ERRORS; /* All until we can distinguish. */
static char default_dso_name[] = "noop"; /* default DSO is noop */
static int default_reg = 1; /* default action is register */
static uint32_t timeout;
struct event_ops {
int (*dm_register_for_event)(char *dso_name, char *device,
enum event_type event_types);
int (*dm_unregister_for_event)(char *dso_name, char *device,
enum event_type event_types);
int (*dm_get_registered_device)(char **dso_name, char **device,
enum event_type *event_types, int next);
int (*dm_set_event_timeout)(char *device, uint32_t time);
int (*dm_get_event_timeout)(char *device, uint32_t *time);
};
/* Display help. */
static void print_usage(char *name)
{
char *cmd = strrchr(name, '/');
cmd = cmd ? cmd + 1 : name;
printf("Usage::\n"
"%s [options] <device>\n"
"\n"
"Options:\n"
" -d <dso> Specify the DSO to use.\n"
" -h Print this usage.\n"
" -l List registered devices.\n"
" -r Register for event (default).\n"
" -t <timeout> (un)register for timeout event.\n"
" -u Unregister for event.\n"
"\n", cmd);
}
/* Parse command line arguments. */
static int parse_argv(int argc, char **argv, char **dso_name_arg,
char **device_arg, int *reg, int *list)
{
int c;
const char *options = "d:hlrt:u";
while ((c = getopt(argc, argv, options)) != -1) {
switch (c) {
case 'd':
*dso_name_arg = optarg;
break;
case 'h':
print_usage(argv[0]);
exit(EXIT_SUCCESS);
case 'l':
*list = 1;
break;
case 'r':
*reg = 1;
break;
case 't':
events = TIMEOUT;
if (sscanf(optarg, "%"SCNu32, &timeout) != 1){
fprintf(stderr, "invalid timeout '%s'\n",
optarg);
timeout = 0;
}
break;
case 'u':
*reg = 0;
break;
default:
fprintf(stderr, "Unknown option '%c'.\n"
"Try '-h' for help.\n", c);
return 0;
}
}
if (optind >= argc) {
if (!*list) {
fprintf(stderr, "You need to specify a device.\n");
return 0;
}
} else
*device_arg = argv[optind];
return 1;
}
static int lookup_symbol(void *dl, void **symbol, const char *name)
{
if ((*symbol = dlsym(dl, name)))
return 1;
fprintf(stderr, "error looking up %s symbol: %s\n", name, dlerror());
return 0;
}
static int lookup_symbols(void *dl, struct event_ops *e)
{
return lookup_symbol(dl, (void *) &e->dm_register_for_event,
"dm_register_for_event") &&
lookup_symbol(dl, (void *) &e->dm_unregister_for_event,
"dm_unregister_for_event") &&
lookup_symbol(dl, (void *) &e->dm_get_registered_device,
"dm_get_registered_device") &&
lookup_symbol(dl, (void *) &e->dm_set_event_timeout,
"dm_set_event_timeout") &&
lookup_symbol(dl, (void *) &e->dm_get_event_timeout,
"dm_get_event_timeout");
}
int main(int argc, char **argv)
{
void *dl;
struct event_ops e;
int list = 0, next = 0, ret, reg = default_reg;
char *device, *device_arg = NULL, *dso_name, *dso_name_arg = NULL;
if (!parse_argv(argc, argv, &dso_name_arg, &device_arg, &reg, &list))
exit(EXIT_FAILURE);
if (device_arg) {
if (!(device = strdup(device_arg)))
exit(EXIT_FAILURE);
} else
device = NULL;
if (dso_name_arg) {
if (!(dso_name = strdup(dso_name_arg)))
exit(EXIT_FAILURE);
} else {
if (!(dso_name = strdup(default_dso_name)))
exit(EXIT_FAILURE);
}
/* FIXME: use -v/-q options to set this */
multilog_add_type(standard, NULL);
multilog_init_verbose(standard, _LOG_DEBUG);
if (!(dl = dlopen("libdmevent.so", RTLD_NOW))){
fprintf(stderr, "Cannot dlopen libdmevent.so: %s\n", dlerror());
goto out;
}
if (!(lookup_symbols(dl, &e)))
goto out;
if (list) {
while (1) {
if ((ret= e.dm_get_registered_device(&dso_name,
&device,
&events, next)))
break;
printf("%s %s 0x%x", dso_name, device, events);
if (events & TIMEOUT){
if ((ret = e.dm_get_event_timeout(device,
&timeout))) {
ret = EXIT_FAILURE;
goto out;
}
printf(" %"PRIu32"\n", timeout);
} else
printf("\n");
if (device_arg)
break;
next = 1;
}
ret = (ret && device_arg) ? EXIT_FAILURE : EXIT_SUCCESS;
goto out;
}
if ((ret = reg ? e.dm_register_for_event(dso_name, device, events) :
e.dm_unregister_for_event(dso_name, device, events))) {
fprintf(stderr, "Failed to %sregister %s: %s\n",
reg ? "": "un", device, strerror(-ret));
ret = EXIT_FAILURE;
} else {
if (reg && (events & TIMEOUT) &&
((ret = e.dm_set_event_timeout(device, timeout)))){
fprintf(stderr, "Failed to set timeout for %s: %s\n",
device, strerror(-ret));
ret = EXIT_FAILURE;
} else {
printf("%s %sregistered successfully.\n",
device, reg ? "" : "un");
ret = EXIT_SUCCESS;
}
}
out:
multilog_del_type(standard);
if (device)
free(device);
if (dso_name)
free(dso_name);
exit(ret);
}
/*
* 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:
*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
#ifndef __DMEVENTD_DOT_H__
#define __DMEVENTD_DOT_H__
#define EXIT_LOCKFILE_INUSE 2
#define EXIT_DESC_CLOSE_FAILURE 3
#define EXIT_OPEN_PID_FAILURE 4
#define EXIT_FIFO_FAILURE 5
#define EXIT_CHDIR_FAILURE 6
void dmeventd(void)
__attribute((noreturn));
#endif /* __DMEVENTD_DOT_H__ */

View File

@@ -0,0 +1,510 @@
/*
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* 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 "lib.h"
#include "libdevmapper-event.h"
//#include "libmultilog.h"
#include "dmeventd.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
/* Set by any of the external fxns the first time one of them is called */
/* FIXME Unused */
// static int _logging = 0;
/* Fetch a string off src and duplicate it into *dest. */
/* FIXME: move to seperate module to share with the daemon. */
static const char delimiter = ' ';
static char *fetch_string(char **src)
{
char *p, *ret;
if ((p = strchr(*src, delimiter)))
*p = 0;
if ((ret = dm_strdup(*src)))
*src += strlen(ret) + 1;
if (p)
*p = delimiter;
return ret;
}
/* Parse a device message from the daemon. */
static int parse_message(struct dm_event_daemon_message *msg, char **dso_name,
char **device, enum dm_event_type *events)
{
char *p = msg->msg;
if ((*dso_name = fetch_string(&p)) &&
(*device = fetch_string(&p))) {
*events = atoi(p);
return 0;
}
return -ENOMEM;
}
/*
* daemon_read
* @fifos
* @msg
*
* Read message from daemon.
*
* Returns: 0 on failure, 1 on success
*/
static int daemon_read(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
{
unsigned bytes = 0;
int ret = 0;
fd_set fds;
memset(msg, 0, sizeof(*msg));
while (bytes < sizeof(*msg)) {
do {
/* Watch daemon read FIFO for input. */
FD_ZERO(&fds);
FD_SET(fifos->server, &fds);
ret = select(fifos->server+1, &fds, NULL, NULL, NULL);
if (ret < 0 && errno != EINTR) {
/* FIXME Log error */
return 0;
}
} while (ret < 1);
ret = read(fifos->server, msg, sizeof(*msg) - bytes);
if (ret < 0) {
if ((errno == EINTR) || (errno == EAGAIN))
continue;
else {
/* FIXME Log error */
return 0;
}
}
bytes += ret;
}
return bytes == sizeof(*msg);
}
/* Write message to daemon. */
static int daemon_write(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
{
unsigned bytes = 0;
int ret = 0;
fd_set fds;
while (bytes < sizeof(*msg)) {
do {
/* Watch daemon write FIFO to be ready for output. */
FD_ZERO(&fds);
FD_SET(fifos->client, &fds);
ret = select(fifos->client +1, NULL, &fds, NULL, NULL);
if ((ret < 0) && (errno != EINTR)) {
/* FIXME Log error */
return 0;
}
} while (ret < 1);
ret = write(fifos->client, msg, sizeof(*msg) - bytes);
if (ret < 0) {
if ((errno == EINTR) || (errno == EAGAIN))
continue;
else {
/* fixme: log error */
return 0;
}
}
bytes += ret;
}
return bytes == sizeof(*msg);
}
static int daemon_talk(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg,
int cmd, char *dso_name, char *device,
enum dm_event_type events, uint32_t timeout)
{
memset(msg, 0, sizeof(*msg));
/*
* Set command and pack the arguments
* into ASCII message string.
*/
msg->opcode.cmd = cmd;
if (sizeof(msg->msg) <= (unsigned) snprintf(msg->msg, sizeof(msg->msg),
"%s %s %u %"PRIu32,
dso_name ? dso_name : "",
device ? device : "",
events, timeout)) {
stack;
return -ENAMETOOLONG;
}
/*
* Write command and message to and
* read status return code from daemon.
*/
if (!daemon_write(fifos, msg)) {
stack;
return -EIO;
}
if (!daemon_read(fifos, msg)) {
stack;
return -EIO;
}
return msg->opcode.status;
}
static volatile sig_atomic_t daemon_running = 0;
static void daemon_running_signal_handler(int sig)
{
daemon_running = 1;
}
/*
* start_daemon
*
* This function forks off a process (dmeventd) that will handle
* the events. A signal must be returned from the child to
* indicate when it is ready to handle requests. The parent
* (this function) returns 1 if there is a daemon running.
*
* Returns: 1 on success, 0 otherwise
*/
static int start_daemon(void)
{
int pid, ret=0;
void *old_hand;
sigset_t set, oset;
/* Must be able to acquire signal */
old_hand = signal(SIGUSR1, &daemon_running_signal_handler);
if (old_hand == SIG_ERR) {
log_error("Unable to setup signal handler.");
return 0;
}
if (sigemptyset(&set) || sigaddset(&set, SIGUSR1)) {
log_error("Unable to fill signal set.");
} else if (sigprocmask(SIG_UNBLOCK, &set, &oset)) {
log_error("Can't unblock the potentially blocked signal SIGUSR1");
}
pid = fork();
if (pid < 0)
log_error("Unable to fork.\n");
else if (pid) { /* parent waits for child to get ready for requests */
int status;
/* FIXME Better way to do this? */
while (!waitpid(pid, &status, WNOHANG) && !daemon_running)
sleep(1);
if (daemon_running) {
ret = 1;
} else {
switch (WEXITSTATUS(status)) {
case EXIT_LOCKFILE_INUSE:
/*
* Note, this is ok... we still have daemon
* that we can communicate with...
*/
log_print("Starting dmeventd failed: "
"dmeventd already running.\n");
ret = 1;
break;
default:
log_error("Unable to start dmeventd.\n");
break;
}
}
/*
* Sometimes, a single process may perform multiple calls
* that result in a daemon starting and exiting. If we
* don't reset this, the second (or greater) time the daemon
* is started will cause this logic not to work.
*/
daemon_running = 0;
} else {
signal(SIGUSR1, SIG_IGN); /* don't care about error */
/* dmeventd function is responsible for properly setting **
** itself up. It must never return - only exit. This is**
** why it is followed by an EXIT_FAILURE */
dmeventd();
exit(EXIT_FAILURE);
}
/* FIXME What if old_hand is SIG_ERR? */
if (signal(SIGUSR1, old_hand) == SIG_ERR)
log_error("Unable to reset signal handler.");
if (sigprocmask(SIG_SETMASK, &oset, NULL))
log_error("Unable to reset signal mask.");
return ret;
}
/* Initialize client. */
static int init_client(struct dm_event_fifos *fifos)
{
/* FIXME Is fifo the most suitable method? */
/* FIXME Why not share comms/daemon code with something else e.g. multipath? */
/* init fifos */
memset(fifos, 0, sizeof(*fifos));
fifos->client_path = DM_EVENT_FIFO_CLIENT;
fifos->server_path = DM_EVENT_FIFO_SERVER;
/* FIXME The server should be responsible for these, not the client. */
/* Create fifos */
if (((mkfifo(fifos->client_path, 0600) == -1) && errno != EEXIST) ||
((mkfifo(fifos->server_path, 0600) == -1) && errno != EEXIST)) {
log_error("%s: Failed to create a fifo.\n", __func__);
return 0;
}
/* FIXME Warn/abort if perms are wrong - not something to fix silently. */
/* If they were already there, make sure permissions are ok. */
if (chmod(fifos->client_path, 0600)) {
log_error("Unable to set correct file permissions on %s",
fifos->client_path);
return 0;
}
if (chmod(fifos->server_path, 0600)) {
log_error("Unable to set correct file permissions on %s",
fifos->server_path);
return 0;
}
/*
* Open the fifo used to read from the daemon.
* Allows daemon to create its write fifo...
*/
if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) {
log_error("%s: open server fifo %s\n",
__func__, fifos->server_path);
stack;
return 0;
}
/* Lock out anyone else trying to do communication with the daemon. */
/* FIXME Why failure not retry? How do multiple processes communicate? */
if (flock(fifos->server, LOCK_EX) < 0){
log_error("%s: flock %s\n", __func__, fifos->server_path);
close(fifos->server);
return 0;
}
/* Anyone listening? If not, errno will be ENXIO */
while ((fifos->client = open(fifos->client_path,
O_WRONLY | O_NONBLOCK)) < 0) {
if (errno != ENXIO) {
log_error("%s: Can't open client fifo %s: %s\n",
__func__, fifos->client_path, strerror(errno));
close(fifos->server);
stack;
return 0;
}
/* FIXME Unnecessary if daemon was started before calling this */
if (!start_daemon()) {
stack;
return 0;
}
}
return 1;
}
static void dtr_client(struct dm_event_fifos *fifos)
{
if (flock(fifos->server, LOCK_UN))
log_error("flock unlock %s\n", fifos->server_path);
close(fifos->client);
close(fifos->server);
}
/* Check, if a block device exists. */
static int device_exists(char *device)
{
struct stat st_buf;
char path2[PATH_MAX];
if (!device)
return 0;
if (device[0] == '/') /* absolute path */
return !stat(device, &st_buf) && S_ISBLK(st_buf.st_mode);
if (PATH_MAX <= snprintf(path2, PATH_MAX, "%s/%s", dm_dir(), device))
return 0;
return !stat(path2, &st_buf) && S_ISBLK(st_buf.st_mode);
}
/* Handle the event (de)registration call and return negative error codes. */
static int do_event(int cmd, struct dm_event_daemon_message *msg,
char *dso_name, char *device, enum dm_event_type events,
uint32_t timeout)
{
int ret;
struct dm_event_fifos fifos;
/* FIXME Start the daemon here if it's not running e.g. exclusive lock file */
/* FIXME Move this to separate 'dm_event_register_handler' - if no daemon here, fail */
if (!init_client(&fifos)) {
stack;
return -ESRCH;
}
/* FIXME Use separate 'dm_event_register_handler' function to pass in dso? */
ret = daemon_talk(&fifos, msg, cmd, dso_name, device, events, timeout);
/* what is the opposite of init? */
dtr_client(&fifos);
return ret;
}
/* FIXME remove dso_name - use handle instead */
/* FIXME Use uuid not path! */
/* External library interface. */
int dm_event_register(char *dso_name, char *device_path,
enum dm_event_type events)
{
int ret;
struct dm_event_daemon_message msg;
if (!device_exists(device_path)) {
log_error("%s: device not found", device_path);
return 0;
}
if ((ret = do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg,
dso_name, device_path, events, 0)) < 0) {
log_error("%s: event registration failed: %s", device_path,
strerror(-ret));
return 0;
}
return 1;
}
int dm_event_unregister(char *dso_name, char *device_path,
enum dm_event_type events)
{
int ret;
struct dm_event_daemon_message msg;
if (!device_exists(device_path)) {
log_error("%s: device not found", device_path);
return 0;
}
if ((ret = do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg,
dso_name, device_path, events, 0)) < 0) {
log_error("%s: event deregistration failed: %s", device_path,
strerror(-ret));
return 0;
}
return 1;
}
int dm_event_get_registered_device(char **dso_name, char **device_path,
enum dm_event_type *events, int next)
{
int ret;
char *dso_name_arg = NULL, *device_path_arg = NULL;
struct dm_event_daemon_message msg;
if (!(ret = do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
&msg, *dso_name, *device_path, *events, 0)))
ret = parse_message(&msg, &dso_name_arg, &device_path_arg,
events);
if (next){
if (*dso_name)
dm_free(*dso_name);
if (*device_path)
dm_free(*device_path);
*dso_name = dso_name_arg;
*device_path = device_path_arg;
} else {
if (!(*dso_name))
*dso_name = dso_name_arg;
if (!(*device_path))
*device_path = device_path_arg;
}
return ret;
}
int dm_event_set_timeout(char *device_path, uint32_t timeout)
{
struct dm_event_daemon_message msg;
if (!device_exists(device_path))
return -ENODEV;
return do_event(DM_EVENT_CMD_SET_TIMEOUT, &msg,
NULL, device_path, 0, timeout);
}
int dm_event_get_timeout(char *device_path, uint32_t *timeout)
{
int ret;
struct dm_event_daemon_message msg;
if (!device_exists(device_path))
return -ENODEV;
if (!(ret = do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path, 0, 0)))
*timeout = atoi(msg.msg);
return ret;
}
/*
* 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:
*/

View File

@@ -0,0 +1,108 @@
/*
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* 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
*/
/*
* Note that this file is released only as part of a technology preview
* and its contents may change in future updates in ways that do not
* preserve compatibility.
*/
#ifndef LIB_DMEVENT_H
#define LIB_DMEVENT_H
#include <stdint.h>
/* FIXME This stuff must be configurable. */
#define DM_EVENT_DAEMON "/sbin/dmeventd"
#define DM_EVENT_LOCKFILE "/var/lock/dmeventd"
#define DM_EVENT_FIFO_CLIENT "/var/run/dmeventd-client"
#define DM_EVENT_FIFO_SERVER "/var/run/dmeventd-server"
#define DM_EVENT_PIDFILE "/var/run/dmeventd.pid"
#define DM_EVENT_DEFAULT_TIMEOUT 10
/* Commands for the daemon passed in the message below. */
enum dm_event_command {
DM_EVENT_CMD_ACTIVE = 1,
DM_EVENT_CMD_REGISTER_FOR_EVENT,
DM_EVENT_CMD_UNREGISTER_FOR_EVENT,
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE,
DM_EVENT_CMD_SET_TIMEOUT,
DM_EVENT_CMD_GET_TIMEOUT,
};
/* Message passed between client and daemon. */
struct dm_event_daemon_message {
union {
unsigned int cmd; /* FIXME Use fixed size. */
int status; /* FIXME Use fixed size. */
} opcode;
char msg[252]; /* FIXME Why is this 252 ? */
} __attribute__((packed)); /* FIXME Do this properly! */
/* FIXME Is this meant to be exported? I can't see where the interface uses it. */
/* Fifos for client/daemon communication. */
struct dm_event_fifos {
int client;
int server;
const char *client_path;
const char *server_path;
};
/* Event type definitions. */
/* FIXME Use masks to separate the types and provide for extension. */
enum dm_event_type {
DM_EVENT_SINGLE = 0x01, /* Report multiple errors just once. */
DM_EVENT_MULTI = 0x02, /* Report all of them. */
DM_EVENT_SECTOR_ERROR = 0x04, /* Failure on a particular sector. */
DM_EVENT_DEVICE_ERROR = 0x08, /* Device failure. */
DM_EVENT_PATH_ERROR = 0x10, /* Failure on an io path. */
DM_EVENT_ADAPTOR_ERROR = 0x20, /* Failure off a host adaptor. */
DM_EVENT_SYNC_STATUS = 0x40, /* Mirror synchronization completed/failed. */
DM_EVENT_TIMEOUT = 0x80, /* Timeout has occured */
};
/* FIXME Use a mask. */
#define DM_EVENT_ALL_ERRORS (DM_EVENT_SECTOR_ERROR | DM_EVENT_DEVICE_ERROR | \
DM_EVENT_PATH_ERROR | DM_EVENT_ADAPTOR_ERROR)
/* Prototypes for event lib interface. */
/* FIXME Replace device with standard name/uuid/devno choice */
/* Interface changes:
First register a handler, passing in a unique ref for the device. */
// int dm_event_register_handler(const char *dso_name, const char *device);
// int dm_event_register(const char *dso_name, const char *name, const char *uuid, uint32_t major, uint32_t minor, enum dm_event_type events);
/* Or (better?) add to task structure and use existing functions - run a task to register/unregister events - we may need to run task withe that with the new event mechanism anyway, then the dso calls just hook in.
*/
/* FIXME Missing consts? */
int dm_event_register(char *dso_name, char *device, enum dm_event_type events);
int dm_event_unregister(char *dso_name, char *device,
enum dm_event_type events);
int dm_event_get_registered_device(char **dso_name, char **device,
enum dm_event_type *events, int next);
int dm_event_set_timeout(char *device, uint32_t timeout);
int dm_event_get_timeout(char *device, uint32_t *timeout);
/* Prototypes for DSO interface. */
void process_event(const char *device, enum dm_event_type event);
int register_device(const char *device);
int unregister_device(const char *device);
#endif

View File

@@ -1,12 +0,0 @@
#!/bin/sh
#
# Create test devices for dmeventd
#
trap "rm -f /tmp/tmp.$$" 0 1 2 3 15
echo "0 1024 zero" > /tmp/tmp.$$
dmsetup create test /tmp/tmp.$$
dmsetup create test1 /tmp/tmp.$$
kill -15 $$

View File

@@ -1,39 +0,0 @@
/*
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* 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 "libdm-event.h"
#include "libmultilog.h"
void process_event(char *device, enum event_type event)
{
log_err("[%s] %s(%d) - Device: %s, Event %d\n",
__FILE__, __func__, __LINE__, device, event);
}
int register_device(char *device)
{
log_err("[%s] %s(%d) - Device: %s\n",
__FILE__, __func__, __LINE__, device);
return 1;
}
int unregister_device(char *device)
{
log_err("[%s] %s(%d) - Device: %s\n",
__FILE__, __func__, __LINE__, device);
return 1;
}

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,36 @@
#
# 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@
INCLUDES += -I${top_srcdir}/tools
CLDFLAGS += -L${top_srcdir}/tools -ldevmapper -llvm2cmd
SOURCES = dmeventd_mirror.c
ifeq ("@LIB_SUFFIX@","dylib")
LIB_SHARED = libdevmapper-event-lvm2mirror.dylib
else
LIB_SHARED = libdevmapper-event-lvm2mirror.so
endif
include $(top_srcdir)/make.tmpl
install: libdevmapper-event-lvm2mirror.$(LIB_SUFFIX)
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
$(libdir)/$<.$(LIB_VERSION)
$(LN_S) -f $<.$(LIB_VERSION) $(libdir)/$<

View File

@@ -0,0 +1,246 @@
/*
* 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 */
#define ME_IGNORE 0
#define ME_INSYNC 1
#define ME_FAILURE 2
/* FIXME: We may need to lock around operations to these */
static int register_count = 0;
static struct dm_pool *mem_pool = NULL;
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];
/* 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;
}
p = strstr(sync_str, "/");
if (p) {
p[0] = '\0';
if (strcmp(sync_str, p+1))
rtn = ME_IGNORE;
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.");
rtn = ME_IGNORE;
}
out:
return rtn;
}
static void _temporary_log_fn(int level, const char *file, int line, const char *format)
{
return;
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, *layer = NULL;
if (strlen(device) > 200)
return -ENAMETOOLONG;
if (!split_dm_name(mem_pool, device, &vg, &lv, &layer)) {
syslog(LOG_ERR, "Unable to determine VG name from %s",
device);
return -ENOMEM;
}
/* FIXME Is any sanity-checking required on %s? */
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");
dm_pool_empty(mem_pool); /* FIXME: not safe with multiple threads */
return -ENAMETOOLONG;
}
lvm2_log_fn(_temporary_log_fn);
handle = lvm2_init();
lvm2_log_level(handle, 1);
r = lvm2_run(handle, cmd_str);
dm_pool_empty(mem_pool); /* FIXME: not safe with multiple threads */
return (r == 1)? 0: -1;
}
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;
/* 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);
/* Should check before warning user that device is now linear
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);
}
int register_device(const char *device)
{
syslog(LOG_INFO, "Monitoring %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);
if (!mem_pool)
return 0;
register_count++;
return 1;
}
int unregister_device(const char *device)
{
syslog(LOG_INFO, "Stopped monitoring %s for events\n", device);
if (!(--register_count)) {
dm_pool_destroy(mem_pool);
mem_pool = NULL;
}
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,36 @@
#
# 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@
INCLUDES += -I${top_srcdir}/tools
CLDFLAGS += -L${top_srcdir}/tools -ldevmapper -llvm2cmd
SOURCES = dmeventd_mirror.c
ifeq ("@LIB_SUFFIX@","dylib")
LIB_SHARED = libdevmapper-event-lvm2mirror.dylib
else
LIB_SHARED = libdevmapper-event-lvm2mirror.so
endif
include $(top_srcdir)/make.tmpl
install: libdevmapper-event-lvm2mirror.$(LIB_SUFFIX)
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
$(libdir)/$<.$(LIB_VERSION)
$(LN_S) -f $<.$(LIB_VERSION) $(libdir)/$<

View File

@@ -0,0 +1,246 @@
/*
* 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 */
#define ME_IGNORE 0
#define ME_INSYNC 1
#define ME_FAILURE 2
/* FIXME: We may need to lock around operations to these */
static int register_count = 0;
static struct dm_pool *mem_pool = NULL;
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];
/* 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;
}
p = strstr(sync_str, "/");
if (p) {
p[0] = '\0';
if (strcmp(sync_str, p+1))
rtn = ME_IGNORE;
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.");
rtn = ME_IGNORE;
}
out:
return rtn;
}
static void _temporary_log_fn(int level, const char *file, int line, const char *format)
{
return;
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, *layer = NULL;
if (strlen(device) > 200)
return -ENAMETOOLONG;
if (!split_dm_name(mem_pool, device, &vg, &lv, &layer)) {
syslog(LOG_ERR, "Unable to determine VG name from %s",
device);
return -ENOMEM;
}
/* FIXME Is any sanity-checking required on %s? */
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");
dm_pool_empty(mem_pool); /* FIXME: not safe with multiple threads */
return -ENAMETOOLONG;
}
lvm2_log_fn(_temporary_log_fn);
handle = lvm2_init();
lvm2_log_level(handle, 1);
r = lvm2_run(handle, cmd_str);
dm_pool_empty(mem_pool); /* FIXME: not safe with multiple threads */
return (r == 1)? 0: -1;
}
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;
/* 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);
/* Should check before warning user that device is now linear
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);
}
int register_device(const char *device)
{
syslog(LOG_INFO, "Monitoring %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);
if (!mem_pool)
return 0;
register_count++;
return 1;
}
int unregister_device(const char *device)
{
syslog(LOG_INFO, "Stopped monitoring %s for events\n", device);
if (!(--register_count)) {
dm_pool_destroy(mem_pool);
mem_pool = NULL;
}
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:
*/

View File

@@ -289,4 +289,9 @@ activation {
# dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ] # dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ]
#} #}
# Event daemon
#
#dmeventd {
# mirror_library = "libdevmapper-event-lvm2mirror.so"
#}

View File

@@ -133,6 +133,10 @@ ifeq ("@HAVE_LIBDL@", "yes")
misc/sharedlib.c misc/sharedlib.c
endif endif
ifeq ("@DMEVENTD@", "yes")
CLDFLAGS += -ldevmapper-event
endif
LIB_STATIC = liblvm.a LIB_STATIC = liblvm.a
$(SUBDIRS): $(LIB_STATIC) $(SUBDIRS): $(LIB_STATIC)

View File

@@ -27,6 +27,7 @@
#include "str_list.h" #include "str_list.h"
#include "config.h" #include "config.h"
#include "filter.h" #include "filter.h"
#include "segtype.h"
#include <limits.h> #include <limits.h>
#include <fcntl.h> #include <fcntl.h>
@@ -75,6 +76,11 @@ int driver_version(char *version, size_t size)
{ {
return 0; return 0;
} }
int target_version(const char *target_name, uint32_t *maj,
uint32_t *min, uint32_t *patchlevel)
{
return 0;
}
int target_present(const char *target_name) int target_present(const char *target_name)
{ {
return 0; return 0;
@@ -170,8 +176,8 @@ void set_activation(int act)
log_verbose("Activation enabled. Device-mapper kernel " log_verbose("Activation enabled. Device-mapper kernel "
"driver will be used."); "driver will be used.");
else else
log_verbose("Activation disabled. No device-mapper " log_print("WARNING: Activation disabled. No device-mapper "
"interaction will be attempted."); "interaction will be attempted.");
} }
int activation(void) int activation(void)
@@ -277,7 +283,8 @@ int driver_version(char *version, size_t size)
return dm_driver_version(version, size); return dm_driver_version(version, size);
} }
static int _target_present(const char *target_name) int target_version(const char *target_name, uint32_t *maj,
uint32_t *min, uint32_t *patchlevel)
{ {
int r = 0; int r = 0;
struct dm_task *dmt; struct dm_task *dmt;
@@ -300,6 +307,9 @@ static int _target_present(const char *target_name)
if (!strcmp(target_name, target->name)) { if (!strcmp(target_name, target->name)) {
r = 1; r = 1;
*maj = target->version[0];
*min = target->version[1];
*patchlevel = target->version[2];
goto out; goto out;
} }
@@ -314,6 +324,7 @@ static int _target_present(const char *target_name)
int target_present(const char *target_name, int use_modprobe) int target_present(const char *target_name, int use_modprobe)
{ {
uint32_t maj, min, patchlevel;
#ifdef MODPROBE_CMD #ifdef MODPROBE_CMD
char module[128]; char module[128];
#endif #endif
@@ -323,7 +334,7 @@ int target_present(const char *target_name, int use_modprobe)
#ifdef MODPROBE_CMD #ifdef MODPROBE_CMD
if (use_modprobe) { if (use_modprobe) {
if (_target_present(target_name)) if (target_version(target_name, &maj, &min, &patchlevel))
return 1; return 1;
if (lvm_snprintf(module, sizeof(module), "dm-%s", target_name) if (lvm_snprintf(module, sizeof(module), "dm-%s", target_name)
@@ -338,7 +349,7 @@ int target_present(const char *target_name, int use_modprobe)
} }
#endif #endif
return _target_present(target_name); return target_version(target_name, &maj, &min, &patchlevel);
} }
/* /*
@@ -563,18 +574,53 @@ int lvs_in_vg_opened(struct volume_group *vg)
return count; return count;
} }
static int _register_dev_for_events(struct cmd_context *cmd,
struct logical_volume *lv, int do_reg)
{
#ifdef DMEVENTD
struct list *tmp;
struct lv_segment *seg;
int (*reg) (struct dm_pool *mem, struct lv_segment *,
struct config_tree *cft, int events);
list_iterate(tmp, &lv->segments) {
seg = list_item(tmp, struct lv_segment);
reg = NULL;
if (do_reg) {
if (seg->segtype->ops->target_register_events)
reg = seg->segtype->ops->target_register_events;
} else if (seg->segtype->ops->target_unregister_events)
reg = seg->segtype->ops->target_unregister_events;
if (reg)
/* FIXME specify events */
if (!reg(cmd->mem, seg, cmd->cft, 0)) {
stack;
return 0;
}
}
#endif
return 1;
}
static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s, static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
int error_if_not_suspended) int error_if_not_suspended)
{ {
struct logical_volume *lv; struct logical_volume *lv, *lv_pre;
struct lvinfo info; struct lvinfo info;
if (!activation()) if (!activation())
return 1; return 1;
if (!(lv = lv_from_lvid(cmd, lvid_s, 0)))
return_0;
/* Use precommitted metadata if present */ /* Use precommitted metadata if present */
if (!(lv = lv_from_lvid(cmd, lvid_s, 1))) if (!(lv_pre = lv_from_lvid(cmd, lvid_s, 1)))
return 0; return_0;
if (test_mode()) { if (test_mode()) {
_skip("Suspending '%s'.", lv->name); _skip("Suspending '%s'.", lv->name);
@@ -588,13 +634,16 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
return error_if_not_suspended ? 0 : 1; return error_if_not_suspended ? 0 : 1;
/* If VG was precommitted, preload devices for the LV */ /* If VG was precommitted, preload devices for the LV */
if ((lv->vg->status & PRECOMMITTED)) { if ((lv_pre->vg->status & PRECOMMITTED)) {
if (!_lv_preload(lv)) { if (!_lv_preload(lv_pre)) {
/* FIXME Revert preloading */ /* FIXME Revert preloading */
return_0; return_0;
} }
} }
if (!_register_dev_for_events(cmd, lv, 0))
stack;
memlock_inc(); memlock_inc();
if (!_lv_suspend_lv(lv)) { if (!_lv_suspend_lv(lv)) {
memlock_dec(); memlock_dec();
@@ -645,6 +694,9 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
memlock_dec(); memlock_dec();
fs_unlock(); fs_unlock();
if (!_register_dev_for_events(cmd, lv, 1))
stack;
return 1; return 1;
} }
@@ -688,6 +740,9 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
return 0; return 0;
} }
if (!_register_dev_for_events(cmd, lv, 0))
stack;
memlock_inc(); memlock_inc();
r = _lv_deactivate(lv); r = _lv_deactivate(lv);
memlock_dec(); memlock_dec();
@@ -758,6 +813,9 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
memlock_dec(); memlock_dec();
fs_unlock(); fs_unlock();
if (!_register_dev_for_events(cmd, lv, 1))
stack;
return r; return r;
} }

View File

@@ -37,6 +37,8 @@ int library_version(char *version, size_t size);
int lvm1_present(struct cmd_context *cmd); int lvm1_present(struct cmd_context *cmd);
int target_present(const char *target_name, int use_modprobe); int target_present(const char *target_name, int use_modprobe);
int target_version(const char *target_name, uint32_t *maj,
uint32_t *min, uint32_t *patchlevel);
void activation_exit(void); void activation_exit(void);

View File

@@ -977,6 +977,8 @@ static int _tree_action(struct dev_manager *dm, struct logical_volume *lv, actio
goto_out; goto_out;
break; break;
case SUSPEND: case SUSPEND:
if (!lv_is_origin(lv) && !lv_is_cow(lv))
dm_tree_skip_lockfs(root);
if (!dm_tree_suspend_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1)) if (!dm_tree_suspend_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1))
goto_out; goto_out;
break; break;

View File

@@ -34,6 +34,8 @@
#define DEFAULT_LOCK_DIR "/var/lock/lvm" #define DEFAULT_LOCK_DIR "/var/lock/lvm"
#define DEFAULT_LOCKING_LIB "lvm2_locking.so" #define DEFAULT_LOCKING_LIB "lvm2_locking.so"
#define DEFAULT_DMEVENTD_MIRROR_LIB "libdevmapper-event-lvm2mirror.so"
#define DEFAULT_UMASK 0077 #define DEFAULT_UMASK 0077
#ifdef LVM1_FALLBACK #ifdef LVM1_FALLBACK

View File

@@ -140,7 +140,12 @@ static int _fill_maps(struct dm_hash_table *maps, struct volume_group *vg,
lvm = lvms[lv_num]; lvm = lvms[lv_num];
if (!lvm) { if (!lvm) {
log_err("invalid lv in extent map"); log_error("Invalid LV in extent map "
"(PV %s, PE %" PRIu32
", LV %" PRIu32
", LE %" PRIu32 ")",
dev_name(pv->dev), i,
lv_num, e[i].le_num);
return 0; return 0;
} }

View File

@@ -52,7 +52,8 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
uint32_t mirrored_pe, uint32_t mirrored_pe,
uint32_t status, uint32_t status,
struct list *allocatable_pvs, struct list *allocatable_pvs,
alloc_policy_t alloc); alloc_policy_t alloc,
struct list *parallel_areas);
int lv_add_segment(struct alloc_handle *ah, int lv_add_segment(struct alloc_handle *ah,
uint32_t first_area, uint32_t num_areas, uint32_t first_area, uint32_t num_areas,
@@ -83,4 +84,7 @@ int lv_add_more_mirrored_areas(struct logical_volume *lv,
void alloc_destroy(struct alloc_handle *ah); void alloc_destroy(struct alloc_handle *ah);
struct list *build_parallel_areas_from_lv(struct cmd_context *cmd,
struct logical_volume *lv);
#endif #endif

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved. * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
* *
* This file is part of LVM2. * This file is part of LVM2.
* *
@@ -24,6 +24,18 @@
#include "display.h" #include "display.h"
#include "segtype.h" #include "segtype.h"
/*
* PVs used by a segment of an LV
*/
struct seg_pvs {
struct list list;
struct list pvs; /* struct pv_list */
uint32_t le;
uint32_t len;
};
/* /*
* Find first unused LV number. * Find first unused LV number.
*/ */
@@ -342,13 +354,16 @@ static int _lv_reduce(struct logical_volume *lv, uint32_t extents, int delete)
} }
/* /*
* Empty an LV * Empty an LV.
*/ */
int lv_empty(struct logical_volume *lv) int lv_empty(struct logical_volume *lv)
{ {
return _lv_reduce(lv, 0, lv->le_count); return _lv_reduce(lv, lv->le_count, 0);
} }
/*
* Remove given number of extents from LV.
*/
int lv_reduce(struct logical_volume *lv, uint32_t extents) int lv_reduce(struct logical_volume *lv, uint32_t extents)
{ {
return _lv_reduce(lv, extents, 1); return _lv_reduce(lv, extents, 1);
@@ -391,6 +406,10 @@ struct alloc_handle {
uint32_t log_count; /* Number of parallel 1-extent logs */ uint32_t log_count; /* Number of parallel 1-extent logs */
uint32_t total_area_len; /* Total number of parallel extents */ uint32_t total_area_len; /* Total number of parallel extents */
struct physical_volume *mirrored_pv; /* FIXME Remove this */
uint32_t mirrored_pe; /* FIXME Remove this */
struct list *parallel_areas; /* PVs to avoid */
struct alloced_area log_area; /* Extent used for log */ struct alloced_area log_area; /* Extent used for log */
struct list alloced_areas[0]; /* Lists of areas in each stripe */ struct list alloced_areas[0]; /* Lists of areas in each stripe */
}; };
@@ -404,7 +423,9 @@ static struct alloc_handle *_alloc_init(struct dm_pool *mem,
uint32_t mirrors, uint32_t mirrors,
uint32_t stripes, uint32_t stripes,
uint32_t log_count, uint32_t log_count,
struct physical_volume *mirrored_pv) struct physical_volume *mirrored_pv,
uint32_t mirrored_pe,
struct list *parallel_areas)
{ {
struct alloc_handle *ah; struct alloc_handle *ah;
uint32_t s, area_count; uint32_t s, area_count;
@@ -458,6 +479,10 @@ static struct alloc_handle *_alloc_init(struct dm_pool *mem,
for (s = 0; s < ah->area_count; s++) for (s = 0; s < ah->area_count; s++)
list_init(&ah->alloced_areas[s]); list_init(&ah->alloced_areas[s]);
ah->mirrored_pv = mirrored_pv;
ah->mirrored_pe = mirrored_pe;
ah->parallel_areas = parallel_areas;
return ah; return ah;
} }
@@ -646,7 +671,6 @@ static int _check_contiguous(struct lv_segment *prev_lvseg,
/* /*
* Choose sets of parallel areas to use, respecting any constraints. * Choose sets of parallel areas to use, respecting any constraints.
*/ */
/* FIXME Also accept existing areas new space must be parallel to */
static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc, static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
struct list *pvms, struct pv_area **areas, struct list *pvms, struct pv_area **areas,
uint32_t areas_size, unsigned can_split, uint32_t areas_size, unsigned can_split,
@@ -655,10 +679,15 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
{ {
struct pv_map *pvm; struct pv_map *pvm;
struct pv_area *pva; struct pv_area *pva;
struct pv_list *pvl;
unsigned already_found_one = 0; unsigned already_found_one = 0;
unsigned contiguous = 0, contiguous_count = 0; unsigned contiguous = 0, contiguous_count = 0;
unsigned ix; unsigned ix;
unsigned ix_offset = 0; /* Offset for non-contiguous allocations */ unsigned ix_offset = 0; /* Offset for non-contiguous allocations */
uint32_t max_parallel; /* Maximum extents to allocate */
uint32_t next_le;
struct seg_pvs *spvs;
struct list *parallel_pvs;
/* FIXME Do calculations on free extent counts before selecting space */ /* FIXME Do calculations on free extent counts before selecting space */
/* FIXME Select log PV appropriately if there isn't one yet */ /* FIXME Select log PV appropriately if there isn't one yet */
@@ -676,6 +705,25 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
do { do {
ix = 0; ix = 0;
parallel_pvs = NULL;
max_parallel = needed;
/*
* If there are existing parallel PVs, avoid them and reduce
* the maximum we can allocate in one go accordingly.
*/
if (ah->parallel_areas) {
list_iterate_items(spvs, ah->parallel_areas) {
next_le = (prev_lvseg ? prev_lvseg->le + prev_lvseg->len : 0) + *allocated;
if (next_le >= spvs->le) {
if (next_le + max_parallel > spvs->le + spvs->len)
max_parallel = (spvs->le + spvs->len - next_le) * ah->area_multiple;
parallel_pvs = &spvs->pvs;
break;
}
}
}
/* /*
* Put the smallest area of each PV that is at least the * Put the smallest area of each PV that is at least the
* size we need into areas array. If there isn't one * size we need into areas array. If there isn't one
@@ -686,10 +734,18 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
if (list_empty(&pvm->areas)) if (list_empty(&pvm->areas))
continue; /* Next PV */ continue; /* Next PV */
/* Don't allocate onto the log pv */ if (alloc != ALLOC_ANYWHERE) {
if ((alloc != ALLOC_ANYWHERE) && ah->log_count && /* Don't allocate onto the log pv */
(pvm->pv == ah->log_area.pv)) if (ah->log_count &&
continue; /* Next PV */ pvm->pv == ah->log_area.pv)
continue; /* Next PV */
/* Avoid PVs used by existing parallel areas */
if (parallel_pvs)
list_iterate_items(pvl, parallel_pvs)
if (pvm->pv == pvl->pv)
goto next_pv;
}
already_found_one = 0; already_found_one = 0;
/* First area in each list is the largest */ /* First area in each list is the largest */
@@ -700,17 +756,17 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
pvm->pv, pvm->pv,
pva, areas)) { pva, areas)) {
contiguous_count++; contiguous_count++;
break; /* Next PV */ goto next_pv;
} }
continue; continue;
} }
/* Is it big enough on its own? */ /* Is it big enough on its own? */
if ((pva->count < needed - *allocated) && if ((pva->count < max_parallel - *allocated) &&
((!can_split && !ah->log_count) || ((!can_split && !ah->log_count) ||
(already_found_one && (already_found_one &&
!(alloc == ALLOC_ANYWHERE)))) !(alloc == ALLOC_ANYWHERE))))
break; /* Next PV */ goto next_pv;
if (!already_found_one || if (!already_found_one ||
alloc == ALLOC_ANYWHERE) { alloc == ALLOC_ANYWHERE) {
@@ -720,8 +776,9 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
areas[ix + ix_offset - 1] = pva; areas[ix + ix_offset - 1] = pva;
break; /* Next PV */ goto next_pv;
} }
next_pv:
if (ix >= areas_size) if (ix >= areas_size)
break; break;
} }
@@ -743,7 +800,7 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
/* First time around, use smallest area as log_area */ /* First time around, use smallest area as log_area */
/* FIXME decide which PV to use at top of function instead */ /* FIXME decide which PV to use at top of function instead */
if (!_alloc_parallel_area(ah, needed, areas, if (!_alloc_parallel_area(ah, max_parallel, areas,
allocated, allocated,
(ah->log_count && !ah->log_area.len) ? (ah->log_count && !ah->log_area.len) ?
*(areas + ix_offset + ix - 1) : *(areas + ix_offset + ix - 1) :
@@ -764,13 +821,11 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
*/ */
static int _allocate(struct alloc_handle *ah, static int _allocate(struct alloc_handle *ah,
struct volume_group *vg, struct volume_group *vg,
struct logical_volume *lv, uint32_t status, struct logical_volume *lv, uint32_t status,
uint32_t new_extents, uint32_t new_extents,
struct list *allocatable_pvs, struct list *allocatable_pvs,
uint32_t stripes, uint32_t mirrors, uint32_t stripes, uint32_t mirrors,
struct segment_type *segtype, struct segment_type *segtype)
struct physical_volume *mirrored_pv,
uint32_t mirrored_pe)
{ {
struct pv_area **areas; struct pv_area **areas;
uint32_t allocated = lv ? lv->le_count : 0; uint32_t allocated = lv ? lv->le_count : 0;
@@ -781,12 +836,12 @@ static int _allocate(struct alloc_handle *ah,
struct list *pvms; struct list *pvms;
uint32_t areas_size; uint32_t areas_size;
if (allocated >= new_extents) { if (allocated >= new_extents && !ah->log_count) {
log_error("_allocate called with no work to do!"); log_error("_allocate called with no work to do!");
return 1; return 1;
} }
if (mirrored_pv || (ah->alloc == ALLOC_CONTIGUOUS)) if (ah->mirrored_pv || (ah->alloc == ALLOC_CONTIGUOUS))
can_split = 0; can_split = 0;
if (lv && !list_empty(&lv->segments)) if (lv && !list_empty(&lv->segments))
@@ -906,7 +961,8 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
uint32_t mirrored_pe, uint32_t mirrored_pe,
uint32_t status, uint32_t status,
struct list *allocatable_pvs, struct list *allocatable_pvs,
alloc_policy_t alloc) alloc_policy_t alloc,
struct list *parallel_areas)
{ {
struct alloc_handle *ah; struct alloc_handle *ah;
@@ -929,15 +985,15 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
alloc = vg->alloc; alloc = vg->alloc;
if (!(ah = _alloc_init(vg->cmd->mem, segtype, alloc, mirrors, if (!(ah = _alloc_init(vg->cmd->mem, segtype, alloc, mirrors,
stripes, log_count, mirrored_pv))) { stripes, log_count, mirrored_pv,
mirrored_pe, parallel_areas))) {
stack; stack;
return NULL; return NULL;
} }
if (!segtype_is_virtual(segtype) && if (!segtype_is_virtual(segtype) &&
!_allocate(ah, vg, lv, status, (lv ? lv->le_count : 0) + extents, !_allocate(ah, vg, lv, status, (lv ? lv->le_count : 0) + extents,
allocatable_pvs, allocatable_pvs, stripes, mirrors, segtype)) {
stripes, mirrors, segtype, mirrored_pv, mirrored_pe)) {
stack; stack;
alloc_destroy(ah); alloc_destroy(ah);
return NULL; return NULL;
@@ -1098,8 +1154,7 @@ int lv_add_more_mirrored_areas(struct logical_volume *lv,
return 0; return 0;
} }
list_iterate_items(seg, &lv->segments) seg = first_seg(lv);
break;
old_area_count = seg->area_count; old_area_count = seg->area_count;
new_area_count = old_area_count + num_extra_areas; new_area_count = old_area_count + num_extra_areas;
@@ -1139,7 +1194,7 @@ int lv_extend(struct logical_volume *lv,
if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors, 0, if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors, 0,
extents, mirrored_pv, mirrored_pe, status, extents, mirrored_pv, mirrored_pe, status,
allocatable_pvs, alloc))) { allocatable_pvs, alloc, NULL))) {
stack; stack;
return 0; return 0;
} }
@@ -1272,3 +1327,116 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
return lv; return lv;
} }
/* Recursively process each PV used by part of an LV */
static int _for_each_pv(struct cmd_context *cmd, struct logical_volume *lv,
uint32_t le, uint32_t len,
int (*fn)(struct cmd_context *cmd, struct pv_segment *peg, struct seg_pvs *spvs),
struct seg_pvs *spvs)
{
struct lv_segment *seg;
uint32_t s;
uint32_t remaining_seg_len, area_len, area_multiple;
if (!(seg = find_seg_by_le(lv, le))) {
log_error("Failed to find segment for %s extent %" PRIu32,
lv->name, le);
return 0;
}
/* Remaining logical length of segment */
remaining_seg_len = seg->len - (le - seg->le);
if (len > remaining_seg_len)
remaining_seg_len = len;
if (spvs->len > remaining_seg_len)
spvs->len = remaining_seg_len;
area_multiple = segtype_is_striped(seg->segtype) ? seg->area_count : 1;
area_len = remaining_seg_len / area_multiple;
for (s = 0; s < seg->area_count; s++) {
if (seg_type(seg, s) == AREA_LV) {
if (!_for_each_pv(cmd, seg_lv(seg, s),
seg_le(seg, s) + (le - seg->le) / area_multiple,
area_len, fn, spvs)) {
stack;
return 0;
}
} else if (seg_type(seg, s) == AREA_PV) {
if (!fn(cmd, seg_pvseg(seg, s), spvs)) {
stack;
return 0;
}
}
}
return 1;
}
static int _add_pvs(struct cmd_context *cmd, struct pv_segment *peg, struct seg_pvs *spvs)
{
struct pv_list *pvl;
/* FIXME Don't add again if it's already on the list! */
if (!(pvl = dm_pool_alloc(cmd->mem, sizeof(*pvl)))) {
log_error("pv_list allocation failed");
return 0;
}
pvl->pv = peg->pv;
/* FIXME Use ordered list to facilitate comparison */
list_add(&spvs->pvs, &pvl->list);
/* FIXME Add mirror logs, snapshot cow LVs etc. */
return 1;
}
/*
* Construct list of segments of LVs showing which PVs they use.
*/
struct list *build_parallel_areas_from_lv(struct cmd_context *cmd,
struct logical_volume *lv)
{
struct list *parallel_areas;
struct seg_pvs *spvs;
uint32_t current_le = 0;
if (!(parallel_areas = dm_pool_alloc(cmd->mem, sizeof(*parallel_areas)))) {
log_error("parallel_areas allocation failed");
return NULL;
}
list_init(parallel_areas);
do {
if (!(spvs = dm_pool_zalloc(cmd->mem, sizeof(*spvs)))) {
log_error("allocation failed");
return NULL;
}
list_init(&spvs->pvs);
spvs->le = current_le;
spvs->len = lv->le_count - current_le;
list_add(parallel_areas, &spvs->list);
/* Find next segment end */
/* FIXME Unnecessary nesting! */
if (!_for_each_pv(cmd, lv, current_le, lv->le_count, _add_pvs, spvs)) {
stack;
return NULL;
}
current_le = spvs->le + spvs->len;
} while (current_le < lv->le_count);
/* FIXME Merge adjacent segments with identical PV lists (avoids need for contiguous allocation attempts between successful allocations) */
return parallel_areas;
}

View File

@@ -561,8 +561,14 @@ int create_mirror_layers(struct alloc_handle *ah,
uint32_t status, uint32_t status,
uint32_t region_size, uint32_t region_size,
struct logical_volume *log_lv); struct logical_volume *log_lv);
int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors); int add_mirror_layers(struct alloc_handle *ah,
int remove_all_mirror_images(struct logical_volume *lv); uint32_t num_mirrors,
uint32_t existing_mirrors,
struct logical_volume *lv,
struct segment_type *segtype);
int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
struct list *removable_pvs, int remove_log);
/* /*
* Given mirror image or mirror log segment, find corresponding mirror segment * Given mirror image or mirror log segment, find corresponding mirror segment
*/ */

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved. * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
* *
* This file is part of LVM2. * This file is part of LVM2.
* *
@@ -21,6 +21,7 @@
#include "activate.h" #include "activate.h"
#include "lv_alloc.h" #include "lv_alloc.h"
#include "lvm-string.h" #include "lvm-string.h"
#include "locking.h" /* FIXME Should not be used in this file */
struct lv_segment *find_mirror_seg(struct lv_segment *seg) struct lv_segment *find_mirror_seg(struct lv_segment *seg)
{ {
@@ -62,6 +63,9 @@ static void _move_lv_segments(struct logical_volume *lv_to, struct logical_volum
list_init(&lv_from->segments); list_init(&lv_from->segments);
lv_to->le_count = lv_from->le_count;
lv_to->size = lv_from->size;
lv_from->le_count = 0; lv_from->le_count = 0;
lv_from->size = 0; lv_from->size = 0;
} }
@@ -69,65 +73,163 @@ static void _move_lv_segments(struct logical_volume *lv_to, struct logical_volum
/* /*
* Reduce mirrored_seg to num_mirrors images. * Reduce mirrored_seg to num_mirrors images.
*/ */
int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors) int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
struct list *removable_pvs, int remove_log)
{ {
uint32_t m; uint32_t m;
uint32_t s, s1;
struct logical_volume *sub_lv;
struct logical_volume *log_lv = NULL;
struct logical_volume *lv1 = NULL;
struct physical_volume *pv;
struct lv_segment *seg;
struct lv_segment_area area;
int all_pvs_removable, pv_found;
struct pv_list *pvl;
uint32_t old_area_count = mirrored_seg->area_count;
uint32_t new_area_count = mirrored_seg->area_count;
log_very_verbose("Reducing mirror set from %" PRIu32 " to %"
PRIu32 " image(s)%s.",
old_area_count, num_mirrors,
remove_log ? " and no log volume" : "");
/* Move removable_pvs to end of array */
if (removable_pvs) {
for (s = 0; s < mirrored_seg->area_count; s++) {
all_pvs_removable = 1;
sub_lv = seg_lv(mirrored_seg, s);
list_iterate_items(seg, &sub_lv->segments) {
for (s1 = 0; s1 < seg->area_count; s1++) {
if (seg_type(seg, s1) != AREA_PV)
/* FIXME Recurse for AREA_LV */
continue;
pv = seg_pv(seg, s1);
pv_found = 0;
list_iterate_items(pvl, removable_pvs) {
if (pv->dev->dev == pvl->pv->dev->dev) {
pv_found = 1;
break;
}
}
if (!pv_found) {
all_pvs_removable = 0;
break;
}
}
if (!all_pvs_removable)
break;
}
if (all_pvs_removable) {
/* Swap segment to end */
new_area_count--;
area = mirrored_seg->areas[new_area_count];
mirrored_seg->areas[new_area_count] = mirrored_seg->areas[s];
mirrored_seg->areas[s] = area;
}
/* Found enough matches? */
if (new_area_count == num_mirrors)
break;
}
if (new_area_count == mirrored_seg->area_count) {
log_error("No mirror images found using specified PVs.");
return 0;
}
}
for (m = num_mirrors; m < mirrored_seg->area_count; m++) { for (m = num_mirrors; m < mirrored_seg->area_count; m++) {
seg_lv(mirrored_seg, m)->status &= ~MIRROR_IMAGE;
seg_lv(mirrored_seg, m)->status |= VISIBLE_LV;
}
mirrored_seg->area_count = num_mirrors;
/* If no more mirrors, remove mirror layer */
if (num_mirrors == 1) {
lv1 = seg_lv(mirrored_seg, 0);
_move_lv_segments(mirrored_seg->lv, lv1);
mirrored_seg->lv->status &= ~MIRRORED;
remove_log = 1;
}
if (remove_log) {
log_lv = mirrored_seg->log_lv;
mirrored_seg->log_lv = NULL;
}
/*
* To successfully remove these unwanted LVs we need to
* remove the LVs from the mirror set, commit that metadata
* then deactivate and remove them fully.
*/
/* FIXME lv1 has no segments here so shouldn't be written to disk! */
if (!vg_write(mirrored_seg->lv->vg)) {
log_error("intermediate VG write failed.");
return 0;
}
if (!suspend_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv)) {
log_error("Failed to lock %s", mirrored_seg->lv->name);
vg_revert(mirrored_seg->lv->vg);
return 0;
}
if (!vg_commit(mirrored_seg->lv->vg)) {
resume_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv);
return 0;
}
log_very_verbose("Updating \"%s\" in kernel", mirrored_seg->lv->name);
if (!resume_lv(mirrored_seg->lv->vg->cmd, mirrored_seg->lv)) {
log_error("Problem reactivating %s", mirrored_seg->lv->name);
return 0;
}
/* Delete the 'orphan' LVs */
for (m = num_mirrors; m < old_area_count; m++) {
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, seg_lv(mirrored_seg, m))) {
stack;
return 0;
}
if (!lv_remove(seg_lv(mirrored_seg, m))) { if (!lv_remove(seg_lv(mirrored_seg, m))) {
stack; stack;
return 0; return 0;
} }
} }
mirrored_seg->area_count = num_mirrors; if (lv1) {
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, lv1)) {
stack;
return 0;
}
if (!lv_remove(lv1)) {
stack;
return 0;
}
}
if (log_lv) {
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, log_lv)) {
stack;
return 0;
}
if (!lv_remove(log_lv)) {
stack;
return 0;
}
}
return 1; return 1;
} }
int remove_all_mirror_images(struct logical_volume *lv)
{
struct lv_segment *seg;
struct logical_volume *lv1;
seg = first_seg(lv);
if (!remove_mirror_images(seg, 1)) {
stack;
return 0;
}
if (seg->log_lv && !lv_remove(seg->log_lv)) {
stack;
return 0;
}
lv1 = seg_lv(seg, 0);
_move_lv_segments(lv, lv1);
if (!lv_remove(lv1)) {
stack;
return 0;
}
lv->status &= ~MIRRORED;
return 1;
}
/*
* Add mirror images to an existing mirror
*/
/* FIXME
int add_mirror_images(struct alloc_handle *ah,
uint32_t first_area,
uint32_t num_areas,
struct logical_volume *lv)
{
}
*/
static int _create_layers_for_mirror(struct alloc_handle *ah, static int _create_layers_for_mirror(struct alloc_handle *ah,
uint32_t first_area, uint32_t first_area,
uint32_t num_mirrors, uint32_t num_mirrors,
@@ -161,7 +263,10 @@ static int _create_layers_for_mirror(struct alloc_handle *ah,
return 0; return 0;
} }
if (!lv_add_segment(ah, m, 1, img_lvs[m], if (m < first_area)
continue;
if (!lv_add_segment(ah, m - first_area, 1, img_lvs[m],
get_segtype_from_string(lv->vg->cmd, get_segtype_from_string(lv->vg->cmd,
"striped"), "striped"),
0, NULL, 0, 0, 0, NULL)) { 0, NULL, 0, 0, 0, NULL)) {
@@ -219,6 +324,30 @@ int create_mirror_layers(struct alloc_handle *ah,
return 1; return 1;
} }
int add_mirror_layers(struct alloc_handle *ah,
uint32_t num_mirrors,
uint32_t existing_mirrors,
struct logical_volume *lv,
struct segment_type *segtype)
{
struct logical_volume **img_lvs;
if (!(img_lvs = alloca(sizeof(*img_lvs) * num_mirrors))) {
log_error("img_lvs allocation failed. "
"Remove new LV and retry.");
return 0;
}
if (!_create_layers_for_mirror(ah, 0, num_mirrors,
lv, segtype,
img_lvs)) {
stack;
return 0;
}
return lv_add_more_mirrored_areas(lv, img_lvs, num_mirrors, 0);
}
/* /*
* Replace any LV segments on given PV with temporary mirror. * Replace any LV segments on given PV with temporary mirror.
* Returns list of LVs changed. * Returns list of LVs changed.

View File

@@ -78,6 +78,12 @@ struct segtype_handler {
uint64_t *total_denominator, float *percent); uint64_t *total_denominator, float *percent);
int (*target_present) (void); int (*target_present) (void);
void (*destroy) (const struct segment_type * segtype); void (*destroy) (const struct segment_type * segtype);
int (*target_register_events) (struct dm_pool *mem,
struct lv_segment *seg,
struct config_tree *cft, int events);
int (*target_unregister_events) (struct dm_pool *mem,
struct lv_segment *seg,
struct config_tree *cft, int events);
}; };
struct segment_type *get_segtype_from_string(struct cmd_context *cmd, struct segment_type *get_segtype_from_string(struct cmd_context *cmd,

View File

@@ -25,6 +25,13 @@
#include "lvm-string.h" #include "lvm-string.h"
#include "targets.h" #include "targets.h"
#include "activate.h" #include "activate.h"
#include "sharedlib.h"
#ifdef DMEVENTD
# include <libdevmapper-event.h>
#endif
static int _block_on_error_available = 0;
enum { enum {
MIRR_DISABLED, MIRR_DISABLED,
@@ -221,6 +228,7 @@ static int _add_log(struct dev_manager *dm, struct lv_segment *seg,
{ {
unsigned clustered = 0; unsigned clustered = 0;
char *log_dlid = NULL; char *log_dlid = NULL;
uint32_t log_flags = 0;
/* /*
* Use clustered mirror log for non-exclusive activation * Use clustered mirror log for non-exclusive activation
@@ -237,8 +245,10 @@ static int _add_log(struct dev_manager *dm, struct lv_segment *seg,
return 0; return 0;
} }
/* FIXME Add sync parm? */ if (_block_on_error_available && !(seg->status & PVMOVE))
return dm_tree_node_add_mirror_target_log(node, region_size, clustered, log_dlid, area_count); log_flags |= DM_BLOCK_ON_ERROR;
return dm_tree_node_add_mirror_target_log(node, region_size, clustered, log_dlid, area_count, log_flags);
} }
static int _add_target_line(struct dev_manager *dm, struct dm_pool *mem, static int _add_target_line(struct dev_manager *dm, struct dm_pool *mem,
@@ -316,15 +326,115 @@ static int _target_present(void)
{ {
static int checked = 0; static int checked = 0;
static int present = 0; static int present = 0;
uint32_t maj, min, patchlevel;
unsigned maj2, min2, patchlevel2;
char vsn[80];
if (!checked) if (!checked) {
present = target_present("mirror", 1); present = target_present("mirror", 1);
/*
* block_on_error available with mirror target >= 1.1
* or with 1.0 in RHEL4U3 driver >= 4.5
*/
/* FIXME Move this into libdevmapper */
if (target_version("mirror", &maj, &min, &patchlevel) &&
maj == 1 &&
(min >= 1 ||
(min == 0 && driver_version(vsn, sizeof(vsn)) &&
sscanf(vsn, "%u.%u.%u", &maj2, &min2, &patchlevel2) == 3 &&
maj2 == 4 && min2 == 5 && patchlevel2 == 0))) /* RHEL4U3 */
_block_on_error_available = 1;
}
checked = 1; checked = 1;
return present; return present;
} }
#endif
#ifdef DMEVENTD
static int _setup_registration(struct dm_pool *mem, struct config_tree *cft,
char **dso)
{
char *path;
const char *libpath;
if (!(path = dm_pool_alloc(mem, PATH_MAX))) {
log_error("Failed to allocate dmeventd library path.");
return 0;
}
libpath = find_config_str(cft->root, "dmeventd/mirror_library",
DEFAULT_DMEVENTD_MIRROR_LIB);
get_shared_library_path(cft, libpath, path, PATH_MAX);
*dso = path;
return 1;
}
/* FIXME This gets run while suspended and performs banned operations. */
/* FIXME Merge these two functions */
static int _target_register_events(struct dm_pool *mem,
struct lv_segment *seg,
struct config_tree *cft, int events)
{
char *dso, *name;
struct logical_volume *lv;
struct volume_group *vg;
lv = seg->lv;
vg = lv->vg;
if (!_setup_registration(mem, cft, &dso)) {
stack;
return 0;
}
if (!(name = build_dm_name(mem, vg->name, lv->name, NULL)))
return_0;
/* FIXME Save a returned handle here so we can unregister it later */
if (!dm_event_register(dso, name, DM_EVENT_ALL_ERRORS))
return_0;
log_info("Registered %s for events", name);
return 1;
}
static int _target_unregister_events(struct dm_pool *mem,
struct lv_segment *seg,
struct config_tree *cft, int events)
{
char *dso;
char *name;
struct logical_volume *lv;
struct volume_group *vg;
lv = seg->lv;
vg = lv->vg;
/* FIXME Remove this and use handle to avoid config file race */
if (!_setup_registration(mem, cft, &dso))
return_0;
if (!(name = build_dm_name(mem, vg->name, lv->name, NULL)))
return_0;
/* FIXME Use handle returned by registration function instead of dso */
if (!dm_event_unregister(dso, name, DM_EVENT_ALL_ERRORS))
return_0;
log_info("Unregistered %s for events", name);
return 1;
}
#endif /* DMEVENTD */
#endif /* DEVMAPPER_SUPPORT */
static void _destroy(const struct segment_type *segtype) static void _destroy(const struct segment_type *segtype)
{ {
@@ -341,6 +451,10 @@ static struct segtype_handler _mirrored_ops = {
add_target_line:_add_target_line, add_target_line:_add_target_line,
target_percent:_target_percent, target_percent:_target_percent,
target_present:_target_present, target_present:_target_present,
#ifdef DMEVENTD
target_register_events:_target_register_events,
target_unregister_events:_target_unregister_events,
#endif
#endif #endif
destroy:_destroy, destroy:_destroy,
}; };

View File

@@ -22,8 +22,8 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <dlfcn.h> #include <dlfcn.h>
static void _get_library_path(struct config_tree *cft, const char *libname, void get_shared_library_path(struct config_tree *cft, const char *libname,
char *path, int path_len) char *path, int path_len)
{ {
struct stat info; struct stat info;
const char *lib_dir; const char *lib_dir;
@@ -43,7 +43,7 @@ void *load_shared_library(struct config_tree *cft, const char *libname,
char path[PATH_MAX]; char path[PATH_MAX];
void *library; void *library;
_get_library_path(cft, libname, path, sizeof(path)); get_shared_library_path(cft, libname, path, sizeof(path));
log_very_verbose("Opening shared %s library %s", desc, path); log_very_verbose("Opening shared %s library %s", desc, path);

View File

@@ -16,5 +16,7 @@
#include "config.h" #include "config.h"
#include <dlfcn.h> #include <dlfcn.h>
void get_shared_library_path(struct config_tree *cft, const char *libname,
char *path, int path_len);
void *load_shared_library(struct config_tree *cf, const char *libname, void *load_shared_library(struct config_tree *cf, const char *libname,
const char *what); const char *what);

View File

@@ -2,6 +2,7 @@ dm_lib_release
dm_lib_exit dm_lib_exit
dm_driver_version dm_driver_version
dm_get_library_version dm_get_library_version
dm_log
dm_log_init dm_log_init
dm_log_init_verbose dm_log_init_verbose
dm_task_create dm_task_create
@@ -22,10 +23,14 @@ dm_task_set_major
dm_task_set_minor dm_task_set_minor
dm_task_set_sector dm_task_set_sector
dm_task_set_message dm_task_set_message
dm_task_set_uid
dm_task_set_gid
dm_task_set_mode
dm_task_suppress_identical_reload dm_task_suppress_identical_reload
dm_task_add_target dm_task_add_target
dm_task_no_open_count dm_task_no_open_count
dm_task_skip_lockfs dm_task_skip_lockfs
dm_task_update_nodes
dm_task_run dm_task_run
dm_get_next_target dm_get_next_target
dm_set_dev_dir dm_set_dev_dir
@@ -59,11 +64,12 @@ dm_tree_node_add_striped_target
dm_tree_node_add_mirror_target dm_tree_node_add_mirror_target
dm_tree_node_add_mirror_target_log dm_tree_node_add_mirror_target_log
dm_tree_node_add_target_area dm_tree_node_add_target_area
dm_tree_skip_lockfs
dm_is_dm_major dm_is_dm_major
dm_mknodes dm_mknodes
dm_malloc_aux dm_malloc_aux
dm_malloc_aux_debug dm_malloc_aux_debug
dm_strdup dm_strdup_aux
dm_free_aux dm_free_aux
dm_realloc_aux dm_realloc_aux
dm_dump_memory_debug dm_dump_memory_debug
@@ -102,3 +108,4 @@ dm_hash_get_data
dm_hash_get_first dm_hash_get_first
dm_hash_get_next dm_hash_get_next
dm_set_selinux_context dm_set_selinux_context
dm_task_set_geometry

View File

@@ -17,14 +17,6 @@ top_srcdir = @top_srcdir@
VPATH = @srcdir@ VPATH = @srcdir@
interface = @interface@ interface = @interface@
ifeq ("@DMEVENTD@", "yes")
SUBDIRS += event
endif
ifeq ($(MAKECMDGOALS),distclean)
SUBDIRS += event
endif
SOURCES =\ SOURCES =\
datastruct/bitset.c \ datastruct/bitset.c \
datastruct/hash.c \ datastruct/hash.c \

View File

@@ -57,7 +57,7 @@ void dm_bit_union(dm_bitset_t out, dm_bitset_t in1, dm_bitset_t in2)
*/ */
static inline int _test_word(uint32_t test, int bit) static inline int _test_word(uint32_t test, int bit)
{ {
while (bit < DM_BITS_PER_INT) { while (bit < (int) DM_BITS_PER_INT) {
if (test & (0x1 << bit)) if (test & (0x1 << bit))
return bit; return bit;
bit++; bit++;
@@ -73,7 +73,10 @@ int dm_bit_get_next(dm_bitset_t bs, int last_bit)
last_bit++; /* otherwise we'll return the same bit again */ last_bit++; /* otherwise we'll return the same bit again */
while (last_bit < bs[0]) { /*
* bs[0] holds number of bits
*/
while (last_bit < (int) bs[0]) {
word = last_bit >> INT_SHIFT; word = last_bit >> INT_SHIFT;
test = bs[word + 1]; test = bs[word + 1];
bit = last_bit & (DM_BITS_PER_INT - 1); bit = last_bit & (DM_BITS_PER_INT - 1);

View File

@@ -18,13 +18,13 @@
struct dm_hash_node { struct dm_hash_node {
struct dm_hash_node *next; struct dm_hash_node *next;
void *data; void *data;
int keylen; unsigned keylen;
char key[0]; char key[0];
}; };
struct dm_hash_table { struct dm_hash_table {
int num_nodes; unsigned num_nodes;
int num_slots; unsigned num_slots;
struct dm_hash_node **slots; struct dm_hash_node **slots;
}; };
@@ -56,7 +56,7 @@ static unsigned char _nums[] = {
209 209
}; };
static struct dm_hash_node *_create_node(const char *str, int len) static struct dm_hash_node *_create_node(const char *str, unsigned len)
{ {
struct dm_hash_node *n = dm_malloc(sizeof(*n) + len); struct dm_hash_node *n = dm_malloc(sizeof(*n) + len);
@@ -68,13 +68,14 @@ static struct dm_hash_node *_create_node(const char *str, int len)
return n; return n;
} }
static unsigned _hash(const char *str, uint32_t len) static unsigned long _hash(const unsigned char *str, unsigned len)
{ {
unsigned long h = 0, g, i; unsigned long h = 0, g;
unsigned i;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
h <<= 4; h <<= 4;
h += _nums[(int) *str++]; h += _nums[*str++];
g = h & ((unsigned long) 0xf << 16u); g = h & ((unsigned long) 0xf << 16u);
if (g) { if (g) {
h ^= g >> 16u; h ^= g >> 16u;
@@ -120,7 +121,7 @@ struct dm_hash_table *dm_hash_create(unsigned size_hint)
static void _free_nodes(struct dm_hash_table *t) static void _free_nodes(struct dm_hash_table *t)
{ {
struct dm_hash_node *c, *n; struct dm_hash_node *c, *n;
int i; unsigned i;
for (i = 0; i < t->num_slots; i++) for (i = 0; i < t->num_slots; i++)
for (c = t->slots[i]; c; c = n) { for (c = t->slots[i]; c; c = n) {
@@ -136,8 +137,8 @@ void dm_hash_destroy(struct dm_hash_table *t)
dm_free(t); dm_free(t);
} }
static inline struct dm_hash_node **_find(struct dm_hash_table *t, const char *key, static struct dm_hash_node **_find(struct dm_hash_table *t, const char *key,
uint32_t len) uint32_t len)
{ {
unsigned h = _hash(key, len) & (t->num_slots - 1); unsigned h = _hash(key, len) & (t->num_slots - 1);
struct dm_hash_node **c; struct dm_hash_node **c;
@@ -153,11 +154,12 @@ void *dm_hash_lookup_binary(struct dm_hash_table *t, const char *key,
uint32_t len) uint32_t len)
{ {
struct dm_hash_node **c = _find(t, key, len); struct dm_hash_node **c = _find(t, key, len);
return *c ? (*c)->data : 0; return *c ? (*c)->data : 0;
} }
int dm_hash_insert_binary(struct dm_hash_table *t, const char *key, int dm_hash_insert_binary(struct dm_hash_table *t, const char *key,
uint32_t len, void *data) uint32_t len, void *data)
{ {
struct dm_hash_node **c = _find(t, key, len); struct dm_hash_node **c = _find(t, key, len);
@@ -214,7 +216,7 @@ unsigned dm_hash_get_num_entries(struct dm_hash_table *t)
void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f) void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f)
{ {
struct dm_hash_node *c; struct dm_hash_node *c;
int i; unsigned i;
for (i = 0; i < t->num_slots; i++) for (i = 0; i < t->num_slots; i++)
for (c = t->slots[i]; c; c = c->next) for (c = t->slots[i]; c; c = c->next)
@@ -225,7 +227,7 @@ void dm_hash_wipe(struct dm_hash_table *t)
{ {
_free_nodes(t); _free_nodes(t);
memset(t->slots, 0, sizeof(struct dm_hash_node *) * t->num_slots); memset(t->slots, 0, sizeof(struct dm_hash_node *) * t->num_slots);
t->num_nodes = 0; t->num_nodes = 0u;
} }
char *dm_hash_get_key(struct dm_hash_table *t, struct dm_hash_node *n) char *dm_hash_get_key(struct dm_hash_table *t, struct dm_hash_node *n)
@@ -241,7 +243,7 @@ void *dm_hash_get_data(struct dm_hash_table *t, struct dm_hash_node *n)
static struct dm_hash_node *_next_slot(struct dm_hash_table *t, unsigned s) static struct dm_hash_node *_next_slot(struct dm_hash_table *t, unsigned s)
{ {
struct dm_hash_node *c = NULL; struct dm_hash_node *c = NULL;
int i; unsigned i;
for (i = s; i < t->num_slots && !c; i++) for (i = s; i < t->num_slots && !c; i++)
c = t->slots[i]; c = t->slots[i];
@@ -257,5 +259,6 @@ struct dm_hash_node *dm_hash_get_first(struct dm_hash_table *t)
struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_node *n) struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_node *n)
{ {
unsigned h = _hash(n->key, n->keylen) & (t->num_slots - 1); unsigned h = _hash(n->key, n->keylen) & (t->num_slots - 1);
return n->next ? n->next : _next_slot(t, h + 1); return n->next ? n->next : _next_slot(t, h + 1);
} }

View File

@@ -116,6 +116,7 @@ static struct cmd_data _cmd_data_v1[] = {
{ "mknodes", 0, {4, 0, 0} }, { "mknodes", 0, {4, 0, 0} },
{ "versions", 0, {4, 1, 0} }, { "versions", 0, {4, 1, 0} },
{ "message", 0, {4, 2, 0} }, { "message", 0, {4, 2, 0} },
{ "setgeometry",0, {4, 6, 0} },
}; };
/* *INDENT-ON* */ /* *INDENT-ON* */

View File

@@ -103,6 +103,9 @@ static struct cmd_data _cmd_data_v4[] = {
#ifdef DM_TARGET_MSG #ifdef DM_TARGET_MSG
{"message", DM_TARGET_MSG, {4, 2, 0}}, {"message", DM_TARGET_MSG, {4, 2, 0}},
#endif #endif
#ifdef DM_DEV_SET_GEOMETRY
{"setgeometry", DM_DEV_SET_GEOMETRY, {4, 6, 0}},
#endif
}; };
/* *INDENT-ON* */ /* *INDENT-ON* */
@@ -672,11 +675,13 @@ static int _dm_task_run_v1(struct dm_task *dmt)
#ifdef DM_IOCTLS #ifdef DM_IOCTLS
else if (ioctl(_control_fd, command, dmi) < 0) { else if (ioctl(_control_fd, command, dmi) < 0) {
if (_log_suppress) if (_log_suppress)
log_verbose("device-mapper ioctl cmd %d failed: %s", log_verbose("device-mapper: %s ioctl failed: %s",
_IOC_NR(command), strerror(errno)); _cmd_data_v1[dmt->type].name,
strerror(errno));
else else
log_error("device-mapper ioctl cmd %d failed: %s", log_error("device-mapper: %s ioctl failed: %s",
_IOC_NR(command), strerror(errno)); _cmd_data_v1[dmt->type].name,
strerror(errno));
goto bad; goto bad;
} }
#else /* Userspace alternative for testing */ #else /* Userspace alternative for testing */
@@ -875,7 +880,7 @@ int dm_format_dev(char *buf, int bufsize, uint32_t dev_major,
if (bufsize < 8) if (bufsize < 8)
return 0; return 0;
r = snprintf(buf, bufsize, "%u:%u", dev_major, dev_minor); r = snprintf(buf, (size_t) bufsize, "%u:%u", dev_major, dev_minor);
if (r < 0 || r > bufsize - 1) if (r < 0 || r > bufsize - 1)
return 0; return 0;
@@ -999,6 +1004,23 @@ int dm_task_set_sector(struct dm_task *dmt, uint64_t sector)
return 1; return 1;
} }
int dm_task_set_geometry(struct dm_task *dmt, const char *cylinders, const char *heads, const char *sectors, const char *start)
{
size_t len = strlen(cylinders) + 1 + strlen(heads) + 1 + strlen(sectors) + 1 + strlen(start) + 1;
if (!(dmt->geometry = dm_malloc(len))) {
log_error("dm_task_set_geometry: dm_malloc failed");
return 0;
}
if (sprintf(dmt->geometry, "%s %s %s %s", cylinders, heads, sectors, start) < 0) {
log_error("dm_task_set_geometry: sprintf failed");
return 0;
}
return 1;
}
int dm_task_no_open_count(struct dm_task *dmt) int dm_task_no_open_count(struct dm_task *dmt)
{ {
dmt->no_open_count = 1; dmt->no_open_count = 1;
@@ -1026,7 +1048,8 @@ struct target *create_target(uint64_t start, uint64_t len, const char *type,
struct target *t = dm_malloc(sizeof(*t)); struct target *t = dm_malloc(sizeof(*t));
if (!t) { if (!t) {
log_error("create_target: malloc(%d) failed", sizeof(*t)); log_error("create_target: malloc(%" PRIsize_t ") failed",
sizeof(*t));
return NULL; return NULL;
} }
@@ -1120,11 +1143,26 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
return NULL; return NULL;
} }
if (count && dmt->geometry) {
log_error("targets and geometry are incompatible");
return NULL;
}
if (dmt->newname && (dmt->sector || dmt->message)) { if (dmt->newname && (dmt->sector || dmt->message)) {
log_error("message and newname are incompatible"); log_error("message and newname are incompatible");
return NULL; return NULL;
} }
if (dmt->newname && dmt->geometry) {
log_error("geometry and newname are incompatible");
return NULL;
}
if (dmt->geometry && (dmt->sector || dmt->message)) {
log_error("geometry and message are incompatible");
return NULL;
}
if (dmt->sector && !dmt->message) { if (dmt->sector && !dmt->message) {
log_error("message is required with sector"); log_error("message is required with sector");
return NULL; return NULL;
@@ -1136,6 +1174,9 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
if (dmt->message) if (dmt->message)
len += sizeof(struct dm_target_msg) + strlen(dmt->message) + 1; len += sizeof(struct dm_target_msg) + strlen(dmt->message) + 1;
if (dmt->geometry)
len += strlen(dmt->geometry) + 1;
/* /*
* Give len a minimum size so that we have space to store * Give len a minimum size so that we have space to store
* dependencies or status information. * dependencies or status information.
@@ -1202,6 +1243,9 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
strcpy(tmsg->message, dmt->message); strcpy(tmsg->message, dmt->message);
} }
if (dmt->geometry)
strcpy(b, dmt->geometry);
return dmi; return dmi;
bad: bad:
@@ -1308,6 +1352,9 @@ static int _create_and_load_v4(struct dm_task *dmt)
task->major = dmt->major; task->major = dmt->major;
task->minor = dmt->minor; task->minor = dmt->minor;
task->uid = dmt->uid;
task->gid = dmt->gid;
task->mode = dmt->mode;
r = dm_task_run(task); r = dm_task_run(task);
dm_task_destroy(task); dm_task_destroy(task);
@@ -1432,7 +1479,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
if (dmt->no_open_count) if (dmt->no_open_count)
dmi->flags |= DM_SKIP_BDGET_FLAG; dmi->flags |= DM_SKIP_BDGET_FLAG;
log_debug("dm %s %s %s%s%s %s%0.0d%s%0.0d%s" log_debug("dm %s %s %s%s%s %s%.0d%s%.0d%s"
"%s%c %.0llu %s [%u]", "%s%c %.0llu %s [%u]",
_cmd_data_v4[dmt->type].name, _cmd_data_v4[dmt->type].name,
dmi->name, dmi->uuid, dmt->newname ? " " : "", dmi->name, dmi->uuid, dmt->newname ? " " : "",
@@ -1454,13 +1501,15 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
dmi->flags &= ~DM_EXISTS_FLAG; /* FIXME */ dmi->flags &= ~DM_EXISTS_FLAG; /* FIXME */
else { else {
if (_log_suppress) if (_log_suppress)
log_verbose("device-mapper ioctl " log_verbose("device-mapper: %s ioctl "
"cmd %d failed: %s", "failed: %s",
_IOC_NR(command), strerror(errno)); _cmd_data_v4[dmt->type].name,
strerror(errno));
else else
log_error("device-mapper ioctl " log_error("device-mapper: %s ioctl "
"cmd %d failed: %s", "failed: %s",
_IOC_NR(command), strerror(errno)); _cmd_data_v4[dmt->type].name,
strerror(errno));
dm_free(dmi); dm_free(dmi);
return NULL; return NULL;
} }
@@ -1470,6 +1519,11 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
return dmi; return dmi;
} }
void dm_task_update_nodes(void)
{
update_devs();
}
int dm_task_run(struct dm_task *dmt) int dm_task_run(struct dm_task *dmt)
{ {
struct dm_ioctl *dmi; struct dm_ioctl *dmi;

View File

@@ -50,6 +50,7 @@ struct dm_task {
} dmi; } dmi;
char *newname; char *newname;
char *message; char *message;
char *geometry;
uint64_t sector; uint64_t sector;
int no_open_count; int no_open_count;
int skip_lockfs; int skip_lockfs;

View File

@@ -42,7 +42,8 @@
*/ */
typedef void (*dm_log_fn) (int level, const char *file, int line, typedef void (*dm_log_fn) (int level, const char *file, int line,
const char *f, ...); const char *f, ...)
__attribute__ ((format(printf, 4, 5)));
/* /*
* The library user may wish to register their own * The library user may wish to register their own
@@ -79,7 +80,9 @@ enum {
DM_DEVICE_LIST_VERSIONS, DM_DEVICE_LIST_VERSIONS,
DM_DEVICE_TARGET_MSG DM_DEVICE_TARGET_MSG,
DM_DEVICE_SET_GEOMETRY
}; };
struct dm_task; struct dm_task;
@@ -140,7 +143,11 @@ int dm_task_set_ro(struct dm_task *dmt);
int dm_task_set_newname(struct dm_task *dmt, const char *newname); int dm_task_set_newname(struct dm_task *dmt, const char *newname);
int dm_task_set_minor(struct dm_task *dmt, int minor); int dm_task_set_minor(struct dm_task *dmt, int minor);
int dm_task_set_major(struct dm_task *dmt, int major); int dm_task_set_major(struct dm_task *dmt, int major);
int dm_task_set_uid(struct dm_task *dmt, uid_t uid);
int dm_task_set_gid(struct dm_task *dmt, gid_t gid);
int dm_task_set_mode(struct dm_task *dmt, mode_t mode);
int dm_task_set_event_nr(struct dm_task *dmt, uint32_t event_nr); int dm_task_set_event_nr(struct dm_task *dmt, uint32_t event_nr);
int dm_task_set_geometry(struct dm_task *dmt, const char *cylinders, const char *heads, const char *sectors, const char *start);
int dm_task_set_message(struct dm_task *dmt, const char *message); int dm_task_set_message(struct dm_task *dmt, const char *message);
int dm_task_set_sector(struct dm_task *dmt, uint64_t sector); int dm_task_set_sector(struct dm_task *dmt, uint64_t sector);
int dm_task_no_open_count(struct dm_task *dmt); int dm_task_no_open_count(struct dm_task *dmt);
@@ -169,6 +176,12 @@ void *dm_get_next_target(struct dm_task *dmt,
*/ */
int dm_task_run(struct dm_task *dmt); int dm_task_run(struct dm_task *dmt);
/*
* Call this to make or remove the device nodes associated with previously
* issued commands.
*/
void dm_task_update_nodes(void);
/* /*
* Configure the device-mapper directory * Configure the device-mapper directory
*/ */
@@ -293,6 +306,13 @@ int dm_tree_suspend_children(struct dm_tree_node *dnode,
const char *uuid_prefix, const char *uuid_prefix,
size_t uuid_prefix_len); size_t uuid_prefix_len);
/*
* Skip the filesystem sync when suspending.
* Does nothing with other functions.
* Use this when no snapshots are involved.
*/
void dm_tree_skip_lockfs(struct dm_tree_node *dnode);
/* /*
* Is the uuid prefix present in the tree? * Is the uuid prefix present in the tree?
* Only returns 0 if every node was checked successfully. * Only returns 0 if every node was checked successfully.
@@ -325,11 +345,18 @@ int dm_tree_node_add_striped_target(struct dm_tree_node *node,
uint32_t stripe_size); uint32_t stripe_size);
int dm_tree_node_add_mirror_target(struct dm_tree_node *node, int dm_tree_node_add_mirror_target(struct dm_tree_node *node,
uint64_t size); uint64_t size);
/* Mirror log flags */
#define DM_NOSYNC 0x00000001 /* Known already in sync */
#define DM_FORCESYNC 0x00000002 /* Force resync */
#define DM_BLOCK_ON_ERROR 0x00000004 /* On error, suspend I/O */
int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node, int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node,
uint32_t region_size, uint32_t region_size,
unsigned clustered, unsigned clustered,
const char *log_uuid, const char *log_uuid,
unsigned area_count); unsigned area_count,
uint32_t flags);
int dm_tree_node_add_target_area(struct dm_tree_node *node, int dm_tree_node_add_target_area(struct dm_tree_node *node,
const char *dev_name, const char *dev_name,
const char *dlid, const char *dlid,
@@ -343,10 +370,9 @@ int dm_tree_node_add_target_area(struct dm_tree_node *node,
* Memory management * Memory management
*******************/ *******************/
char *dm_strdup(const char *str);
void *dm_malloc_aux(size_t s, const char *file, int line); void *dm_malloc_aux(size_t s, const char *file, int line);
void *dm_malloc_aux_debug(size_t s, const char *file, int line); void *dm_malloc_aux_debug(size_t s, const char *file, int line);
char *dm_strdup_aux(const char *str);
void dm_free_aux(void *p); void dm_free_aux(void *p);
void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line); void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line);
int dm_dump_memory_debug(void); int dm_dump_memory_debug(void);
@@ -355,6 +381,7 @@ void dm_bounds_check_debug(void);
#ifdef DEBUG_MEM #ifdef DEBUG_MEM
# define dm_malloc(s) dm_malloc_aux_debug((s), __FILE__, __LINE__) # define dm_malloc(s) dm_malloc_aux_debug((s), __FILE__, __LINE__)
# define dm_strdup(s) dm_strdup_aux(s)
# define dm_free(p) dm_free_aux(p) # define dm_free(p) dm_free_aux(p)
# define dm_realloc(p, s) dm_realloc_aux(p, s, __FILE__, __LINE__) # define dm_realloc(p, s) dm_realloc_aux(p, s, __FILE__, __LINE__)
# define dm_dump_memory() dm_dump_memory_debug() # define dm_dump_memory() dm_dump_memory_debug()
@@ -363,6 +390,7 @@ void dm_bounds_check_debug(void);
#else #else
# define dm_malloc(s) dm_malloc_aux((s), __FILE__, __LINE__) # define dm_malloc(s) dm_malloc_aux((s), __FILE__, __LINE__)
# define dm_strdup(s) strdup(s)
# define dm_free(p) free(p) # define dm_free(p) free(p)
# define dm_realloc(p, s) realloc(p, s) # define dm_realloc(p, s) realloc(p, s)
# define dm_dump_memory() {} # define dm_dump_memory() {}
@@ -503,6 +531,17 @@ int dm_bit_get_next(dm_bitset_t bs, int last_bit);
#define dm_bit_copy(bs1, bs2) \ #define dm_bit_copy(bs1, bs2) \
memcpy(bs1 + 1, bs2 + 1, ((*bs1 / DM_BITS_PER_INT) + 1) * sizeof(int)) memcpy(bs1 + 1, bs2 + 1, ((*bs1 / DM_BITS_PER_INT) + 1) * sizeof(int))
/* Returns number of set bits */
static inline unsigned hweight32(uint32_t i)
{
unsigned r = (i & 0x55555555) + ((i >> 1) & 0x55555555);
r = (r & 0x33333333) + ((r >> 2) & 0x33333333);
r = (r & 0x0F0F0F0F) + ((r >> 4) & 0x0F0F0F0F);
r = (r & 0x00FF00FF) + ((r >> 8) & 0x00FF00FF);
return (r & 0x0000FFFF) + ((r >> 16) & 0x0000FFFF);
}
/**************** /****************
* hash functions * hash functions
****************/ ****************/
@@ -537,9 +576,9 @@ struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_no
for (v = dm_hash_get_first(h); v; \ for (v = dm_hash_get_first(h); v; \
v = dm_hash_get_next(h, v)) v = dm_hash_get_next(h, v))
#endif /* LIB_DEVICE_MAPPER_H */
/********* /*********
* selinux * selinux
*********/ *********/
int dm_set_selinux_context(const char *path, mode_t mode); int dm_set_selinux_context(const char *path, mode_t mode);
#endif /* LIB_DEVICE_MAPPER_H */

View File

@@ -61,14 +61,14 @@ static void _default_log(int level, const char *file, int line,
fprintf(stdout, "\n"); fprintf(stdout, "\n");
} }
dm_log_fn _log = _default_log; dm_log_fn dm_log = _default_log;
void dm_log_init(dm_log_fn fn) void dm_log_init(dm_log_fn fn)
{ {
if (fn) if (fn)
_log = fn; dm_log = fn;
else else
_log = _default_log; dm_log = _default_log;
} }
void dm_log_init_verbose(int level) void dm_log_init_verbose(int level)
@@ -96,7 +96,8 @@ struct dm_task *dm_task_create(int type)
struct dm_task *dmt = dm_malloc(sizeof(*dmt)); struct dm_task *dmt = dm_malloc(sizeof(*dmt));
if (!dmt) { if (!dmt) {
log_error("dm_task_create: malloc(%d) failed", sizeof(*dmt)); log_error("dm_task_create: malloc(%" PRIsize_t ") failed",
sizeof(*dmt));
return NULL; return NULL;
} }
@@ -180,6 +181,27 @@ int dm_task_set_minor(struct dm_task *dmt, int minor)
return 1; return 1;
} }
int dm_task_set_uid(struct dm_task *dmt, uid_t uid)
{
dmt->uid = uid;
return 1;
}
int dm_task_set_gid(struct dm_task *dmt, gid_t gid)
{
dmt->gid = gid;
return 1;
}
int dm_task_set_mode(struct dm_task *dmt, mode_t mode)
{
dmt->mode = mode;
return 1;
}
int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size, int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size,
const char *ttype, const char *params) const char *ttype, const char *params)
{ {
@@ -488,3 +510,4 @@ out:
dm_task_destroy(dmt); dm_task_destroy(dmt);
return r; return r;
} }

View File

@@ -85,6 +85,8 @@ struct load_segment {
uint32_t region_size; /* Mirror */ uint32_t region_size; /* Mirror */
unsigned clustered; /* Mirror */ unsigned clustered; /* Mirror */
unsigned mirror_area_count; /* Mirror */ unsigned mirror_area_count; /* Mirror */
uint32_t flags; /* Mirror log */
char *uuid; /* Clustered mirror log */
}; };
/* Per-device properties */ /* Per-device properties */
@@ -127,6 +129,7 @@ struct dm_tree {
struct dm_hash_table *devs; struct dm_hash_table *devs;
struct dm_hash_table *uuids; struct dm_hash_table *uuids;
struct dm_tree_node root; struct dm_tree_node root;
int skip_lockfs; /* 1 skips lockfs (for non-snapshots) */
}; };
/* FIXME Consider exporting this */ /* FIXME Consider exporting this */
@@ -139,7 +142,7 @@ static int _dm_snprintf(char *buf, size_t bufsize, const char *format, ...)
n = vsnprintf(buf, bufsize, format, ap); n = vsnprintf(buf, bufsize, format, ap);
va_end(ap); va_end(ap);
if (n < 0 || (n > bufsize - 1)) if (n < 0 || (n > (int) bufsize - 1))
return -1; return -1;
return n; return n;
@@ -158,6 +161,7 @@ struct dm_tree *dm_tree_create(void)
dtree->root.dtree = dtree; dtree->root.dtree = dtree;
list_init(&dtree->root.uses); list_init(&dtree->root.uses);
list_init(&dtree->root.used_by); list_init(&dtree->root.used_by);
dtree->skip_lockfs = 0;
if (!(dtree->mem = dm_pool_create("dtree", 1024))) { if (!(dtree->mem = dm_pool_create("dtree", 1024))) {
log_error("dtree pool creation failed"); log_error("dtree pool creation failed");
@@ -899,12 +903,13 @@ static int _resume_node(const char *name, uint32_t major, uint32_t minor,
} }
static int _suspend_node(const char *name, uint32_t major, uint32_t minor, static int _suspend_node(const char *name, uint32_t major, uint32_t minor,
struct dm_info *newinfo) int skip_lockfs, struct dm_info *newinfo)
{ {
struct dm_task *dmt; struct dm_task *dmt;
int r; int r;
log_verbose("Suspending %s (%" PRIu32 ":%" PRIu32 ")", name, major, minor); log_verbose("Suspending %s (%" PRIu32 ":%" PRIu32 ")%s", name, major,
minor, skip_lockfs ? "" : " with filesystem sync.");
if (!(dmt = dm_task_create(DM_DEVICE_SUSPEND))) { if (!(dmt = dm_task_create(DM_DEVICE_SUSPEND))) {
log_error("Suspend dm_task creation failed for %s", name); log_error("Suspend dm_task creation failed for %s", name);
@@ -920,6 +925,9 @@ static int _suspend_node(const char *name, uint32_t major, uint32_t minor,
if (!dm_task_no_open_count(dmt)) if (!dm_task_no_open_count(dmt))
log_error("Failed to disable open_count"); log_error("Failed to disable open_count");
if (skip_lockfs && !dm_task_skip_lockfs(dmt))
log_error("Failed to set skip_lockfs flag.");
if ((r = dm_task_run(dmt))) if ((r = dm_task_run(dmt)))
r = dm_task_get_info(dmt, newinfo); r = dm_task_get_info(dmt, newinfo);
@@ -978,6 +986,11 @@ int dm_tree_deactivate_children(struct dm_tree_node *dnode,
return 1; return 1;
} }
void dm_tree_skip_lockfs(struct dm_tree_node *dnode)
{
dnode->dtree->skip_lockfs = 1;
}
int dm_tree_suspend_children(struct dm_tree_node *dnode, int dm_tree_suspend_children(struct dm_tree_node *dnode,
const char *uuid_prefix, const char *uuid_prefix,
size_t uuid_prefix_len) size_t uuid_prefix_len)
@@ -1018,7 +1031,8 @@ int dm_tree_suspend_children(struct dm_tree_node *dnode,
!info.exists) !info.exists)
continue; continue;
if (!_suspend_node(name, info.major, info.minor, &newinfo)) { if (!_suspend_node(name, info.major, info.minor,
child->dtree->skip_lockfs, &newinfo)) {
log_error("Unable to suspend %s (%" PRIu32 log_error("Unable to suspend %s (%" PRIu32
":%" PRIu32 ")", name, info.major, ":%" PRIu32 ")", name, info.major,
info.minor); info.minor);
@@ -1211,10 +1225,12 @@ static int _emit_areas_line(struct dm_task *dmt, struct load_segment *seg, char
static int _emit_segment_line(struct dm_task *dmt, struct load_segment *seg, uint64_t *seg_start, char *params, size_t paramsize) static int _emit_segment_line(struct dm_task *dmt, struct load_segment *seg, uint64_t *seg_start, char *params, size_t paramsize)
{ {
unsigned log_parm_count;
int pos = 0; int pos = 0;
int tw; int tw;
int r; int r;
char originbuf[10], cowbuf[10], logbuf[10]; char originbuf[10], cowbuf[10], logbuf[10];
const char *logtype;
switch(seg->type) { switch(seg->type) {
case SEG_ERROR: case SEG_ERROR:
@@ -1223,33 +1239,84 @@ static int _emit_segment_line(struct dm_task *dmt, struct load_segment *seg, uin
case SEG_LINEAR: case SEG_LINEAR:
break; break;
case SEG_MIRRORED: case SEG_MIRRORED:
log_parm_count = 1; /* Region size */
log_parm_count += hweight32(seg->flags); /* [no]sync, block_on_error etc. */
if (seg->clustered) { if (seg->clustered) {
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "clustered ")) < 0) { if (seg->uuid)
log_parm_count++; /* uuid */
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "clustered_")) < 0) {
stack; /* Out of space */ stack; /* Out of space */
return -1; return -1;
} }
pos += tw; pos += tw;
} }
if (!seg->log) {
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "core 1 ")) < 0) { if (!seg->log)
stack; /* Out of space */ logtype = "core";
return -1; else {
} logtype = "disk";
pos += tw; log_parm_count++;
} else {
if (!_build_dev_string(logbuf, sizeof(logbuf), seg->log)) if (!_build_dev_string(logbuf, sizeof(logbuf), seg->log))
return_0; return_0;
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "disk 2 %s ", logbuf)) < 0) { }
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "%s %u ", logtype, log_parm_count)) < 0) {
stack; /* Out of space */
return -1;
}
pos += tw;
if (seg->log) {
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "%s ", logbuf)) < 0) {
stack; /* Out of space */ stack; /* Out of space */
return -1; return -1;
} }
pos += tw; pos += tw;
} }
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "%u %u ", seg->region_size, seg->mirror_area_count)) < 0) {
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "%u ", seg->region_size)) < 0) {
stack; /* Out of space */ stack; /* Out of space */
return -1; return -1;
} }
pos += tw; pos += tw;
if (seg->clustered && seg->uuid) {
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "%s ", seg->uuid)) < 0) {
stack; /* Out of space */
return -1;
}
pos += tw;
}
if ((seg->flags & DM_NOSYNC)) {
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "nosync ")) < 0) {
stack; /* Out of space */
return -1;
}
pos += tw;
} else if ((seg->flags & DM_FORCESYNC)) {
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "sync ")) < 0) {
stack; /* Out of space */
return -1;
}
pos += tw;
}
if ((seg->flags & DM_BLOCK_ON_ERROR)) {
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "block_on_error ")) < 0) {
stack; /* Out of space */
return -1;
}
pos += tw;
}
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "%u ", seg->mirror_area_count)) < 0) {
stack; /* Out of space */
return -1;
}
pos += tw;
break; break;
case SEG_SNAPSHOT: case SEG_SNAPSHOT:
if (!_build_dev_string(originbuf, sizeof(originbuf), seg->origin)) if (!_build_dev_string(originbuf, sizeof(originbuf), seg->origin))
@@ -1620,7 +1687,8 @@ int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node,
uint32_t region_size, uint32_t region_size,
unsigned clustered, unsigned clustered,
const char *log_uuid, const char *log_uuid,
unsigned area_count) unsigned area_count,
uint32_t flags)
{ {
struct dm_tree_node *log_node = NULL; struct dm_tree_node *log_node = NULL;
struct load_segment *seg; struct load_segment *seg;
@@ -1637,14 +1705,21 @@ int dm_tree_node_add_mirror_target_log(struct dm_tree_node *node,
log_error("Couldn't find mirror log uuid %s.", log_uuid); log_error("Couldn't find mirror log uuid %s.", log_uuid);
return 0; return 0;
} }
if (!_link_tree_nodes(node, log_node)) if (!_link_tree_nodes(node, log_node))
return_0; return_0;
if (!(seg->uuid = dm_pool_strdup(node->dtree->mem, log_uuid))) {
log_error("log uuid pool_strdup failed");
return 0;
}
} }
seg->log = log_node; seg->log = log_node;
seg->region_size = region_size; seg->region_size = region_size;
seg->clustered = clustered; seg->clustered = clustered;
seg->mirror_area_count = area_count; seg->mirror_area_count = area_count;
seg->flags = flags;
return 1; return 1;
} }

View File

@@ -1,95 +0,0 @@
/*
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* 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
*/
#ifndef LIB_DMEVENT_H
#define LIB_DMEVENT_H
#include "list.h"
#include <stdint.h>
#define DAEMON "/sbin/dmeventd"
#define LOCKFILE "/var/lock/dmeventd"
#define FIFO_CLIENT "/var/run/dmeventd-client"
#define FIFO_SERVER "/var/run/dmeventd-server"
#define PIDFILE "/var/run/dmeventd.pid"
#define DEFAULT_TIMEOUT 10
/* Commands for the daemon passed in the message below. */
enum dmeventd_command {
CMD_ACTIVE = 1,
CMD_REGISTER_FOR_EVENT,
CMD_UNREGISTER_FOR_EVENT,
CMD_GET_REGISTERED_DEVICE,
CMD_GET_NEXT_REGISTERED_DEVICE,
CMD_SET_TIMEOUT,
CMD_GET_TIMEOUT,
};
/* Message passed between client and daemon. */
struct daemon_message {
union {
unsigned int cmd;
int status;
} opcode;
char msg[252];
} __attribute__((packed));
/* Fifos for client/daemon communication. */
struct fifos {
int client;
int server;
const char *client_path;
const char *server_path;
};
/* Event type definitions. */
enum event_type {
SINGLE = 0x01, /* Report multiple errors just once. */
MULTI = 0x02, /* Report all of them. */
SECTOR_ERROR = 0x04, /* Failure on a particular sector. */
DEVICE_ERROR = 0x08, /* Device failure. */
PATH_ERROR = 0x10, /* Failure on an io path. */
ADAPTOR_ERROR = 0x20, /* Failure off a host adaptor. */
SYNC_STATUS = 0x40, /* Mirror synchronization completed/failed. */
TIMEOUT = 0x80, /* Timeout has occured */
};
#define ALL_ERRORS (SECTOR_ERROR | DEVICE_ERROR | PATH_ERROR | ADAPTOR_ERROR)
/* Prototypes for event lib interface. */
int dm_register_for_event(char *dso_name, char *device, enum event_type events);
int dm_unregister_for_event(char *dso_name, char *device,
enum event_type events);
int dm_get_registered_device(char **dso_name, char **device,
enum event_type *events, int next);
int dm_set_event_timeout(char *device, uint32_t timeout);
int dm_get_event_timeout(char *device, uint32_t *timeout);
/* Prototypes for DSO interface. */
void process_event(char *device, enum event_type event);
int register_device(char *device);
int unregister_device(char *device);
#endif
/*
* 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:
*/

View File

@@ -20,10 +20,6 @@
#include <fcntl.h> #include <fcntl.h>
#include <dirent.h> #include <dirent.h>
#ifdef linux
# include <malloc.h>
#endif
static int _create_dir_recursive(const char *dir) static int _create_dir_recursive(const char *dir)
{ {
char *orig, *s; char *orig, *s;
@@ -31,7 +27,7 @@ static int _create_dir_recursive(const char *dir)
log_verbose("Creating directory \"%s\"", dir); log_verbose("Creating directory \"%s\"", dir);
/* Create parent directories */ /* Create parent directories */
orig = s = strdup(dir); orig = s = dm_strdup(dir);
while ((s = strchr(s, '/')) != NULL) { while ((s = strchr(s, '/')) != NULL) {
*s = '\0'; *s = '\0';
if (*orig) { if (*orig) {
@@ -39,13 +35,13 @@ static int _create_dir_recursive(const char *dir)
if (rc < 0 && errno != EEXIST) { if (rc < 0 && errno != EEXIST) {
log_error("%s: mkdir failed: %s", orig, log_error("%s: mkdir failed: %s", orig,
strerror(errno)); strerror(errno));
free(orig); dm_free(orig);
return 0; return 0;
} }
} }
*s++ = '/'; *s++ = '/';
} }
free(orig); dm_free(orig);
/* Create final directory */ /* Create final directory */
rc = mkdir(dir, 0777); rc = mkdir(dir, 0777);

View File

@@ -18,7 +18,7 @@
#include <assert.h> #include <assert.h>
#include <stdarg.h> #include <stdarg.h>
char *dm_strdup(const char *str) char *dm_strdup_aux(const char *str)
{ {
char *ret = dm_malloc(strlen(str) + 1); char *ret = dm_malloc(strlen(str) + 1);
@@ -198,9 +198,9 @@ int dm_dump_memory_debug(void)
} }
str[sizeof(str) - 1] = '\0'; str[sizeof(str) - 1] = '\0';
_log(_LOG_INFO, mb->file, mb->line, dm_log(_LOG_INFO, mb->file, mb->line,
"block %d at %p, size %" PRIsize_t "\t [%s]", "block %d at %p, size %" PRIsize_t "\t [%s]",
mb->id, mb->magic, mb->length, str); mb->id, mb->magic, mb->length, str);
tot += mb->length; tot += mb->length;
} }

View File

@@ -85,7 +85,7 @@ void *dm_pool_alloc_aligned(struct dm_pool *p, size_t s, unsigned alignment)
/* have we got room ? */ /* have we got room ? */
if (!c || (c->begin > c->end) || (c->end - c->begin < s)) { if (!c || (c->begin > c->end) || (c->end - c->begin < s)) {
/* allocate new chunk */ /* allocate new chunk */
int needed = s + alignment + sizeof(struct chunk); size_t needed = s + alignment + sizeof(struct chunk);
c = _new_chunk(p, (needed > p->chunk_size) ? c = _new_chunk(p, (needed > p->chunk_size) ?
needed : p->chunk_size); needed : p->chunk_size);

View File

@@ -27,11 +27,9 @@ LIBS = @LIBS@
CFLAGS += @DEFS@ CFLAGS += @DEFS@
CFLAGS += @CFLAGS@ CFLAGS += @CFLAGS@
CLDFLAGS += @CLDFLAGS@ CLDFLAGS += @CLDFLAGS@
CLDWHOLEARCHIVE += @CLDWHOLEARCHIVE@
CLDNOWHOLEARCHIVE += @CLDNOWHOLEARCHIVE@
LDDEPS += @LDDEPS@ LDDEPS += @LDDEPS@
LDFLAGS += @LDFLAGS@ LDFLAGS += @LDFLAGS@
SOFLAG += @SOFLAG@ LIB_SUFFIX = @LIB_SUFFIX@
# Setup directory variables # Setup directory variables
prefix = @prefix@ prefix = @prefix@
@@ -56,7 +54,7 @@ ifndef MAKEFLAGS
MAKEFLAGS = @JOBS@ MAKEFLAGS = @JOBS@
endif endif
SUFFIXES = .c .d .o .so .a .po .pot .mo SUFFIXES = .c .d .o .so .a .po .pot .mo .dylib
CFLAGS += -fPIC -Wall -Wundef -Wshadow -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline CFLAGS += -fPIC -Wall -Wundef -Wshadow -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline
@@ -151,9 +149,21 @@ $(TARGETS): $(OBJECTS)
%.so: %.o %.so: %.o
$(CC) -c $(INCLUDES) $(CFLAGS) $< -o $@ $(CC) -c $(INCLUDES) $(CFLAGS) $< -o $@
ifeq ("@LIB_SUFFIX@","so")
$(LIB_SHARED): $(OBJECTS) $(LDDEPS) $(LIB_SHARED): $(OBJECTS) $(LDDEPS)
$(CC) $(SOFLAG) -Wl,-soname,$(notdir $@).$(LIB_VERSION) \ $(CC) -shared -Wl,-soname,$(notdir $@).$(LIB_VERSION) \
$(CLDFLAGS) $(OBJECTS) -o $@ $(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
endif
ifeq ("@LIB_SUFFIX@","dylib")
$(LIB_SHARED): $(OBJECTS) $(LDDEPS)
$(CC) -dynamiclib -dylib_current_version,$(LIB_VERSION) \
$(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
endif
%.so: %.a
$(CC) -shared -Wl,-soname,$(notdir $@).$(LIB_VERSION) \
$(CLDFLAGS) $(LIBS) -o $@ @CLDWHOLEARCHIVE@ $< @CLDNOWHOLEARCHIVE@
$(LIB_STATIC): $(OBJECTS) $(LIB_STATIC): $(OBJECTS)
$(RM) $@ $(RM) $@

View File

@@ -43,8 +43,8 @@ The values are:
Display the mapping of logical extents to physical volumes and Display the mapping of logical extents to physical volumes and
physical extents. physical extents.
.SH Examples .SH Examples
"lvdisplay -v /dev/vg00/lvol2" shows attributes of that logical volume "lvdisplay -v /dev/vg00/lvol2" shows attributes of that logical volume.
and its mapping of logical to physical extents. In case snapshot If snapshot
logical volumes have been created for this original logical volume, logical volumes have been created for this original logical volume,
this command shows a list of all snapshot logical volumes and their this command shows a list of all snapshot logical volumes and their
status (active or inactive) as well. status (active or inactive) as well.

View File

@@ -87,6 +87,10 @@ ifeq ("@CMDLIB@", "yes")
INSTALL_TARGETS += $(INSTALL_CMDLIB_TARGETS) INSTALL_TARGETS += $(INSTALL_CMDLIB_TARGETS)
endif endif
ifeq ("@DMEVENTD@", "yes")
LVMLIBS += -ldevmapper-event -lpthread
endif
ifeq ("@DEVMAPPER@", "yes") ifeq ("@DEVMAPPER@", "yes")
LVMLIBS += -ldevmapper LVMLIBS += -ldevmapper
endif endif
@@ -107,8 +111,6 @@ liblvm2cmd.a: $(top_srcdir)/lib/liblvm.a $(OBJECTS)
$(AR) rs $@ $(OBJECTS) $(AR) rs $@ $(OBJECTS)
liblvm2cmd.so: liblvm2cmd.a $(LDDEPS) liblvm2cmd.so: liblvm2cmd.a $(LDDEPS)
$(CC) -o liblvm2cmd.so $(SOFLAG) $(CLDFLAGS) \
$(CLDWHOLEARCHIVE) liblvm2cmd.a $(CLDNOWHOLEARCHIVE)
.commands: commands.h cmdnames.h Makefile .commands: commands.h cmdnames.h Makefile
$(CC) -E -P cmdnames.h 2> /dev/null | \ $(CC) -E -P cmdnames.h 2> /dev/null | \

View File

@@ -44,6 +44,7 @@ arg(minor_ARG, '\0', "minor", minor_arg)
arg(type_ARG, '\0', "type", segtype_arg) arg(type_ARG, '\0', "type", segtype_arg)
arg(alloc_ARG, '\0', "alloc", alloc_arg) arg(alloc_ARG, '\0', "alloc", alloc_arg)
arg(separator_ARG, '\0', "separator", string_arg) arg(separator_ARG, '\0', "separator", string_arg)
arg(mirrorsonly_ARG, '\0', "mirrorsonly", NULL)
/* Allow some variations */ /* Allow some variations */
arg(resizable_ARG, '\0', "resizable", yes_no_arg) arg(resizable_ARG, '\0', "resizable", yes_no_arg)
@@ -85,7 +86,7 @@ arg(size_ARG, 'L', "size", size_mb_arg)
arg(logicalextent_ARG, 'L', "logicalextent", int_arg_with_sign) arg(logicalextent_ARG, 'L', "logicalextent", int_arg_with_sign)
arg(persistent_ARG, 'M', "persistent", yes_no_arg) arg(persistent_ARG, 'M', "persistent", yes_no_arg)
arg(major_ARG, 'j', "major", major_arg) arg(major_ARG, 'j', "major", major_arg)
arg(mirrors_ARG, 'm', "mirrors", int_arg) arg(mirrors_ARG, 'm', "mirrors", int_arg_with_sign)
arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_arg) arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_arg)
arg(maps_ARG, 'm', "maps", NULL) arg(maps_ARG, 'm', "maps", NULL)
arg(name_ARG, 'n', "name", string_arg) arg(name_ARG, 'n', "name", string_arg)

View File

@@ -85,11 +85,12 @@ xx(lvconvert,
"\t[-d|--debug]\n" "\t[-d|--debug]\n"
"\t[-h|-?|--help]\n" "\t[-h|-?|--help]\n"
"\t[-m|--mirrors Mirrors]\n" "\t[-m|--mirrors Mirrors]\n"
"\t[-R|--regionsize MirrorLogRegionSize]\n"
"\t[-v|--verbose]\n" "\t[-v|--verbose]\n"
"\t[--version]" "\n" "\t[--version]" "\n"
"\tLogicalVolume[Path] [PhysicalVolume[Path]...]\n", "\tLogicalVolume[Path] [PhysicalVolume[Path]...]\n",
alloc_ARG, mirrors_ARG, test_ARG) alloc_ARG, mirrors_ARG, regionsize_ARG, test_ARG)
xx(lvcreate, xx(lvcreate,
"Create a logical volume", "Create a logical volume",
@@ -769,6 +770,7 @@ xx(vgreduce,
"\t[-A|--autobackup y|n]\n" "\t[-A|--autobackup y|n]\n"
"\t[-d|--debug]\n" "\t[-d|--debug]\n"
"\t[-h|--help]\n" "\t[-h|--help]\n"
"\t[--mirrorsonly]\n"
"\t[--removemissing]\n" "\t[--removemissing]\n"
"\t[-t|--test]\n" "\t[-t|--test]\n"
"\t[-v|--verbose]\n" "\t[-v|--verbose]\n"
@@ -776,7 +778,7 @@ xx(vgreduce,
"\tVolumeGroupName\n" "\tVolumeGroupName\n"
"\t[PhysicalVolumePath...]\n", "\t[PhysicalVolumePath...]\n",
all_ARG, autobackup_ARG, removemissing_ARG, test_ARG) all_ARG, autobackup_ARG, mirrorsonly_ARG, removemissing_ARG, test_ARG)
xx(vgremove, xx(vgremove,
"Remove volume group(s)", "Remove volume group(s)",

View File

@@ -86,8 +86,10 @@ enum {
READ_ONLY = 0, READ_ONLY = 0,
COLS_ARG, COLS_ARG,
EXEC_ARG, EXEC_ARG,
GID_ARG,
MAJOR_ARG, MAJOR_ARG,
MINOR_ARG, MINOR_ARG,
MODE_ARG,
NOHEADINGS_ARG, NOHEADINGS_ARG,
NOLOCKFS_ARG, NOLOCKFS_ARG,
NOOPENCOUNT_ARG, NOOPENCOUNT_ARG,
@@ -95,6 +97,7 @@ enum {
OPTIONS_ARG, OPTIONS_ARG,
TARGET_ARG, TARGET_ARG,
TREE_ARG, TREE_ARG,
UID_ARG,
UUID_ARG, UUID_ARG,
VERBOSE_ARG, VERBOSE_ARG,
VERSION_ARG, VERSION_ARG,
@@ -390,6 +393,15 @@ static int _create(int argc, char **argv, void *data)
if (_switches[MINOR_ARG] && !dm_task_set_minor(dmt, _values[MINOR_ARG])) if (_switches[MINOR_ARG] && !dm_task_set_minor(dmt, _values[MINOR_ARG]))
goto out; goto out;
if (_switches[UID_ARG] && !dm_task_set_uid(dmt, _values[UID_ARG]))
goto out;
if (_switches[GID_ARG] && !dm_task_set_gid(dmt, _values[GID_ARG]))
goto out;
if (_switches[MODE_ARG] && !dm_task_set_mode(dmt, _values[MODE_ARG]))
goto out;
if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt)) if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
goto out; goto out;
@@ -438,7 +450,8 @@ static int _rename(int argc, char **argv, void *data)
static int _message(int argc, char **argv, void *data) static int _message(int argc, char **argv, void *data)
{ {
int r = 0, sz = 1, i; int r = 0, i;
size_t sz = 1;
struct dm_task *dmt; struct dm_task *dmt;
char *str; char *str;
@@ -455,7 +468,7 @@ static int _message(int argc, char **argv, void *data)
argv++; argv++;
} }
if (!dm_task_set_sector(dmt, atoll(argv[1]))) if (!dm_task_set_sector(dmt, (uint64_t) atoll(argv[1])))
goto out; goto out;
argc -= 2; argc -= 2;
@@ -495,6 +508,39 @@ static int _message(int argc, char **argv, void *data)
return r; return r;
} }
static int _setgeometry(int argc, char **argv, void *data)
{
int r = 0;
struct dm_task *dmt;
if (!(dmt = dm_task_create(DM_DEVICE_SET_GEOMETRY)))
return 0;
if (_switches[UUID_ARG] || _switches[MAJOR_ARG]) {
if (!_set_task_device(dmt, NULL, 0))
goto out;
} else {
if (!_set_task_device(dmt, argv[1], 0))
goto out;
argc--;
argv++;
}
if (!dm_task_set_geometry(dmt, argv[1], argv[2], argv[3], argv[4]))
goto out;
/* run the task */
if (!dm_task_run(dmt))
goto out;
r = 1;
out:
dm_task_destroy(dmt);
return r;
}
static int _version(int argc, char **argv, void *data) static int _version(int argc, char **argv, void *data)
{ {
char version[80]; char version[80];
@@ -502,7 +548,7 @@ static int _version(int argc, char **argv, void *data)
if (dm_get_library_version(version, sizeof(version))) if (dm_get_library_version(version, sizeof(version)))
printf("Library version: %s\n", version); printf("Library version: %s\n", version);
if (dm_driver_version(version, sizeof(version))) if (!dm_driver_version(version, sizeof(version)))
return 0; return 0;
printf("Driver version: %s\n", version); printf("Driver version: %s\n", version);
@@ -580,7 +626,7 @@ static int _wait(int argc, char **argv, void *data)
} }
return _simple(DM_DEVICE_WAITEVENT, name, return _simple(DM_DEVICE_WAITEVENT, name,
(argc > 1) ? atoi(argv[argc - 1]) : 0, 1); (argc > 1) ? (uint32_t) atoi(argv[argc - 1]) : 0, 1);
} }
static int _process_all(int argc, char **argv, static int _process_all(int argc, char **argv,
@@ -622,7 +668,7 @@ static int _process_all(int argc, char **argv,
return r; return r;
} }
static void _display_dev(struct dm_task *dmt, char *name) static void _display_dev(struct dm_task *dmt, const char *name)
{ {
struct dm_info info; struct dm_info info;
@@ -635,7 +681,7 @@ static int _mknodes(int argc, char **argv, void *data)
return dm_mknodes(argc > 1 ? argv[1] : NULL); return dm_mknodes(argc > 1 ? argv[1] : NULL);
} }
static int _exec_command(char *name) static int _exec_command(const char *name)
{ {
int n; int n;
static char path[PATH_MAX]; static char path[PATH_MAX];
@@ -651,7 +697,7 @@ static int _exec_command(char *name)
return 0; return 0;
n = snprintf(path, sizeof(path), "%s/%s", dm_dir(), name); n = snprintf(path, sizeof(path), "%s/%s", dm_dir(), name);
if (n < 0 || n > sizeof(path) - 1) if (n < 0 || n > (int) sizeof(path) - 1)
return 0; return 0;
if (!argc) { if (!argc) {
@@ -704,7 +750,7 @@ static int _status(int argc, char **argv, void *data)
char *params; char *params;
int cmd; int cmd;
struct dm_names *names = (struct dm_names *) data; struct dm_names *names = (struct dm_names *) data;
char *name = NULL; const char *name = NULL;
int matched = 0; int matched = 0;
int ls_only = 0; int ls_only = 0;
struct dm_info info; struct dm_info info;
@@ -742,7 +788,7 @@ static int _status(int argc, char **argv, void *data)
goto out; goto out;
if (!name) if (!name)
name = (char *) dm_task_get_name(dmt); name = dm_task_get_name(dmt);
/* Fetch targets and print 'em */ /* Fetch targets and print 'em */
do { do {
@@ -1292,6 +1338,7 @@ struct command {
static struct command _commands[] = { static struct command _commands[] = {
{"create", "<dev_name> [-j|--major <major> -m|--minor <minor>]\n" {"create", "<dev_name> [-j|--major <major> -m|--minor <minor>]\n"
"\t [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>]\n"
"\t [-u|uuid <uuid>] [--notable] [<table_file>]", "\t [-u|uuid <uuid>] [--notable] [<table_file>]",
1, 2, _create}, 1, 2, _create},
{"remove", "<device>", 0, 1, _remove}, {"remove", "<device>", 0, 1, _remove},
@@ -1312,6 +1359,7 @@ static struct command _commands[] = {
{"mknodes", "[<device>]", 0, 1, _mknodes}, {"mknodes", "[<device>]", 0, 1, _mknodes},
{"targets", "", 0, 0, _targets}, {"targets", "", 0, 0, _targets},
{"version", "", 0, 0, _version}, {"version", "", 0, 0, _version},
{"setgeometry", "<device> <cyl> <head> <sect> <start>", 5, 5, _setgeometry},
{NULL, NULL, 0, 0, NULL} {NULL, NULL, 0, 0, NULL}
}; };
@@ -1418,8 +1466,10 @@ static int _process_switches(int *argc, char ***argv)
{"readonly", 0, &ind, READ_ONLY}, {"readonly", 0, &ind, READ_ONLY},
{"columns", 0, &ind, COLS_ARG}, {"columns", 0, &ind, COLS_ARG},
{"exec", 1, &ind, EXEC_ARG}, {"exec", 1, &ind, EXEC_ARG},
{"gid", 1, &ind, GID_ARG},
{"major", 1, &ind, MAJOR_ARG}, {"major", 1, &ind, MAJOR_ARG},
{"minor", 1, &ind, MINOR_ARG}, {"minor", 1, &ind, MINOR_ARG},
{"mode", 1, &ind, MODE_ARG},
{"noheadings", 0, &ind, NOHEADINGS_ARG}, {"noheadings", 0, &ind, NOHEADINGS_ARG},
{"nolockfs", 0, &ind, NOLOCKFS_ARG}, {"nolockfs", 0, &ind, NOLOCKFS_ARG},
{"noopencount", 0, &ind, NOOPENCOUNT_ARG}, {"noopencount", 0, &ind, NOOPENCOUNT_ARG},
@@ -1427,6 +1477,7 @@ static int _process_switches(int *argc, char ***argv)
{"options", 1, &ind, OPTIONS_ARG}, {"options", 1, &ind, OPTIONS_ARG},
{"target", 1, &ind, TARGET_ARG}, {"target", 1, &ind, TARGET_ARG},
{"tree", 0, &ind, TREE_ARG}, {"tree", 0, &ind, TREE_ARG},
{"uid", 1, &ind, UID_ARG},
{"uuid", 1, &ind, UUID_ARG}, {"uuid", 1, &ind, UUID_ARG},
{"verbose", 1, &ind, VERBOSE_ARG}, {"verbose", 1, &ind, VERBOSE_ARG},
{"version", 0, &ind, VERSION_ARG}, {"version", 0, &ind, VERSION_ARG},
@@ -1478,7 +1529,7 @@ static int _process_switches(int *argc, char ***argv)
optarg = 0; optarg = 0;
optind = OPTIND_INIT; optind = OPTIND_INIT;
while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCj:m:no:ru:v", while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCGj:m:Mno:ru:Uv",
long_options, NULL)) != -1) { long_options, NULL)) != -1) {
if (c == 'c' || c == 'C' || ind == COLS_ARG) if (c == 'c' || c == 'C' || ind == COLS_ARG)
_switches[COLS_ARG]++; _switches[COLS_ARG]++;
@@ -1504,6 +1555,19 @@ static int _process_switches(int *argc, char ***argv)
_switches[UUID_ARG]++; _switches[UUID_ARG]++;
_uuid = optarg; _uuid = optarg;
} }
if (c == 'G' || ind == GID_ARG) {
_switches[GID_ARG]++;
_values[GID_ARG] = atoi(optarg);
}
if (c == 'U' || ind == UID_ARG) {
_switches[UID_ARG]++;
_values[UID_ARG] = atoi(optarg);
}
if (c == 'M' || ind == MODE_ARG) {
_switches[MODE_ARG]++;
/* FIXME Accept modes as per chmod */
_values[MODE_ARG] = (int) strtol(optarg, NULL, 8);
}
if ((ind == EXEC_ARG)) { if ((ind == EXEC_ARG)) {
_switches[EXEC_ARG]++; _switches[EXEC_ARG]++;
_command = optarg; _command = optarg;

View File

@@ -13,10 +13,13 @@
*/ */
#include "tools.h" #include "tools.h"
#include "lv_alloc.h"
struct lvconvert_params { struct lvconvert_params {
const char *lv_name; const char *lv_name;
uint32_t mirrors; uint32_t mirrors;
sign_t mirrors_sign;
uint32_t region_size;
alloc_policy_t alloc; alloc_policy_t alloc;
@@ -40,7 +43,29 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
return 0; return 0;
} }
lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1; lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0);
lp->mirrors_sign = arg_sign_value(cmd, mirrors_ARG, 0);
/*
* --regionsize is only valid when converting an LV into a mirror.
* This is checked when we know the state of the LV being converted.
*/
if (arg_count(cmd, regionsize_ARG)) {
if (arg_sign_value(cmd, regionsize_ARG, 0) == SIGN_MINUS) {
log_error("Negative regionsize is invalid");
return 0;
}
lp->region_size = 2 * arg_uint_value(cmd, regionsize_ARG, 0);
} else
lp->region_size = 2 * find_config_int(cmd->cft->root,
"activation/mirror_region_size",
DEFAULT_MIRROR_REGION_SIZE);
if (lp->region_size & (lp->region_size - 1)) {
log_error("Region size (%" PRIu32 ") must be a power of 2",
lp->region_size);
return 0;
}
if (!argc) { if (!argc) {
log_error("Please give logical volume path"); log_error("Please give logical volume path");
@@ -61,8 +86,33 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
{ {
struct lv_segment *seg; struct lv_segment *seg;
uint32_t existing_mirrors; uint32_t existing_mirrors;
// struct alloc_handle *ah = NULL; struct alloc_handle *ah = NULL;
// struct logical_volume *log_lv; struct logical_volume *log_lv;
struct list *parallel_areas;
struct segment_type *segtype;
seg = first_seg(lv);
existing_mirrors = seg->area_count;
/* Adjust required number of mirrors */
if (lp->mirrors_sign == SIGN_PLUS)
lp->mirrors = existing_mirrors + lp->mirrors;
else if (lp->mirrors_sign == SIGN_MINUS) {
if (lp->mirrors >= existing_mirrors) {
log_error("Logical volume %s only has %" PRIu32 " mirrors.",
lv->name, existing_mirrors);
return 0;
}
lp->mirrors = existing_mirrors - lp->mirrors;
} else
lp->mirrors += 1;
if (arg_count(cmd, regionsize_ARG) && (lv->status & MIRRORED) &&
(lp->region_size != seg->region_size)) {
log_error("Mirror log region size cannot be changed on "
"an existing mirror.");
return 0;
}
if ((lp->mirrors == 1)) { if ((lp->mirrors == 1)) {
if (!(lv->status & MIRRORED)) { if (!(lv->status & MIRRORED)) {
@@ -70,8 +120,8 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
lv->name); lv->name);
return 1; return 1;
} }
/* FIXME If allocatable_pvs supplied only remove those */
if (!remove_all_mirror_images(lv)) { if (!remove_mirror_images(seg, 1, lp->pv_count ? lp->pvh : NULL, 1)) {
stack; stack;
return 0; return 0;
} }
@@ -82,8 +132,6 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
"mirror segments.", lv->name); "mirror segments.", lv->name);
return 0; return 0;
} }
seg = first_seg(lv);
existing_mirrors = seg->area_count;
if (lp->mirrors == existing_mirrors) { if (lp->mirrors == existing_mirrors) {
log_error("Logical volume %s already has %" log_error("Logical volume %s already has %"
PRIu32 " mirror(s).", lv->name, PRIu32 " mirror(s).", lv->name,
@@ -100,18 +148,58 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
"supported yet."); "supported yet.");
return 0; return 0;
} else { } else {
if (!remove_mirror_images(seg, lp->mirrors)) { /* Reduce number of mirrors */
if (!remove_mirror_images(seg, lp->mirrors, lp->pv_count ? lp->pvh : NULL, 0)) {
stack; stack;
return 0; return 0;
} }
} }
} else { } else {
/* Make existing LV into mirror set */
/* FIXME Share code with lvcreate */ /* FIXME Share code with lvcreate */
/* region size, log_name, create log_lv, zero it */
// Allocate (mirrors) new areas & log - replace mirrored_pv with mirrored_lv /* FIXME Why is this restriction here? Fix it! */
// Restructure as mirror - add existing param to create_mirror_layers list_iterate_items(seg, &lv->segments) {
log_error("Adding mirror images is not supported yet."); if (seg_is_striped(seg) && seg->area_count > 1) {
return 0; log_error("Mirrors of striped volumes are not yet supported.");
return 0;
}
}
if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv))) {
stack;
return 0;
}
segtype = get_segtype_from_string(cmd, "striped");
if (!(ah = allocate_extents(lv->vg, NULL, segtype, 1,
lp->mirrors - 1, 1,
lv->le_count * (lp->mirrors - 1),
NULL, 0, 0, lp->pvh,
lp->alloc,
parallel_areas))) {
stack;
return 0;
}
lp->region_size = adjusted_mirror_region_size(lv->vg->extent_size,
lv->le_count,
lp->region_size);
if (!(log_lv = create_mirror_log(cmd, lv->vg, ah,
lp->alloc,
lv->name))) {
log_error("Failed to create mirror log.");
return 0;
}
if (!create_mirror_layers(ah, 1, lp->mirrors, lv,
segtype, 0, lp->region_size,
log_lv)) {
stack;
return 0;
}
} }
} }

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved. * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
* *
* This file is part of LVM2. * This file is part of LVM2.
* *
@@ -291,6 +291,10 @@ static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd,
lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1; lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1;
if (lp->mirrors == 1) if (lp->mirrors == 1)
log_print("Redundant mirrors argument: default is 0"); log_print("Redundant mirrors argument: default is 0");
if (arg_sign_value(cmd, mirrors_ARG, 0) == SIGN_MINUS) {
log_error("Mirrors argument may not be negative");
return 0;
}
} }
if (lp->snapshot) { if (lp->snapshot) {
@@ -432,9 +436,8 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
const char *tag; const char *tag;
int consistent = 1; int consistent = 1;
struct alloc_handle *ah = NULL; struct alloc_handle *ah = NULL;
char *log_name, lv_name_buf[128]; char lv_name_buf[128];
const char *lv_name; const char *lv_name;
size_t len;
status |= lp->permission | VISIBLE_LV; status |= lp->permission | VISIBLE_LV;
@@ -584,71 +587,25 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
} }
if (lp->mirrors > 1) { if (lp->mirrors > 1) {
/* FIXME Calculate how many extents needed for the log */
if (!(ah = allocate_extents(vg, NULL, lp->segtype, lp->stripes,
lp->mirrors, 1, lp->extents,
NULL, 0, 0, pvh, lp->alloc,
NULL))) {
stack;
return 0;
}
lp->region_size = adjusted_mirror_region_size(vg->extent_size, lp->region_size = adjusted_mirror_region_size(vg->extent_size,
lp->extents, lp->extents,
lp->region_size); lp->region_size);
/* FIXME Calculate how many extents needed for the log */ if (!(log_lv = create_mirror_log(cmd, vg, ah, lp->alloc,
lv_name))) {
len = strlen(lv_name) + 32; log_error("Failed to create mirror log.");
if (!(log_name = alloca(len)) ||
!(generate_log_name_format(vg, lv_name, log_name, len))) {
log_error("log_name allocation failed. "
"Remove new LV and retry.");
return 0;
}
if (!(log_lv = lv_create_empty(vg->fid, log_name, NULL,
VISIBLE_LV | LVM_READ | LVM_WRITE,
lp->alloc, 0, vg))) {
stack;
return 0; return 0;
} }
if (!(ah = allocate_extents(vg, NULL, lp->segtype, lp->stripes,
lp->mirrors, 1, lp->extents,
NULL, 0, 0, pvh, lp->alloc))) {
stack;
return 0;
}
if (!lv_add_log_segment(ah, log_lv)) {
stack;
goto error;
}
/* store mirror log on disk(s) */
if (!vg_write(vg)) {
stack;
goto error;
}
backup(vg);
if (!vg_commit(vg)) {
stack;
goto error;
}
if (!activate_lv(cmd, log_lv)) {
log_error("Aborting. Failed to activate mirror log. "
"Remove new LVs and retry.");
goto error;
}
if (activation() && !zero_lv(cmd, log_lv)) {
log_error("Aborting. Failed to wipe mirror log. "
"Remove new LV and retry.");
goto error;
}
if (!deactivate_lv(cmd, log_lv)) {
log_error("Aborting. Failed to deactivate mirror log. "
"Remove new LV and retry.");
goto error;
}
log_lv->status &= ~VISIBLE_LV;
} }
if (!(lv = lv_create_empty(vg->fid, lv_name ? lv_name : "lvol%d", NULL, if (!(lv = lv_create_empty(vg->fid, lv_name ? lv_name : "lvol%d", NULL,

View File

@@ -168,6 +168,10 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 1) + 1; lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 1) + 1;
else else
log_print("Mirrors not supported. Ignoring."); log_print("Mirrors not supported. Ignoring.");
if (arg_sign_value(cmd, mirrors_ARG, 0) == SIGN_MINUS) {
log_error("Mirrors argument may not be negative");
return 0;
}
} }
if (arg_count(cmd, stripesize_ARG)) { if (arg_count(cmd, stripesize_ARG)) {

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved. * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
* *
* This file is part of LVM2. * This file is part of LVM2.
* *
@@ -21,6 +21,9 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv,
struct lvinfo info; struct lvinfo info;
int lv_total = 0; int lv_total = 0;
uint64_t lv_capacity_total = 0; uint64_t lv_capacity_total = 0;
int inkernel, snap_active = 1;
struct lv_segment *snap_seg = NULL;
float snap_percent; /* fused, fsize; */
const char *active_str, *snapshot_str; const char *active_str, *snapshot_str;
@@ -29,8 +32,27 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv,
!(lv_is_cow(lv))) !(lv_is_cow(lv)))
return ECMD_PROCESSED; return ECMD_PROCESSED;
inkernel = lv_info(cmd, lv, &info, 1) && info.exists;
if (lv_is_origin(lv)) {
list_iterate_items_gen(snap_seg, &lv->snapshot_segs,
origin_list) {
if (inkernel &&
(snap_active = lv_snapshot_percent(snap_seg->cow,
&snap_percent)))
if (snap_percent < 0 || snap_percent >= 100)
snap_active = 0;
}
snap_seg = NULL;
} else if ((snap_seg = find_cow(lv))) {
if (inkernel &&
(snap_active = lv_snapshot_percent(snap_seg->cow,
&snap_percent)))
if (snap_percent < 0 || snap_percent >= 100)
snap_active = 0;
}
/* FIXME Add -D arg to skip this! */ /* FIXME Add -D arg to skip this! */
if (lv_info(cmd, lv, &info, 0) && info.exists) if (inkernel && snap_active)
active_str = "ACTIVE "; active_str = "ACTIVE ";
else else
active_str = "inactive "; active_str = "inactive ";

View File

@@ -78,7 +78,7 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name)
} }
if (!dev) { if (!dev) {
log_error("Device %s not found.", name); log_error("Device %s not found (or ignored by filtering).", name);
return 0; return 0;
} }

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved. * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
* *
* This file is part of LVM2. * This file is part of LVM2.
* *
@@ -14,6 +14,7 @@
*/ */
#include "tools.h" #include "tools.h"
#include "lv_alloc.h"
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h> #include <sys/wait.h>
@@ -1074,3 +1075,71 @@ int zero_lv(struct cmd_context *cmd, struct logical_volume *lv)
return 1; return 1;
} }
struct logical_volume *create_mirror_log(struct cmd_context *cmd,
struct volume_group *vg,
struct alloc_handle *ah,
alloc_policy_t alloc,
const char *lv_name)
{
struct logical_volume *log_lv;
char *log_name;
size_t len;
len = strlen(lv_name) + 32;
if (!(log_name = alloca(len)) ||
!(generate_log_name_format(vg, lv_name, log_name, len))) {
log_error("log_name allocation failed. "
"Remove new LV and retry.");
return NULL;
}
if (!(log_lv = lv_create_empty(vg->fid, log_name, NULL,
VISIBLE_LV | LVM_READ | LVM_WRITE,
alloc, 0, vg))) {
stack;
return NULL;
}
if (!lv_add_log_segment(ah, log_lv)) {
stack;
goto error;
}
/* store mirror log on disk(s) */
if (!vg_write(vg)) {
stack;
goto error;
}
backup(vg);
if (!vg_commit(vg)) {
stack;
goto error;
}
if (!activate_lv(cmd, log_lv)) {
log_error("Aborting. Failed to activate mirror log. "
"Remove new LVs and retry.");
goto error;
}
if (activation() && !zero_lv(cmd, log_lv)) {
log_error("Aborting. Failed to wipe mirror log. "
"Remove new LV and retry.");
goto error;
}
if (!deactivate_lv(cmd, log_lv)) {
log_error("Aborting. Failed to deactivate mirror log. "
"Remove new LV and retry.");
goto error;
}
log_lv->status &= ~VISIBLE_LV;
return log_lv;
error:
/* FIXME Attempt to clean up. */
return NULL;
}

View File

@@ -93,6 +93,12 @@ int validate_vg_name(struct cmd_context *cmd, const char *vg_name);
int generate_log_name_format(struct volume_group *vg, const char *lv_name, int generate_log_name_format(struct volume_group *vg, const char *lv_name,
char *buffer, size_t size); char *buffer, size_t size);
struct logical_volume *create_mirror_log(struct cmd_context *cmd,
struct volume_group *vg,
struct alloc_handle *ah,
alloc_policy_t alloc,
const char *lv_name);
int zero_lv(struct cmd_context *cmd, struct logical_volume *lv); int zero_lv(struct cmd_context *cmd, struct logical_volume *lv);
#endif #endif

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved. * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
* *
* This file is part of LVM2. * This file is part of LVM2.
* *
@@ -14,6 +14,7 @@
*/ */
#include "tools.h" #include "tools.h"
#include "lv_alloc.h"
static int _remove_pv(struct volume_group *vg, struct pv_list *pvl) static int _remove_pv(struct volume_group *vg, struct pv_list *pvl)
{ {
@@ -47,29 +48,27 @@ static int _remove_pv(struct volume_group *vg, struct pv_list *pvl)
} }
static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv, static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
int *list_unsafe) int *list_unsafe, struct list *lvs_changed)
{ {
struct lv_segment *snap_seg; struct lv_segment *snap_seg, *mirror_seg;
struct list *snh, *snht; struct list *snh, *snht;
struct logical_volume *cow; struct logical_volume *cow;
struct lv_list *lvl;
uint32_t extents;
struct lvinfo info;
int first = 1;
log_verbose("%s/%s has missing extents: removing (including " log_verbose("%s/%s has missing extents: removing (including "
"dependencies)", lv->vg->name, lv->name); "dependencies)", lv->vg->name, lv->name);
/* Deactivate if necessary */ /* FIXME Cope properly with stacked devices & snapshots. */
if (!lv_is_cow(lv)) {
log_verbose("Deactivating (if active) logical volume %s",
lv->name);
if (!deactivate_lv(cmd, lv)) { /* If snapshot device is missing, deactivate origin. */
log_error("Failed to deactivate LV %s", lv->name); if (lv_is_cow(lv) && (snap_seg = find_cow(lv))) {
return 0;
}
} else if ((snap_seg = find_cow(lv))) {
log_verbose("Deactivating (if active) logical volume %s " log_verbose("Deactivating (if active) logical volume %s "
"(origin of %s)", snap_seg->origin->name, lv->name); "(origin of %s)", snap_seg->origin->name, lv->name);
if (!deactivate_lv(cmd, snap_seg->origin)) { if (!test_mode() && !deactivate_lv(cmd, snap_seg->origin)) {
log_error("Failed to deactivate LV %s", log_error("Failed to deactivate LV %s",
snap_seg->origin->name); snap_seg->origin->name);
return 0; return 0;
@@ -85,6 +84,13 @@ static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
origin_list); origin_list);
cow = snap_seg->cow; cow = snap_seg->cow;
if (first && !test_mode() &&
!deactivate_lv(cmd, snap_seg->origin)) {
log_error("Failed to deactivate LV %s",
snap_seg->origin->name);
return 0;
}
*list_unsafe = 1; /* May remove caller's lvht! */ *list_unsafe = 1; /* May remove caller's lvht! */
if (!vg_remove_snapshot(cow)) { if (!vg_remove_snapshot(cow)) {
stack; stack;
@@ -96,13 +102,46 @@ static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
stack; stack;
return 0; return 0;
} }
first = 0;
} }
/* Remove the LV itself */ /*
log_verbose("Removing LV %s from VG %s", lv->name, lv->vg->name); * If LV is active, replace it with error segment
if (!lv_remove(lv)) { * and add to list of LVs to be removed later.
stack; * Doesn't apply to snapshots/origins yet - they're already deactivated.
return 0; */
if (lv_info(cmd, lv, &info, 0) && info.exists) {
extents = lv->le_count;
mirror_seg = first_seg(lv)->mirror_seg;
if (!lv_empty(lv)) {
stack;
return 0;
}
if (!lv_add_virtual_segment(lv, 0, extents,
get_segtype_from_string(cmd,
"error"))) {
stack;
return 0;
}
if (mirror_seg) {
first_seg(lv)->status |= MIRROR_IMAGE;
first_seg(lv)->mirror_seg = mirror_seg;
}
if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl)))) {
log_error("lv_list alloc failed");
return 0;
}
lvl->lv = lv;
list_add(lvs_changed, &lvl->list);
} else {
/* Remove LV immediately. */
log_verbose("Removing LV %s from VG %s", lv->name, lv->vg->name);
if (!lv_remove(lv)) {
stack;
return 0;
}
} }
return 1; return 1;
@@ -113,11 +152,16 @@ static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
struct list *pvh, *pvht; struct list *pvh, *pvht;
struct list *lvh, *lvht; struct list *lvh, *lvht;
struct pv_list *pvl; struct pv_list *pvl;
struct lv_list *lvl, *lvl2, *lvlt;
struct logical_volume *lv; struct logical_volume *lv;
struct physical_volume *pv; struct physical_volume *pv;
struct lv_segment *seg; struct lv_segment *seg, *mirrored_seg;
struct lv_segment_area area;
unsigned int s; unsigned int s;
int list_unsafe; uint32_t mimages;
int list_unsafe, only_mirror_images_found;
LIST_INIT(lvs_changed);
only_mirror_images_found = 1;
/* Deactivate & remove necessary LVs */ /* Deactivate & remove necessary LVs */
restart_loop: restart_loop:
@@ -136,7 +180,13 @@ static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
pv = seg_pv(seg, s); pv = seg_pv(seg, s);
if (!pv || !pv->dev) { if (!pv || !pv->dev) {
if (!_remove_lv(cmd, lv, &list_unsafe)) { if (arg_count(cmd, mirrorsonly_ARG) &&
!(lv->status & MIRROR_IMAGE)) {
log_error("Non-mirror-image LV %s found: can't remove.", lv->name);
only_mirror_images_found = 0;
continue;
}
if (!_remove_lv(cmd, lv, &list_unsafe, &lvs_changed)) {
stack; stack;
return 0; return 0;
} }
@@ -147,6 +197,11 @@ static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
} }
} }
if (!only_mirror_images_found) {
log_error("Aborting because --mirrorsonly was specified.");
return 0;
}
/* Remove missing PVs */ /* Remove missing PVs */
list_iterate_safe(pvh, pvht, &vg->pvs) { list_iterate_safe(pvh, pvht, &vg->pvs) {
pvl = list_item(pvh, struct pv_list); pvl = list_item(pvh, struct pv_list);
@@ -158,6 +213,111 @@ static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
} }
} }
/* VG is now consistent */
vg->status &= ~PARTIAL_VG;
vg->status |= LVM_WRITE;
init_partial(0);
/* FIXME Recovery. For now people must clean up by hand. */
if (!list_empty(&lvs_changed)) {
if (!vg_write(vg)) {
log_error("Failed to write out a consistent VG for %s",
vg->name);
return 0;
}
if (!test_mode()) {
/* Suspend lvs_changed */
init_partial(1);
if (!suspend_lvs(cmd, &lvs_changed)) {
stack;
init_partial(0);
vg_revert(vg);
return 0;
}
init_partial(0);
}
if (!vg_commit(vg)) {
log_error("Failed to commit consistent VG for %s",
vg->name);
vg_revert(vg);
return 0;
}
if (!test_mode()) {
if (!resume_lvs(cmd, &lvs_changed)) {
log_error("Failed to resume LVs using error segments.");
return 0;
}
}
/* Remove lost mirror images from mirrors */
list_iterate_items(lvl, &vg->lvs) {
mirrored_seg = first_seg(lvl->lv);
if (!seg_is_mirrored(mirrored_seg))
continue;
mimages = mirrored_seg->area_count;
for (s = 0; s < mirrored_seg->area_count; s++) {
list_iterate_items_safe(lvl2, lvlt, &lvs_changed) {
if (seg_type(mirrored_seg, s) != AREA_LV ||
lvl2->lv != seg_lv(mirrored_seg, s))
continue;
list_del(&lvl2->list);
area = mirrored_seg->areas[mimages - 1];
mirrored_seg->areas[mimages - 1] = mirrored_seg->areas[s];
mirrored_seg->areas[s] = area;
mimages--; /* FIXME Assumes uniqueness */
}
}
if (mimages != mirrored_seg->area_count) {
if (!remove_mirror_images(mirrored_seg, mimages, NULL, 0)) {
stack;
return 0;
}
if (!vg_write(vg)) {
log_error("Failed to write out updated "
"VG for %s", vg->name);
return 0;
}
if (!vg_commit(vg)) {
log_error("Failed to commit updated VG "
"for %s", vg->name);
vg_revert(vg);
return 0;
}
}
}
/* Deactivate error LVs */
if (!test_mode()) {
list_iterate_items(lvl, &lvs_changed) {
log_verbose("Deactivating (if active) logical volume %s",
lvl->lv->name);
if (!deactivate_lv(cmd, lvl->lv)) {
log_error("Failed to deactivate LV %s",
lvl->lv->name);
return 0;
}
}
}
/* Remove remaining LVs */
list_iterate_items(lvl, &lvs_changed) {
log_verbose("Removing LV %s from VG %s", lvl->lv->name,
lvl->lv->vg->name);
if (!lv_remove(lvl->lv)) {
stack;
return 0;
}
}
}
return 1; return 1;
} }
@@ -190,7 +350,7 @@ static int _vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
list_del(&pvl->list); list_del(&pvl->list);
pv->vg_name = ORPHAN; pv->vg_name = ORPHAN;
pv->status = ALLOCATABLE_PV; pv->status = ALLOCATABLE_PV;
if (!dev_get_size(pv->dev, &pv->size)) { if (!dev_get_size(pv->dev, &pv->size)) {
log_error("%s: Couldn't get size.", dev_name(pv->dev)); log_error("%s: Couldn't get size.", dev_name(pv->dev));
@@ -239,6 +399,12 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE; return EINVALID_CMD_LINE;
} }
if (arg_count(cmd, mirrorsonly_ARG) &&
!arg_count(cmd, removemissing_ARG)) {
log_error("--mirrorsonly requires --removemissing");
return EINVALID_CMD_LINE;
}
if (argc == 1 && !arg_count(cmd, all_ARG) if (argc == 1 && !arg_count(cmd, all_ARG)
&& !arg_count(cmd, removemissing_ARG)) { && !arg_count(cmd, removemissing_ARG)) {
log_error("Please enter physical volume paths or option -a"); log_error("Please enter physical volume paths or option -a");
@@ -300,11 +466,6 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED; return ECMD_FAILED;
} }
init_partial(0);
vg->status &= ~PARTIAL_VG;
vg->status |= LVM_WRITE;
if (!vg_write(vg) || !vg_commit(vg)) { if (!vg_write(vg) || !vg_commit(vg)) {
log_error("Failed to write out a consistent VG for %s", log_error("Failed to write out a consistent VG for %s",
vg_name); vg_name);