mirror of
git://sourceware.org/git/lvm2.git
synced 2025-09-29 13:44:18 +03:00
Compare commits
64 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ed43dc842b | ||
|
49d4db6cd2 | ||
|
ea80ab2cae | ||
|
382e808b8d | ||
|
846befa7e0 | ||
|
74dd29f843 | ||
|
b0473bffcb | ||
|
24dd9ab1a7 | ||
|
49d3037e87 | ||
|
37ad2bd4e8 | ||
|
7d7b332b02 | ||
|
ac033b8612 | ||
|
a7b98dfe25 | ||
|
7fb7c86c46 | ||
|
ed036598a9 | ||
|
160bb70cdf | ||
|
c2e61f3c21 | ||
|
18218467f3 | ||
|
17e298ad2a | ||
|
d031a374f9 | ||
|
55f69c98cb | ||
|
71f2e4306d | ||
|
f8af23a025 | ||
|
4ef55a6cd3 | ||
|
312f866723 | ||
|
0ebe1f6dec | ||
|
2ad92e0e6e | ||
|
ac8823cdcf | ||
|
77565f7ee4 | ||
|
d656d90fa8 | ||
|
175b3b0834 | ||
|
7477e6b714 | ||
|
cd6568db69 | ||
|
6aff325fb2 | ||
|
0d603cfe9c | ||
|
34a1f14a17 | ||
|
efe1c8a070 | ||
|
1575844344 | ||
|
221ac1c208 | ||
|
57442db759 | ||
|
5fdb3e7cd6 | ||
|
96f259726c | ||
|
4936efba5e | ||
|
d5a3559a2f | ||
|
114a1c7f52 | ||
|
ce5265c203 | ||
|
1a575d926f | ||
|
85c818a39e | ||
|
4ffa2defe4 | ||
|
8825157fbb | ||
|
966d608dc5 | ||
|
b808c89471 | ||
|
75d4e6490f | ||
|
a82775f544 | ||
|
6a22ad0171 | ||
|
c854e88186 | ||
|
d02203060c | ||
|
cf703b0433 | ||
|
c0197a72d3 | ||
|
e5a543e283 | ||
|
b8b029b7d3 | ||
|
370f368b1a | ||
|
8288b45b4f | ||
|
fe529faf8e |
11
Makefile.in
11
Makefile.in
@@ -24,8 +24,13 @@ endif
|
||||
|
||||
SUBDIRS += lib tools daemons
|
||||
|
||||
ifeq ("@DMEVENTD@", "yes")
|
||||
SUBDIRS += dmeventd
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS += daemons/clvmd \
|
||||
dmeventd \
|
||||
lib/format1 \
|
||||
lib/format_pool \
|
||||
lib/locking \
|
||||
@@ -40,13 +45,15 @@ include make.tmpl
|
||||
daemons: lib
|
||||
lib: include
|
||||
tools: lib
|
||||
po: tools daemons
|
||||
dmeventd: tools
|
||||
po: tools daemons dmeventd
|
||||
|
||||
ifeq ("@INTL@", "yes")
|
||||
lib.pofile: include.pofile
|
||||
tools.pofile: lib.pofile
|
||||
daemons.pofile: lib.pofile
|
||||
po.pofile: tools.pofile daemons.pofile
|
||||
dmeventd.pofile: tools.pofile
|
||||
po.pofile: tools.pofile daemons.pofile dmeventd.pofile
|
||||
pofile: po.pofile
|
||||
endif
|
||||
|
||||
|
21
WHATS_NEW
21
WHATS_NEW
@@ -1,5 +1,22 @@
|
||||
Version 2.02.02
|
||||
====================================
|
||||
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.
|
||||
|
23
WHATS_NEW_DM
23
WHATS_NEW_DM
@@ -1,5 +1,24 @@
|
||||
Version 1.02.02 -
|
||||
=============================
|
||||
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.
|
||||
|
||||
|
30
configure.in
30
configure.in
@@ -35,7 +35,7 @@ case "$host_os" in
|
||||
CLDNOWHOLEARCHIVE="-Wl,-no-whole-archive"
|
||||
LDDEPS="$LDDEPS .export.sym"
|
||||
LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
|
||||
SOFLAG="-shared"
|
||||
LIB_SUFFIX="so"
|
||||
DEVMAPPER=yes
|
||||
ODIRECT=yes
|
||||
SELINUX=yes
|
||||
@@ -49,7 +49,7 @@ case "$host_os" in
|
||||
CLDNOWHOLEARCHIVE=
|
||||
LDDEPS="$LDDEPS"
|
||||
LDFLAGS="$LDFLAGS"
|
||||
SOFLAG="-dynamiclib"
|
||||
LIB_SUFFIX="dylib"
|
||||
DEVMAPPER=yes
|
||||
ODIRECT=no
|
||||
SELINUX=no
|
||||
@@ -355,6 +355,23 @@ AC_ARG_ENABLE(fsadm, [ --enable-fsadm Enable fsadm],
|
||||
FSADM=$enableval)
|
||||
AC_MSG_RESULT($FSADM)
|
||||
|
||||
################################################################################
|
||||
dnl -- enable dmeventd handling
|
||||
AC_MSG_CHECKING(whether to use dmeventd)
|
||||
AC_ARG_ENABLE(dmeventd, [ --enable-dmeventd Enable the device-mapper event daemon],
|
||||
DMEVENTD=$enableval)
|
||||
AC_MSG_RESULT($DMEVENTD)
|
||||
|
||||
dnl -- dmeventd currently requires internal mirror support
|
||||
if test x$DMEVENTD = xyes && test x$MIRRORS != xinternal; then
|
||||
AC_MSG_ERROR(
|
||||
--enable-dmeventd currently requires --with-mirrors=internal
|
||||
)
|
||||
fi
|
||||
|
||||
if test x$DMEVENTD = xyes; then
|
||||
CFLAGS="$CFLAGS -DDMEVENTD"
|
||||
fi
|
||||
################################################################################
|
||||
dnl -- Mess with default exec_prefix
|
||||
if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
|
||||
@@ -545,7 +562,7 @@ AC_SUBST(CLDWHOLEARCHIVE)
|
||||
AC_SUBST(CLDNOWHOLEARCHIVE)
|
||||
AC_SUBST(LDDEPS)
|
||||
AC_SUBST(LDFLAGS)
|
||||
AC_SUBST(SOFLAG)
|
||||
AC_SUBST(LIB_SUFFIX)
|
||||
AC_SUBST(LIBS)
|
||||
AC_SUBST(LVM_VERSION)
|
||||
AC_SUBST(LVM1_FALLBACK)
|
||||
@@ -563,6 +580,7 @@ AC_SUBST(INTL)
|
||||
AC_SUBST(CLVMD)
|
||||
AC_SUBST(CLUSTER)
|
||||
AC_SUBST(FSADM)
|
||||
AC_SUBST(DMEVENTD)
|
||||
|
||||
################################################################################
|
||||
dnl -- First and last lines should not contain files to generate in order to
|
||||
@@ -572,6 +590,8 @@ Makefile \
|
||||
make.tmpl \
|
||||
daemons/Makefile \
|
||||
daemons/clvmd/Makefile \
|
||||
dmeventd/Makefile \
|
||||
dmeventd/mirror/Makefile \
|
||||
doc/Makefile \
|
||||
include/Makefile \
|
||||
lib/Makefile \
|
||||
@@ -599,3 +619,7 @@ fi
|
||||
if test x$FSADM == xyes; then
|
||||
AC_MSG_WARN(fsadm support is untested)
|
||||
fi
|
||||
|
||||
if test x$DMEVENTD == xyes; then
|
||||
AC_MSG_WARN(dmeventd support is untested)
|
||||
fi
|
||||
|
@@ -53,10 +53,19 @@ endif
|
||||
TARGETS = \
|
||||
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
|
||||
LIBS += -ldevmapper -llvm -lpthread
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
INSTALL_TARGETS = \
|
||||
install_clvmd
|
||||
|
@@ -1,5 +1,5 @@
|
||||
dm_register_for_event
|
||||
dm_unregister_for_event
|
||||
dm_get_registered_device
|
||||
dm_set_event_timeout
|
||||
dm_get_event_timeout
|
||||
dm_event_register
|
||||
dm_event_unregister
|
||||
dm_event_get_registered_device
|
||||
dm_event_set_timeout
|
||||
dm_event_get_timeout
|
||||
|
@@ -14,7 +14,6 @@
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
interface = @interface@
|
||||
|
||||
SOURCES = libdevmapper-event.c \
|
||||
dmeventd.c
|
||||
@@ -27,10 +26,10 @@ else
|
||||
LIB_SHARED = libdevmapper-event.so
|
||||
endif
|
||||
|
||||
CLDFLAGS += -ldl -ldevmapper -lpthread
|
||||
|
||||
include ../make.tmpl
|
||||
|
||||
CLDFLAGS += -ldl -ldevmapper -lpthread
|
||||
|
||||
.PHONY: install_dynamic install_static
|
||||
|
||||
INSTALL_TYPE = install_dynamic
|
||||
|
@@ -32,7 +32,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
@@ -45,11 +44,6 @@
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
/* FIXME Use dm library */
|
||||
#define dbg_malloc(x...) malloc(x)
|
||||
#define dbg_strdup(x...) strdup(x)
|
||||
#define dbg_free(x...) free(x)
|
||||
|
||||
/* List (un)link macros. */
|
||||
#define LINK(x, head) list_add(head, &(x)->list)
|
||||
#define LINK_DSO(dso) LINK(dso, &dso_registry)
|
||||
@@ -132,7 +126,8 @@ struct thread_status {
|
||||
struct dso_data *dso_data;/* DSO this thread accesses. */
|
||||
|
||||
char *device_path; /* Mapped device path. */
|
||||
int event_nr; /* event number */
|
||||
uint32_t event_nr; /* event number */
|
||||
int processing; /* Set when event is being processed */
|
||||
enum dm_event_type events; /* bitfield for event filter. */
|
||||
enum dm_event_type current_events;/* bitfield for occured events. */
|
||||
enum dm_event_type processed_events;/* bitfield for processed events. */
|
||||
@@ -141,6 +136,7 @@ struct thread_status {
|
||||
struct list timeout_list;
|
||||
};
|
||||
static LIST_INIT(thread_registry);
|
||||
static LIST_INIT(thread_registry_unused);
|
||||
|
||||
static int timeout_running;
|
||||
static LIST_INIT(timeout_registry);
|
||||
@@ -151,12 +147,12 @@ static pthread_cond_t timeout_cond = PTHREAD_COND_INITIALIZER;
|
||||
static struct thread_status *alloc_thread_status(struct message_data *data,
|
||||
struct dso_data *dso_data)
|
||||
{
|
||||
struct thread_status *ret = (typeof(ret)) dbg_malloc(sizeof(*ret));
|
||||
struct thread_status *ret = (typeof(ret)) dm_malloc(sizeof(*ret));
|
||||
|
||||
if (ret) {
|
||||
if (!memset(ret, 0, sizeof(*ret)) ||
|
||||
!(ret->device_path = dbg_strdup(data->device_path))) {
|
||||
dbg_free(ret);
|
||||
!(ret->device_path = dm_strdup(data->device_path))) {
|
||||
dm_free(ret);
|
||||
ret = NULL;
|
||||
} else {
|
||||
ret->dso_data = dso_data;
|
||||
@@ -171,19 +167,19 @@ static struct thread_status *alloc_thread_status(struct message_data *data,
|
||||
|
||||
static void free_thread_status(struct thread_status *thread)
|
||||
{
|
||||
dbg_free(thread->device_path);
|
||||
dbg_free(thread);
|
||||
dm_free(thread->device_path);
|
||||
dm_free(thread);
|
||||
}
|
||||
|
||||
/* Allocate/free DSO data. */
|
||||
static struct dso_data *alloc_dso_data(struct message_data *data)
|
||||
{
|
||||
struct dso_data *ret = (typeof(ret)) dbg_malloc(sizeof(*ret));
|
||||
struct dso_data *ret = (typeof(ret)) dm_malloc(sizeof(*ret));
|
||||
|
||||
if (ret) {
|
||||
if (!memset(ret, 0, sizeof(*ret)) ||
|
||||
!(ret->dso_name = dbg_strdup(data->dso_name))) {
|
||||
dbg_free(ret);
|
||||
!(ret->dso_name = dm_strdup(data->dso_name))) {
|
||||
dm_free(ret);
|
||||
ret = NULL;
|
||||
}
|
||||
}
|
||||
@@ -193,8 +189,8 @@ static struct dso_data *alloc_dso_data(struct message_data *data)
|
||||
|
||||
static void free_dso_data(struct dso_data *data)
|
||||
{
|
||||
dbg_free(data->dso_name);
|
||||
dbg_free(data);
|
||||
dm_free(data->dso_name);
|
||||
dm_free(data);
|
||||
}
|
||||
|
||||
/* FIXME: Factor out. */
|
||||
@@ -220,11 +216,11 @@ static int fetch_string(char **ptr, char **src)
|
||||
if ((p = strchr(*src, delimiter)))
|
||||
*p = 0;
|
||||
|
||||
if ((*ptr = dbg_strdup(*src))) {
|
||||
if ((*ptr = dm_strdup(*src))) {
|
||||
if ((len = strlen(*ptr)))
|
||||
*src += len;
|
||||
else {
|
||||
dbg_free(*ptr);
|
||||
dm_free(*ptr);
|
||||
*ptr = NULL;
|
||||
}
|
||||
|
||||
@@ -242,10 +238,10 @@ static int fetch_string(char **ptr, char **src)
|
||||
static void free_message(struct message_data *message_data)
|
||||
{
|
||||
if (message_data->dso_name)
|
||||
dbg_free(message_data->dso_name);
|
||||
dm_free(message_data->dso_name);
|
||||
|
||||
if (message_data->device_path)
|
||||
dbg_free(message_data->device_path);
|
||||
dm_free(message_data->device_path);
|
||||
}
|
||||
|
||||
/* Parse a register message from the client. */
|
||||
@@ -268,12 +264,12 @@ static int parse_message(struct message_data *message_data)
|
||||
* Free string representaion of events.
|
||||
* Not needed an more.
|
||||
*/
|
||||
dbg_free(message_data->events.str);
|
||||
dm_free(message_data->events.str);
|
||||
message_data->events.field = i;
|
||||
}
|
||||
if (message_data->timeout.str) {
|
||||
uint32_t secs = atoi(message_data->timeout.str);
|
||||
dbg_free(message_data->timeout.str);
|
||||
dm_free(message_data->timeout.str);
|
||||
message_data->timeout.secs = secs ? secs :
|
||||
DM_EVENT_DEFAULT_TIMEOUT;
|
||||
}
|
||||
@@ -304,10 +300,10 @@ static int storepid(int lf)
|
||||
if ((len = snprintf(pid, sizeof(pid), "%u\n", getpid())) < 0)
|
||||
return 0;
|
||||
|
||||
if (len > sizeof(pid))
|
||||
len = sizeof(pid);
|
||||
if (len > (int) sizeof(pid))
|
||||
len = (int) sizeof(pid);
|
||||
|
||||
if (write(lf, pid, len) != len)
|
||||
if (write(lf, pid, (size_t) len) != len)
|
||||
return 0;
|
||||
|
||||
fsync(lf);
|
||||
@@ -315,19 +311,29 @@ static int storepid(int lf)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* FIXME This is unreliable: should use DM_DEVICE_INFO ioctl instead. */
|
||||
/* Check, if a device exists. */
|
||||
static int device_exists(char *device)
|
||||
{
|
||||
struct stat st_buf;
|
||||
char path2[PATH_MAX];
|
||||
|
||||
return !stat(device, &st_buf) && S_ISBLK(st_buf.st_mode);
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find an existing thread for a device.
|
||||
*
|
||||
* Mutex must be hold when calling this.
|
||||
* Mutex must be held when calling this.
|
||||
*/
|
||||
static struct thread_status *lookup_thread_status(struct message_data *data)
|
||||
{
|
||||
@@ -578,6 +584,8 @@ static void monitor_unregister(void *arg)
|
||||
}
|
||||
|
||||
/* Device monitoring thread. */
|
||||
static void *monitor_thread(void *arg)
|
||||
__attribute((noreturn));
|
||||
static void *monitor_thread(void *arg)
|
||||
{
|
||||
struct thread_status *thread = arg;
|
||||
@@ -585,7 +593,7 @@ static void *monitor_thread(void *arg)
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
|
||||
pthread_cleanup_push(monitor_unregister, thread);
|
||||
|
||||
/* Wait for do_process_reques() to finish its task. */
|
||||
/* Wait for do_process_request() to finish its task. */
|
||||
lock_mutex();
|
||||
unlock_mutex();
|
||||
|
||||
@@ -593,6 +601,11 @@ static void *monitor_thread(void *arg)
|
||||
while (1) {
|
||||
thread->current_events = 0;
|
||||
|
||||
/*
|
||||
* FIXME: if unrecoverable error (ENODEV) happens,
|
||||
* we loop indefinitely. event_wait should return
|
||||
* more than 0/1.
|
||||
*/
|
||||
if (!event_wait(thread))
|
||||
continue;
|
||||
|
||||
@@ -603,12 +616,22 @@ static void *monitor_thread(void *arg)
|
||||
* the device got registered for those events AND
|
||||
* those events haven't been processed yet, call
|
||||
* the DSO's process_event() handler.
|
||||
*
|
||||
* FIXME: when does processed_events get cleared? What if
|
||||
* the same type of event happens later... after the first
|
||||
* was handled properly?
|
||||
*/
|
||||
if (thread->events &
|
||||
thread->current_events &
|
||||
~thread->processed_events) {
|
||||
lock_mutex();
|
||||
thread->processing = 1;
|
||||
unlock_mutex();
|
||||
do_process_event(thread);
|
||||
thread->processed_events |= thread->current_events;
|
||||
lock_mutex();
|
||||
thread->processing = 0;
|
||||
unlock_mutex();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -689,41 +712,27 @@ static int lookup_symbols(void *dl, struct dso_data *data)
|
||||
"unregister_device");
|
||||
}
|
||||
|
||||
/* Create a DSO file name based on its name. */
|
||||
static char *create_dso_file_name(char *dso_name)
|
||||
{
|
||||
char *ret;
|
||||
static char prefix[] = "libdmeventd";
|
||||
static char suffix[] = ".so";
|
||||
|
||||
if ((ret = dbg_malloc(strlen(prefix) +
|
||||
strlen(dso_name) +
|
||||
strlen(suffix) + 1)))
|
||||
sprintf(ret, "%s%s%s", prefix, dso_name, suffix);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Load an application specific DSO. */
|
||||
static struct dso_data *load_dso(struct message_data *data)
|
||||
{
|
||||
void *dl;
|
||||
struct dso_data *ret = NULL;
|
||||
char *dso_file;
|
||||
|
||||
if (!(dso_file = create_dso_file_name(data->dso_name)))
|
||||
return NULL;
|
||||
|
||||
if (!(dl = dlopen(dso_file, RTLD_NOW))){
|
||||
if (!(dl = dlopen(data->dso_name, RTLD_NOW))){
|
||||
log_error("%s\n", dlerror());
|
||||
goto free_dso_file;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(ret = alloc_dso_data(data)))
|
||||
goto close;
|
||||
if (!(ret = alloc_dso_data(data))) {
|
||||
dlclose(dl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(lookup_symbols(dl, ret)))
|
||||
goto free_all;
|
||||
if (!(lookup_symbols(dl, ret))) {
|
||||
free_dso_data(ret);
|
||||
dlclose(dl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Keep handle to close the library once
|
||||
@@ -736,17 +745,6 @@ static struct dso_data *load_dso(struct message_data *data)
|
||||
LINK_DSO(ret);
|
||||
unlock_mutex();
|
||||
|
||||
goto free_dso_file;
|
||||
|
||||
free_all:
|
||||
free_dso_data(ret);
|
||||
|
||||
close:
|
||||
dlclose(dl);
|
||||
|
||||
free_dso_file:
|
||||
dbg_free(dso_file);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -875,27 +873,11 @@ static int unregister_for_event(struct message_data *message_data)
|
||||
* In case there's no events to monitor on this device ->
|
||||
* unlink and terminate its monitoring thread.
|
||||
*/
|
||||
if (!thread->events)
|
||||
UNLINK_THREAD(thread);
|
||||
|
||||
unlock_mutex();
|
||||
|
||||
if (!thread->events) {
|
||||
/* turn codes negative */
|
||||
if ((ret = -terminate_thread(thread)))
|
||||
stack;
|
||||
else {
|
||||
pthread_join(thread->thread, NULL);
|
||||
free_thread_status(thread);
|
||||
lib_put(thread->dso_data);
|
||||
|
||||
lock_mutex();
|
||||
if (list_empty(&thread_registry))
|
||||
exit_dm_lib();
|
||||
unlock_mutex();
|
||||
}
|
||||
UNLINK_THREAD(thread);
|
||||
LINK(thread, &thread_registry_unused);
|
||||
}
|
||||
|
||||
unlock_mutex();
|
||||
|
||||
out:
|
||||
return ret;
|
||||
@@ -1054,7 +1036,8 @@ static int open_fifos(struct dm_event_fifos *fifos)
|
||||
*/
|
||||
static int client_read(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
|
||||
{
|
||||
int bytes = 0, ret = 0;
|
||||
unsigned bytes = 0;
|
||||
int ret = 0;
|
||||
fd_set fds;
|
||||
|
||||
errno = 0;
|
||||
@@ -1077,7 +1060,8 @@ static int client_read(struct dm_event_fifos *fifos, struct dm_event_daemon_mess
|
||||
*/
|
||||
static int client_write(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
|
||||
{
|
||||
int bytes = 0, ret = 0;
|
||||
unsigned bytes = 0;
|
||||
int ret = 0;
|
||||
fd_set fds;
|
||||
|
||||
errno = 0;
|
||||
@@ -1139,7 +1123,6 @@ static int do_process_request(struct dm_event_daemon_message *msg)
|
||||
stack;
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
log_print("%s: %u \"%s\"\n", __func__, msg->opcode.cmd, message_data.msg->msg);
|
||||
ret = handle_request(msg, &message_data);
|
||||
}
|
||||
|
||||
@@ -1164,11 +1147,43 @@ static void process_request(struct dm_event_fifos *fifos)
|
||||
|
||||
msg.opcode.status = do_process_request(&msg);
|
||||
|
||||
log_print("%s: status: %s\n", __func__, strerror(-msg.opcode.status));
|
||||
if (!client_write(fifos, &msg))
|
||||
stack;
|
||||
}
|
||||
|
||||
static void cleanup_unused_threads(void)
|
||||
{
|
||||
int ret;
|
||||
struct list *l;
|
||||
struct thread_status *thread;
|
||||
|
||||
lock_mutex();
|
||||
while ((l = list_first(&thread_registry_unused))) {
|
||||
thread = list_item(l, struct thread_status);
|
||||
if (thread->processing) {
|
||||
goto out; /* cleanup on the next round */
|
||||
}
|
||||
list_del(l);
|
||||
|
||||
if (!thread->events) {
|
||||
/* turn codes negative -- should we be returning this? */
|
||||
if ((ret = -terminate_thread(thread)))
|
||||
stack;
|
||||
else {
|
||||
pthread_join(thread->thread, NULL);
|
||||
lib_put(thread->dso_data);
|
||||
free_thread_status(thread);
|
||||
}
|
||||
} else {
|
||||
log_error("thread can't be on unused list unless !thread->events");
|
||||
LINK_THREAD(thread);
|
||||
}
|
||||
|
||||
}
|
||||
out:
|
||||
unlock_mutex();
|
||||
}
|
||||
|
||||
static void sig_alarm(int signum)
|
||||
{
|
||||
pthread_testcancel();
|
||||
@@ -1264,8 +1279,25 @@ void dmeventd(void)
|
||||
*/
|
||||
do {
|
||||
process_request(&fifos);
|
||||
cleanup_unused_threads();
|
||||
} while(!list_empty(&thread_registry));
|
||||
|
||||
/*
|
||||
* There may still have been some threads that were doing work,
|
||||
* make sure these are cleaned up
|
||||
*
|
||||
* I don't necessarily like the sleep there, but otherwise,
|
||||
* cleanup_unused_threads could get called many many times.
|
||||
* It's worth noting that the likelyhood of it being called
|
||||
* here is slim.
|
||||
*/
|
||||
while(!list_empty(&thread_registry_unused)) {
|
||||
sleep(1);
|
||||
cleanup_unused_threads();
|
||||
}
|
||||
|
||||
exit_dm_lib();
|
||||
|
||||
#ifdef MCL_CURRENT
|
||||
munlockall();
|
||||
#endif
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#define EXIT_FIFO_FAILURE 5
|
||||
#define EXIT_CHDIR_FAILURE 6
|
||||
|
||||
void dmeventd(void);
|
||||
void dmeventd(void)
|
||||
__attribute((noreturn));
|
||||
|
||||
#endif /* __DMEVENTD_DOT_H__ */
|
||||
|
@@ -44,7 +44,7 @@ static char *fetch_string(char **src)
|
||||
if ((p = strchr(*src, delimiter)))
|
||||
*p = 0;
|
||||
|
||||
if ((ret = strdup(*src)))
|
||||
if ((ret = dm_strdup(*src)))
|
||||
*src += strlen(ret) + 1;
|
||||
|
||||
if (p)
|
||||
@@ -69,52 +69,80 @@ static int parse_message(struct dm_event_daemon_message *msg, char **dso_name,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Read message from daemon. */
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
int bytes = 0, ret = 0;
|
||||
unsigned bytes = 0;
|
||||
int ret = 0;
|
||||
fd_set fds;
|
||||
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
errno = 0;
|
||||
/* FIXME Fix error handling. Check 'ret' before errno. EINTR? EAGAIN? */
|
||||
/* FIXME errno != EOF? RTFM! */
|
||||
while (bytes < sizeof(*msg) && errno != EOF) {
|
||||
while (bytes < sizeof(*msg)) {
|
||||
do {
|
||||
/* Watch daemon read FIFO for input. */
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fifos->server, &fds);
|
||||
/* FIXME Check for errors e.g. EBADF */
|
||||
} while (select(fifos->server+1, &fds, NULL, NULL, NULL) != 1);
|
||||
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);
|
||||
bytes += ret > 0 ? ret : 0;
|
||||
if (ret < 0) {
|
||||
if ((errno == EINTR) || (errno == EAGAIN))
|
||||
continue;
|
||||
else {
|
||||
/* FIXME Log error */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bytes += ret;
|
||||
}
|
||||
|
||||
// log_print("%s: \"%s\"\n", __func__, msg->msg);
|
||||
return bytes == sizeof(*msg);
|
||||
}
|
||||
|
||||
/* Write message to daemon. */
|
||||
static int daemon_write(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
|
||||
{
|
||||
int bytes = 0, ret = 0;
|
||||
unsigned bytes = 0;
|
||||
int ret = 0;
|
||||
fd_set fds;
|
||||
|
||||
|
||||
// log_print("%s: \"%s\"\n", __func__, msg->msg);
|
||||
errno = 0;
|
||||
/* FIXME Fix error handling. Check 'ret' before errno. EINTR? EAGAIN? */
|
||||
while (bytes < sizeof(*msg) && errno != EIO) {
|
||||
while (bytes < sizeof(*msg)) {
|
||||
do {
|
||||
/* Watch daemon write FIFO to be ready for output. */
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fifos->client, &fds);
|
||||
/* FIXME Check for errors e.g. EBADF */
|
||||
} while (select(fifos->client +1, NULL, &fds, NULL, NULL) != 1);
|
||||
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);
|
||||
bytes += ret > 0 ? ret : 0;
|
||||
if (ret < 0) {
|
||||
if ((errno == EINTR) || (errno == EAGAIN))
|
||||
continue;
|
||||
else {
|
||||
/* fixme: log error */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bytes += ret;
|
||||
}
|
||||
|
||||
return bytes == sizeof(*msg);
|
||||
@@ -132,11 +160,11 @@ static int daemon_talk(struct dm_event_fifos *fifos, struct dm_event_daemon_mess
|
||||
*/
|
||||
msg->opcode.cmd = cmd;
|
||||
|
||||
if (sizeof(msg->msg) <= snprintf(msg->msg, sizeof(msg->msg),
|
||||
"%s %s %u %"PRIu32,
|
||||
dso_name ? dso_name : "",
|
||||
device ? device : "",
|
||||
events, timeout)) {
|
||||
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;
|
||||
}
|
||||
@@ -178,8 +206,8 @@ static void daemon_running_signal_handler(int sig)
|
||||
static int start_daemon(void)
|
||||
{
|
||||
int pid, ret=0;
|
||||
int old_mask;
|
||||
void *old_hand;
|
||||
sigset_t set, oset;
|
||||
|
||||
/* Must be able to acquire signal */
|
||||
old_hand = signal(SIGUSR1, &daemon_running_signal_handler);
|
||||
@@ -188,12 +216,11 @@ static int start_daemon(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef linux
|
||||
/* FIXME Deprecated. Try posix sigprocmask instead. */
|
||||
old_mask = siggetmask();
|
||||
old_mask &= ~sigmask(SIGUSR1);
|
||||
old_mask = sigsetmask(old_mask);
|
||||
#endif
|
||||
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();
|
||||
|
||||
@@ -207,7 +234,6 @@ static int start_daemon(void)
|
||||
sleep(1);
|
||||
|
||||
if (daemon_running) {
|
||||
log_print("dmeventd started.\n");
|
||||
ret = 1;
|
||||
} else {
|
||||
switch (WEXITSTATUS(status)) {
|
||||
@@ -225,6 +251,13 @@ static int start_daemon(void)
|
||||
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 */
|
||||
|
||||
@@ -238,9 +271,11 @@ static int start_daemon(void)
|
||||
/* FIXME What if old_hand is SIG_ERR? */
|
||||
if (signal(SIGUSR1, old_hand) == SIG_ERR)
|
||||
log_error("Unable to reset signal handler.");
|
||||
sigsetmask(old_mask);
|
||||
|
||||
return ret;
|
||||
if (sigprocmask(SIG_SETMASK, &oset, NULL))
|
||||
log_error("Unable to reset signal mask.");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initialize client. */
|
||||
@@ -251,15 +286,15 @@ static int init_client(struct dm_event_fifos *fifos)
|
||||
|
||||
/* init fifos */
|
||||
memset(fifos, 0, sizeof(*fifos));
|
||||
fifos->client_path = DM_EVENT_FIFO_CLIENT;
|
||||
fifos->server_path = DM_EVENT_FIFO_SERVER;
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME Warn/abort if perms are wrong - not something to fix silently. */
|
||||
@@ -296,11 +331,11 @@ static int init_client(struct dm_event_fifos *fifos)
|
||||
}
|
||||
|
||||
/* Anyone listening? If not, errno will be ENXIO */
|
||||
if ((fifos->client = open(fifos->client_path,
|
||||
while ((fifos->client = open(fifos->client_path,
|
||||
O_WRONLY | O_NONBLOCK)) < 0) {
|
||||
if (errno != ENXIO) {
|
||||
log_error("%s: open client fifo %s\n",
|
||||
__func__, fifos->client_path);
|
||||
log_error("%s: Can't open client fifo %s: %s\n",
|
||||
__func__, fifos->client_path, strerror(errno));
|
||||
close(fifos->server);
|
||||
stack;
|
||||
return 0;
|
||||
@@ -311,17 +346,6 @@ static int init_client(struct dm_event_fifos *fifos)
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME Unnecessary if daemon was started before calling this */
|
||||
/* Daemon is started, retry the open */
|
||||
fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK);
|
||||
if (fifos->client < 0) {
|
||||
log_error("%s: open client fifo %s\n",
|
||||
__func__, fifos->client_path);
|
||||
close(fifos->server);
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -330,7 +354,7 @@ static int init_client(struct dm_event_fifos *fifos)
|
||||
static void dtr_client(struct dm_event_fifos *fifos)
|
||||
{
|
||||
if (flock(fifos->server, LOCK_UN))
|
||||
log_error("flock unlock %s\n", fifos->server_path);
|
||||
log_error("flock unlock %s\n", fifos->server_path);
|
||||
|
||||
close(fifos->client);
|
||||
close(fifos->server);
|
||||
@@ -363,12 +387,13 @@ static int do_event(int cmd, struct dm_event_daemon_message *msg,
|
||||
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? */
|
||||
@@ -377,29 +402,49 @@ static int do_event(int cmd, struct dm_event_daemon_message *msg,
|
||||
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)
|
||||
enum dm_event_type events)
|
||||
{
|
||||
int ret;
|
||||
struct dm_event_daemon_message msg;
|
||||
|
||||
if (!device_exists(device_path))
|
||||
return -ENODEV;
|
||||
if (!device_exists(device_path)) {
|
||||
log_error("%s: device not found", device_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg,
|
||||
dso_name, device_path, events, 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)
|
||||
enum dm_event_type events)
|
||||
{
|
||||
int ret;
|
||||
struct dm_event_daemon_message msg;
|
||||
|
||||
if (!device_exists(device_path))
|
||||
return -ENODEV;
|
||||
if (!device_exists(device_path)) {
|
||||
log_error("%s: device not found", device_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg,
|
||||
dso_name, device_path, events, 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,
|
||||
@@ -417,9 +462,9 @@ int dm_event_get_registered_device(char **dso_name, char **device_path,
|
||||
|
||||
if (next){
|
||||
if (*dso_name)
|
||||
free(*dso_name);
|
||||
dm_free(*dso_name);
|
||||
if (*device_path)
|
||||
free(*device_path);
|
||||
dm_free(*device_path);
|
||||
*dso_name = dso_name_arg;
|
||||
*device_path = device_path_arg;
|
||||
} else {
|
||||
|
@@ -82,6 +82,15 @@ enum dm_event_type {
|
||||
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,
|
||||
|
22
daemons/dmeventd/plugins/Makefile.in
Normal file
22
daemons/dmeventd/plugins/Makefile.in
Normal 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
|
||||
|
3
daemons/dmeventd/plugins/mirror/.exported_symbols
Normal file
3
daemons/dmeventd/plugins/mirror/.exported_symbols
Normal file
@@ -0,0 +1,3 @@
|
||||
process_event
|
||||
register_device
|
||||
unregister_device
|
36
daemons/dmeventd/plugins/mirror/Makefile.in
Normal file
36
daemons/dmeventd/plugins/mirror/Makefile.in
Normal 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)/$<
|
||||
|
246
daemons/dmeventd/plugins/mirror/dmeventd_mirror.c
Normal file
246
daemons/dmeventd/plugins/mirror/dmeventd_mirror.c
Normal 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, ¶ms);
|
||||
|
||||
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
22
dmeventd/Makefile.in
Normal 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
|
||||
|
3
dmeventd/mirror/.exported_symbols
Normal file
3
dmeventd/mirror/.exported_symbols
Normal file
@@ -0,0 +1,3 @@
|
||||
process_event
|
||||
register_device
|
||||
unregister_device
|
36
dmeventd/mirror/Makefile.in
Normal file
36
dmeventd/mirror/Makefile.in
Normal 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)/$<
|
||||
|
246
dmeventd/mirror/dmeventd_mirror.c
Normal file
246
dmeventd/mirror/dmeventd_mirror.c
Normal 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, ¶ms);
|
||||
|
||||
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:
|
||||
*/
|
@@ -289,4 +289,9 @@ activation {
|
||||
# dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ]
|
||||
#}
|
||||
|
||||
# Event daemon
|
||||
#
|
||||
#dmeventd {
|
||||
# mirror_library = "libdevmapper-event-lvm2mirror.so"
|
||||
#}
|
||||
|
||||
|
@@ -133,6 +133,10 @@ ifeq ("@HAVE_LIBDL@", "yes")
|
||||
misc/sharedlib.c
|
||||
endif
|
||||
|
||||
ifeq ("@DMEVENTD@", "yes")
|
||||
CLDFLAGS += -ldevmapper-event
|
||||
endif
|
||||
|
||||
LIB_STATIC = liblvm.a
|
||||
|
||||
$(SUBDIRS): $(LIB_STATIC)
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include "str_list.h"
|
||||
#include "config.h"
|
||||
#include "filter.h"
|
||||
#include "segtype.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <fcntl.h>
|
||||
@@ -75,6 +76,11 @@ int driver_version(char *version, size_t size)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return 0;
|
||||
@@ -170,8 +176,8 @@ void set_activation(int act)
|
||||
log_verbose("Activation enabled. Device-mapper kernel "
|
||||
"driver will be used.");
|
||||
else
|
||||
log_verbose("Activation disabled. No device-mapper "
|
||||
"interaction will be attempted.");
|
||||
log_print("WARNING: Activation disabled. No device-mapper "
|
||||
"interaction will be attempted.");
|
||||
}
|
||||
|
||||
int activation(void)
|
||||
@@ -277,7 +283,8 @@ int driver_version(char *version, size_t 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;
|
||||
struct dm_task *dmt;
|
||||
@@ -300,6 +307,9 @@ static int _target_present(const char *target_name)
|
||||
|
||||
if (!strcmp(target_name, target->name)) {
|
||||
r = 1;
|
||||
*maj = target->version[0];
|
||||
*min = target->version[1];
|
||||
*patchlevel = target->version[2];
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -314,6 +324,7 @@ static int _target_present(const char *target_name)
|
||||
|
||||
int target_present(const char *target_name, int use_modprobe)
|
||||
{
|
||||
uint32_t maj, min, patchlevel;
|
||||
#ifdef MODPROBE_CMD
|
||||
char module[128];
|
||||
#endif
|
||||
@@ -323,7 +334,7 @@ int target_present(const char *target_name, int use_modprobe)
|
||||
|
||||
#ifdef MODPROBE_CMD
|
||||
if (use_modprobe) {
|
||||
if (_target_present(target_name))
|
||||
if (target_version(target_name, &maj, &min, &patchlevel))
|
||||
return 1;
|
||||
|
||||
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
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
int error_if_not_suspended)
|
||||
{
|
||||
struct logical_volume *lv;
|
||||
struct logical_volume *lv, *lv_pre;
|
||||
struct lvinfo info;
|
||||
|
||||
if (!activation())
|
||||
return 1;
|
||||
|
||||
if (!(lv = lv_from_lvid(cmd, lvid_s, 0)))
|
||||
return_0;
|
||||
|
||||
/* Use precommitted metadata if present */
|
||||
if (!(lv = lv_from_lvid(cmd, lvid_s, 1)))
|
||||
return 0;
|
||||
if (!(lv_pre = lv_from_lvid(cmd, lvid_s, 1)))
|
||||
return_0;
|
||||
|
||||
if (test_mode()) {
|
||||
_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;
|
||||
|
||||
/* If VG was precommitted, preload devices for the LV */
|
||||
if ((lv->vg->status & PRECOMMITTED)) {
|
||||
if (!_lv_preload(lv)) {
|
||||
if ((lv_pre->vg->status & PRECOMMITTED)) {
|
||||
if (!_lv_preload(lv_pre)) {
|
||||
/* FIXME Revert preloading */
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_register_dev_for_events(cmd, lv, 0))
|
||||
stack;
|
||||
|
||||
memlock_inc();
|
||||
if (!_lv_suspend_lv(lv)) {
|
||||
memlock_dec();
|
||||
@@ -645,6 +694,9 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
||||
memlock_dec();
|
||||
fs_unlock();
|
||||
|
||||
if (!_register_dev_for_events(cmd, lv, 1))
|
||||
stack;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -688,6 +740,9 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_register_dev_for_events(cmd, lv, 0))
|
||||
stack;
|
||||
|
||||
memlock_inc();
|
||||
r = _lv_deactivate(lv);
|
||||
memlock_dec();
|
||||
@@ -758,6 +813,9 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
memlock_dec();
|
||||
fs_unlock();
|
||||
|
||||
if (!_register_dev_for_events(cmd, lv, 1))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@@ -37,6 +37,8 @@ int library_version(char *version, size_t size);
|
||||
int lvm1_present(struct cmd_context *cmd);
|
||||
|
||||
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);
|
||||
|
||||
|
@@ -977,6 +977,8 @@ static int _tree_action(struct dev_manager *dm, struct logical_volume *lv, actio
|
||||
goto_out;
|
||||
break;
|
||||
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))
|
||||
goto_out;
|
||||
break;
|
||||
|
@@ -34,6 +34,8 @@
|
||||
#define DEFAULT_LOCK_DIR "/var/lock/lvm"
|
||||
#define DEFAULT_LOCKING_LIB "lvm2_locking.so"
|
||||
|
||||
#define DEFAULT_DMEVENTD_MIRROR_LIB "libdevmapper-event-lvm2mirror.so"
|
||||
|
||||
#define DEFAULT_UMASK 0077
|
||||
|
||||
#ifdef LVM1_FALLBACK
|
||||
|
@@ -140,7 +140,12 @@ static int _fill_maps(struct dm_hash_table *maps, struct volume_group *vg,
|
||||
lvm = lvms[lv_num];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@@ -717,7 +717,7 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
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;
|
||||
max_parallel = (spvs->le + spvs->len - next_le) * ah->area_multiple;
|
||||
parallel_pvs = &spvs->pvs;
|
||||
break;
|
||||
}
|
||||
|
@@ -78,6 +78,12 @@ struct segtype_handler {
|
||||
uint64_t *total_denominator, float *percent);
|
||||
int (*target_present) (void);
|
||||
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,
|
||||
|
@@ -25,6 +25,13 @@
|
||||
#include "lvm-string.h"
|
||||
#include "targets.h"
|
||||
#include "activate.h"
|
||||
#include "sharedlib.h"
|
||||
|
||||
#ifdef DMEVENTD
|
||||
# include <libdevmapper-event.h>
|
||||
#endif
|
||||
|
||||
static int _block_on_error_available = 0;
|
||||
|
||||
enum {
|
||||
MIRR_DISABLED,
|
||||
@@ -221,6 +228,7 @@ static int _add_log(struct dev_manager *dm, struct lv_segment *seg,
|
||||
{
|
||||
unsigned clustered = 0;
|
||||
char *log_dlid = NULL;
|
||||
uint32_t log_flags = 0;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/* FIXME Add sync parm? */
|
||||
return dm_tree_node_add_mirror_target_log(node, region_size, clustered, log_dlid, area_count);
|
||||
if (_block_on_error_available && !(seg->status & PVMOVE))
|
||||
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,
|
||||
@@ -316,15 +326,115 @@ static int _target_present(void)
|
||||
{
|
||||
static int checked = 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);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -341,6 +451,10 @@ static struct segtype_handler _mirrored_ops = {
|
||||
add_target_line:_add_target_line,
|
||||
target_percent:_target_percent,
|
||||
target_present:_target_present,
|
||||
#ifdef DMEVENTD
|
||||
target_register_events:_target_register_events,
|
||||
target_unregister_events:_target_unregister_events,
|
||||
#endif
|
||||
#endif
|
||||
destroy:_destroy,
|
||||
};
|
||||
|
@@ -22,8 +22,8 @@
|
||||
#include <sys/stat.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
static void _get_library_path(struct config_tree *cft, const char *libname,
|
||||
char *path, int path_len)
|
||||
void get_shared_library_path(struct config_tree *cft, const char *libname,
|
||||
char *path, int path_len)
|
||||
{
|
||||
struct stat info;
|
||||
const char *lib_dir;
|
||||
@@ -43,7 +43,7 @@ void *load_shared_library(struct config_tree *cft, const char *libname,
|
||||
char path[PATH_MAX];
|
||||
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);
|
||||
|
||||
|
@@ -16,5 +16,7 @@
|
||||
#include "config.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,
|
||||
const char *what);
|
||||
|
@@ -2,6 +2,7 @@ dm_lib_release
|
||||
dm_lib_exit
|
||||
dm_driver_version
|
||||
dm_get_library_version
|
||||
dm_log
|
||||
dm_log_init
|
||||
dm_log_init_verbose
|
||||
dm_task_create
|
||||
@@ -22,6 +23,9 @@ dm_task_set_major
|
||||
dm_task_set_minor
|
||||
dm_task_set_sector
|
||||
dm_task_set_message
|
||||
dm_task_set_uid
|
||||
dm_task_set_gid
|
||||
dm_task_set_mode
|
||||
dm_task_suppress_identical_reload
|
||||
dm_task_add_target
|
||||
dm_task_no_open_count
|
||||
@@ -60,11 +64,12 @@ dm_tree_node_add_striped_target
|
||||
dm_tree_node_add_mirror_target
|
||||
dm_tree_node_add_mirror_target_log
|
||||
dm_tree_node_add_target_area
|
||||
dm_tree_skip_lockfs
|
||||
dm_is_dm_major
|
||||
dm_mknodes
|
||||
dm_malloc_aux
|
||||
dm_malloc_aux_debug
|
||||
dm_strdup
|
||||
dm_strdup_aux
|
||||
dm_free_aux
|
||||
dm_realloc_aux
|
||||
dm_dump_memory_debug
|
||||
@@ -103,3 +108,4 @@ dm_hash_get_data
|
||||
dm_hash_get_first
|
||||
dm_hash_get_next
|
||||
dm_set_selinux_context
|
||||
dm_task_set_geometry
|
||||
|
@@ -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)
|
||||
{
|
||||
while (bit < DM_BITS_PER_INT) {
|
||||
while (bit < (int) DM_BITS_PER_INT) {
|
||||
if (test & (0x1 << bit))
|
||||
return 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 */
|
||||
|
||||
while (last_bit < bs[0]) {
|
||||
/*
|
||||
* bs[0] holds number of bits
|
||||
*/
|
||||
while (last_bit < (int) bs[0]) {
|
||||
word = last_bit >> INT_SHIFT;
|
||||
test = bs[word + 1];
|
||||
bit = last_bit & (DM_BITS_PER_INT - 1);
|
||||
|
@@ -18,13 +18,13 @@
|
||||
struct dm_hash_node {
|
||||
struct dm_hash_node *next;
|
||||
void *data;
|
||||
int keylen;
|
||||
unsigned keylen;
|
||||
char key[0];
|
||||
};
|
||||
|
||||
struct dm_hash_table {
|
||||
int num_nodes;
|
||||
int num_slots;
|
||||
unsigned num_nodes;
|
||||
unsigned num_slots;
|
||||
struct dm_hash_node **slots;
|
||||
};
|
||||
|
||||
@@ -56,7 +56,7 @@ static unsigned char _nums[] = {
|
||||
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);
|
||||
|
||||
@@ -68,13 +68,14 @@ static struct dm_hash_node *_create_node(const char *str, int len)
|
||||
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++) {
|
||||
h <<= 4;
|
||||
h += _nums[(int) *str++];
|
||||
h += _nums[*str++];
|
||||
g = h & ((unsigned long) 0xf << 16u);
|
||||
if (g) {
|
||||
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)
|
||||
{
|
||||
struct dm_hash_node *c, *n;
|
||||
int i;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < t->num_slots; i++)
|
||||
for (c = t->slots[i]; c; c = n) {
|
||||
@@ -136,8 +137,8 @@ void dm_hash_destroy(struct dm_hash_table *t)
|
||||
dm_free(t);
|
||||
}
|
||||
|
||||
static inline struct dm_hash_node **_find(struct dm_hash_table *t, const char *key,
|
||||
uint32_t len)
|
||||
static struct dm_hash_node **_find(struct dm_hash_table *t, const char *key,
|
||||
uint32_t len)
|
||||
{
|
||||
unsigned h = _hash(key, len) & (t->num_slots - 1);
|
||||
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)
|
||||
{
|
||||
struct dm_hash_node **c = _find(t, key, len);
|
||||
|
||||
return *c ? (*c)->data : 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
struct dm_hash_node *c;
|
||||
int i;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < t->num_slots; i++)
|
||||
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);
|
||||
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)
|
||||
@@ -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)
|
||||
{
|
||||
struct dm_hash_node *c = NULL;
|
||||
int i;
|
||||
unsigned i;
|
||||
|
||||
for (i = s; i < t->num_slots && !c; 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)
|
||||
{
|
||||
unsigned h = _hash(n->key, n->keylen) & (t->num_slots - 1);
|
||||
|
||||
return n->next ? n->next : _next_slot(t, h + 1);
|
||||
}
|
||||
|
@@ -116,6 +116,7 @@ static struct cmd_data _cmd_data_v1[] = {
|
||||
{ "mknodes", 0, {4, 0, 0} },
|
||||
{ "versions", 0, {4, 1, 0} },
|
||||
{ "message", 0, {4, 2, 0} },
|
||||
{ "setgeometry",0, {4, 6, 0} },
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
|
@@ -103,6 +103,9 @@ static struct cmd_data _cmd_data_v4[] = {
|
||||
#ifdef DM_TARGET_MSG
|
||||
{"message", DM_TARGET_MSG, {4, 2, 0}},
|
||||
#endif
|
||||
#ifdef DM_DEV_SET_GEOMETRY
|
||||
{"setgeometry", DM_DEV_SET_GEOMETRY, {4, 6, 0}},
|
||||
#endif
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
@@ -877,7 +880,7 @@ int dm_format_dev(char *buf, int bufsize, uint32_t dev_major,
|
||||
if (bufsize < 8)
|
||||
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)
|
||||
return 0;
|
||||
|
||||
@@ -1001,6 +1004,23 @@ int dm_task_set_sector(struct dm_task *dmt, uint64_t sector)
|
||||
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)
|
||||
{
|
||||
dmt->no_open_count = 1;
|
||||
@@ -1028,7 +1048,8 @@ struct target *create_target(uint64_t start, uint64_t len, const char *type,
|
||||
struct target *t = dm_malloc(sizeof(*t));
|
||||
|
||||
if (!t) {
|
||||
log_error("create_target: malloc(%d) failed", sizeof(*t));
|
||||
log_error("create_target: malloc(%" PRIsize_t ") failed",
|
||||
sizeof(*t));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1122,11 +1143,26 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (count && dmt->geometry) {
|
||||
log_error("targets and geometry are incompatible");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dmt->newname && (dmt->sector || dmt->message)) {
|
||||
log_error("message and newname are incompatible");
|
||||
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) {
|
||||
log_error("message is required with sector");
|
||||
return NULL;
|
||||
@@ -1138,6 +1174,9 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
||||
if (dmt->message)
|
||||
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
|
||||
* dependencies or status information.
|
||||
@@ -1204,6 +1243,9 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
||||
strcpy(tmsg->message, dmt->message);
|
||||
}
|
||||
|
||||
if (dmt->geometry)
|
||||
strcpy(b, dmt->geometry);
|
||||
|
||||
return dmi;
|
||||
|
||||
bad:
|
||||
@@ -1310,6 +1352,9 @@ static int _create_and_load_v4(struct dm_task *dmt)
|
||||
|
||||
task->major = dmt->major;
|
||||
task->minor = dmt->minor;
|
||||
task->uid = dmt->uid;
|
||||
task->gid = dmt->gid;
|
||||
task->mode = dmt->mode;
|
||||
|
||||
r = dm_task_run(task);
|
||||
dm_task_destroy(task);
|
||||
@@ -1434,7 +1479,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
||||
if (dmt->no_open_count)
|
||||
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]",
|
||||
_cmd_data_v4[dmt->type].name,
|
||||
dmi->name, dmi->uuid, dmt->newname ? " " : "",
|
||||
|
@@ -50,6 +50,7 @@ struct dm_task {
|
||||
} dmi;
|
||||
char *newname;
|
||||
char *message;
|
||||
char *geometry;
|
||||
uint64_t sector;
|
||||
int no_open_count;
|
||||
int skip_lockfs;
|
||||
|
@@ -42,7 +42,8 @@
|
||||
*/
|
||||
|
||||
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
|
||||
@@ -79,7 +80,9 @@ enum {
|
||||
|
||||
DM_DEVICE_LIST_VERSIONS,
|
||||
|
||||
DM_DEVICE_TARGET_MSG
|
||||
DM_DEVICE_TARGET_MSG,
|
||||
|
||||
DM_DEVICE_SET_GEOMETRY
|
||||
};
|
||||
|
||||
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_minor(struct dm_task *dmt, int minor);
|
||||
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_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_sector(struct dm_task *dmt, uint64_t sector);
|
||||
int dm_task_no_open_count(struct dm_task *dmt);
|
||||
@@ -299,6 +306,13 @@ int dm_tree_suspend_children(struct dm_tree_node *dnode,
|
||||
const char *uuid_prefix,
|
||||
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?
|
||||
* Only returns 0 if every node was checked successfully.
|
||||
@@ -331,11 +345,18 @@ int dm_tree_node_add_striped_target(struct dm_tree_node *node,
|
||||
uint32_t stripe_size);
|
||||
int dm_tree_node_add_mirror_target(struct dm_tree_node *node,
|
||||
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,
|
||||
uint32_t region_size,
|
||||
unsigned clustered,
|
||||
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,
|
||||
const char *dev_name,
|
||||
const char *dlid,
|
||||
@@ -349,10 +370,9 @@ int dm_tree_node_add_target_area(struct dm_tree_node *node,
|
||||
* Memory management
|
||||
*******************/
|
||||
|
||||
char *dm_strdup(const char *str);
|
||||
|
||||
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);
|
||||
char *dm_strdup_aux(const char *str);
|
||||
void dm_free_aux(void *p);
|
||||
void *dm_realloc_aux(void *p, unsigned int s, const char *file, int line);
|
||||
int dm_dump_memory_debug(void);
|
||||
@@ -361,6 +381,7 @@ void dm_bounds_check_debug(void);
|
||||
#ifdef DEBUG_MEM
|
||||
|
||||
# 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_realloc(p, s) dm_realloc_aux(p, s, __FILE__, __LINE__)
|
||||
# define dm_dump_memory() dm_dump_memory_debug()
|
||||
@@ -369,6 +390,7 @@ void dm_bounds_check_debug(void);
|
||||
#else
|
||||
|
||||
# define dm_malloc(s) dm_malloc_aux((s), __FILE__, __LINE__)
|
||||
# define dm_strdup(s) strdup(s)
|
||||
# define dm_free(p) free(p)
|
||||
# define dm_realloc(p, s) realloc(p, s)
|
||||
# define dm_dump_memory() {}
|
||||
@@ -509,6 +531,17 @@ int dm_bit_get_next(dm_bitset_t bs, int last_bit);
|
||||
#define dm_bit_copy(bs1, bs2) \
|
||||
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
|
||||
****************/
|
||||
@@ -543,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; \
|
||||
v = dm_hash_get_next(h, v))
|
||||
|
||||
#endif /* LIB_DEVICE_MAPPER_H */
|
||||
|
||||
/*********
|
||||
* selinux
|
||||
*********/
|
||||
int dm_set_selinux_context(const char *path, mode_t mode);
|
||||
|
||||
#endif /* LIB_DEVICE_MAPPER_H */
|
||||
|
@@ -61,14 +61,14 @@ static void _default_log(int level, const char *file, int line,
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
dm_log_fn _log = _default_log;
|
||||
dm_log_fn dm_log = _default_log;
|
||||
|
||||
void dm_log_init(dm_log_fn fn)
|
||||
{
|
||||
if (fn)
|
||||
_log = fn;
|
||||
dm_log = fn;
|
||||
else
|
||||
_log = _default_log;
|
||||
dm_log = _default_log;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -180,6 +181,27 @@ int dm_task_set_minor(struct dm_task *dmt, int minor)
|
||||
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,
|
||||
const char *ttype, const char *params)
|
||||
{
|
||||
@@ -488,3 +510,4 @@ out:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@@ -85,6 +85,8 @@ struct load_segment {
|
||||
uint32_t region_size; /* Mirror */
|
||||
unsigned clustered; /* Mirror */
|
||||
unsigned mirror_area_count; /* Mirror */
|
||||
uint32_t flags; /* Mirror log */
|
||||
char *uuid; /* Clustered mirror log */
|
||||
};
|
||||
|
||||
/* Per-device properties */
|
||||
@@ -127,6 +129,7 @@ struct dm_tree {
|
||||
struct dm_hash_table *devs;
|
||||
struct dm_hash_table *uuids;
|
||||
struct dm_tree_node root;
|
||||
int skip_lockfs; /* 1 skips lockfs (for non-snapshots) */
|
||||
};
|
||||
|
||||
/* 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);
|
||||
va_end(ap);
|
||||
|
||||
if (n < 0 || (n > bufsize - 1))
|
||||
if (n < 0 || (n > (int) bufsize - 1))
|
||||
return -1;
|
||||
|
||||
return n;
|
||||
@@ -158,6 +161,7 @@ struct dm_tree *dm_tree_create(void)
|
||||
dtree->root.dtree = dtree;
|
||||
list_init(&dtree->root.uses);
|
||||
list_init(&dtree->root.used_by);
|
||||
dtree->skip_lockfs = 0;
|
||||
|
||||
if (!(dtree->mem = dm_pool_create("dtree", 1024))) {
|
||||
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,
|
||||
struct dm_info *newinfo)
|
||||
int skip_lockfs, struct dm_info *newinfo)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
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))) {
|
||||
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))
|
||||
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)))
|
||||
r = dm_task_get_info(dmt, newinfo);
|
||||
|
||||
@@ -978,6 +986,11 @@ int dm_tree_deactivate_children(struct dm_tree_node *dnode,
|
||||
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,
|
||||
const char *uuid_prefix,
|
||||
size_t uuid_prefix_len)
|
||||
@@ -1018,7 +1031,8 @@ int dm_tree_suspend_children(struct dm_tree_node *dnode,
|
||||
!info.exists)
|
||||
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
|
||||
":%" PRIu32 ")", name, info.major,
|
||||
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)
|
||||
{
|
||||
unsigned log_parm_count;
|
||||
int pos = 0;
|
||||
int tw;
|
||||
int r;
|
||||
char originbuf[10], cowbuf[10], logbuf[10];
|
||||
const char *logtype;
|
||||
|
||||
switch(seg->type) {
|
||||
case SEG_ERROR:
|
||||
@@ -1223,33 +1239,84 @@ static int _emit_segment_line(struct dm_task *dmt, struct load_segment *seg, uin
|
||||
case SEG_LINEAR:
|
||||
break;
|
||||
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 ((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 */
|
||||
return -1;
|
||||
}
|
||||
pos += tw;
|
||||
}
|
||||
if (!seg->log) {
|
||||
if ((tw = _dm_snprintf(params + pos, paramsize - pos, "core 1 ")) < 0) {
|
||||
stack; /* Out of space */
|
||||
return -1;
|
||||
}
|
||||
pos += tw;
|
||||
} else {
|
||||
|
||||
if (!seg->log)
|
||||
logtype = "core";
|
||||
else {
|
||||
logtype = "disk";
|
||||
log_parm_count++;
|
||||
if (!_build_dev_string(logbuf, sizeof(logbuf), seg->log))
|
||||
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 */
|
||||
return -1;
|
||||
}
|
||||
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 */
|
||||
return -1;
|
||||
}
|
||||
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;
|
||||
case SEG_SNAPSHOT:
|
||||
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,
|
||||
unsigned clustered,
|
||||
const char *log_uuid,
|
||||
unsigned area_count)
|
||||
unsigned area_count,
|
||||
uint32_t flags)
|
||||
{
|
||||
struct dm_tree_node *log_node = NULL;
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_link_tree_nodes(node, log_node))
|
||||
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->region_size = region_size;
|
||||
seg->clustered = clustered;
|
||||
seg->mirror_area_count = area_count;
|
||||
seg->flags = flags;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@@ -20,10 +20,6 @@
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#ifdef linux
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
|
||||
static int _create_dir_recursive(const char *dir)
|
||||
{
|
||||
char *orig, *s;
|
||||
@@ -31,7 +27,7 @@ static int _create_dir_recursive(const char *dir)
|
||||
|
||||
log_verbose("Creating directory \"%s\"", dir);
|
||||
/* Create parent directories */
|
||||
orig = s = strdup(dir);
|
||||
orig = s = dm_strdup(dir);
|
||||
while ((s = strchr(s, '/')) != NULL) {
|
||||
*s = '\0';
|
||||
if (*orig) {
|
||||
@@ -39,13 +35,13 @@ static int _create_dir_recursive(const char *dir)
|
||||
if (rc < 0 && errno != EEXIST) {
|
||||
log_error("%s: mkdir failed: %s", orig,
|
||||
strerror(errno));
|
||||
free(orig);
|
||||
dm_free(orig);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*s++ = '/';
|
||||
}
|
||||
free(orig);
|
||||
dm_free(orig);
|
||||
|
||||
/* Create final directory */
|
||||
rc = mkdir(dir, 0777);
|
||||
|
@@ -18,7 +18,7 @@
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
char *dm_strdup(const char *str)
|
||||
char *dm_strdup_aux(const char *str)
|
||||
{
|
||||
char *ret = dm_malloc(strlen(str) + 1);
|
||||
|
||||
@@ -198,9 +198,9 @@ int dm_dump_memory_debug(void)
|
||||
}
|
||||
str[sizeof(str) - 1] = '\0';
|
||||
|
||||
_log(_LOG_INFO, mb->file, mb->line,
|
||||
"block %d at %p, size %" PRIsize_t "\t [%s]",
|
||||
mb->id, mb->magic, mb->length, str);
|
||||
dm_log(_LOG_INFO, mb->file, mb->line,
|
||||
"block %d at %p, size %" PRIsize_t "\t [%s]",
|
||||
mb->id, mb->magic, mb->length, str);
|
||||
tot += mb->length;
|
||||
}
|
||||
|
||||
|
@@ -85,7 +85,7 @@ void *dm_pool_alloc_aligned(struct dm_pool *p, size_t s, unsigned alignment)
|
||||
/* have we got room ? */
|
||||
if (!c || (c->begin > c->end) || (c->end - c->begin < s)) {
|
||||
/* 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) ?
|
||||
needed : p->chunk_size);
|
||||
|
||||
|
22
make.tmpl.in
22
make.tmpl.in
@@ -27,11 +27,9 @@ LIBS = @LIBS@
|
||||
CFLAGS += @DEFS@
|
||||
CFLAGS += @CFLAGS@
|
||||
CLDFLAGS += @CLDFLAGS@
|
||||
CLDWHOLEARCHIVE += @CLDWHOLEARCHIVE@
|
||||
CLDNOWHOLEARCHIVE += @CLDNOWHOLEARCHIVE@
|
||||
LDDEPS += @LDDEPS@
|
||||
LDFLAGS += @LDFLAGS@
|
||||
SOFLAG += @SOFLAG@
|
||||
LIB_SUFFIX = @LIB_SUFFIX@
|
||||
|
||||
# Setup directory variables
|
||||
prefix = @prefix@
|
||||
@@ -56,7 +54,7 @@ ifndef MAKEFLAGS
|
||||
MAKEFLAGS = @JOBS@
|
||||
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
|
||||
|
||||
@@ -151,9 +149,21 @@ $(TARGETS): $(OBJECTS)
|
||||
%.so: %.o
|
||||
$(CC) -c $(INCLUDES) $(CFLAGS) $< -o $@
|
||||
|
||||
ifeq ("@LIB_SUFFIX@","so")
|
||||
$(LIB_SHARED): $(OBJECTS) $(LDDEPS)
|
||||
$(CC) $(SOFLAG) -Wl,-soname,$(notdir $@).$(LIB_VERSION) \
|
||||
$(CLDFLAGS) $(OBJECTS) -o $@
|
||||
$(CC) -shared -Wl,-soname,$(notdir $@).$(LIB_VERSION) \
|
||||
$(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)
|
||||
$(RM) $@
|
||||
|
@@ -43,8 +43,8 @@ The values are:
|
||||
Display the mapping of logical extents to physical volumes and
|
||||
physical extents.
|
||||
.SH Examples
|
||||
"lvdisplay -v /dev/vg00/lvol2" shows attributes of that logical volume
|
||||
and its mapping of logical to physical extents. In case snapshot
|
||||
"lvdisplay -v /dev/vg00/lvol2" shows attributes of that logical volume.
|
||||
If snapshot
|
||||
logical volumes have been created for this original logical volume,
|
||||
this command shows a list of all snapshot logical volumes and their
|
||||
status (active or inactive) as well.
|
||||
|
@@ -87,6 +87,10 @@ ifeq ("@CMDLIB@", "yes")
|
||||
INSTALL_TARGETS += $(INSTALL_CMDLIB_TARGETS)
|
||||
endif
|
||||
|
||||
ifeq ("@DMEVENTD@", "yes")
|
||||
LVMLIBS += -ldevmapper-event -lpthread
|
||||
endif
|
||||
|
||||
ifeq ("@DEVMAPPER@", "yes")
|
||||
LVMLIBS += -ldevmapper
|
||||
endif
|
||||
@@ -107,8 +111,6 @@ liblvm2cmd.a: $(top_srcdir)/lib/liblvm.a $(OBJECTS)
|
||||
$(AR) rs $@ $(OBJECTS)
|
||||
|
||||
liblvm2cmd.so: liblvm2cmd.a $(LDDEPS)
|
||||
$(CC) -o liblvm2cmd.so $(SOFLAG) $(CLDFLAGS) \
|
||||
$(CLDWHOLEARCHIVE) liblvm2cmd.a $(CLDNOWHOLEARCHIVE)
|
||||
|
||||
.commands: commands.h cmdnames.h Makefile
|
||||
$(CC) -E -P cmdnames.h 2> /dev/null | \
|
||||
|
@@ -44,6 +44,7 @@ arg(minor_ARG, '\0', "minor", minor_arg)
|
||||
arg(type_ARG, '\0', "type", segtype_arg)
|
||||
arg(alloc_ARG, '\0', "alloc", alloc_arg)
|
||||
arg(separator_ARG, '\0', "separator", string_arg)
|
||||
arg(mirrorsonly_ARG, '\0', "mirrorsonly", NULL)
|
||||
|
||||
/* Allow some variations */
|
||||
arg(resizable_ARG, '\0', "resizable", yes_no_arg)
|
||||
|
@@ -770,6 +770,7 @@ xx(vgreduce,
|
||||
"\t[-A|--autobackup y|n]\n"
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-h|--help]\n"
|
||||
"\t[--mirrorsonly]\n"
|
||||
"\t[--removemissing]\n"
|
||||
"\t[-t|--test]\n"
|
||||
"\t[-v|--verbose]\n"
|
||||
@@ -777,7 +778,7 @@ xx(vgreduce,
|
||||
"\tVolumeGroupName\n"
|
||||
"\t[PhysicalVolumePath...]\n",
|
||||
|
||||
all_ARG, autobackup_ARG, removemissing_ARG, test_ARG)
|
||||
all_ARG, autobackup_ARG, mirrorsonly_ARG, removemissing_ARG, test_ARG)
|
||||
|
||||
xx(vgremove,
|
||||
"Remove volume group(s)",
|
||||
|
@@ -86,8 +86,10 @@ enum {
|
||||
READ_ONLY = 0,
|
||||
COLS_ARG,
|
||||
EXEC_ARG,
|
||||
GID_ARG,
|
||||
MAJOR_ARG,
|
||||
MINOR_ARG,
|
||||
MODE_ARG,
|
||||
NOHEADINGS_ARG,
|
||||
NOLOCKFS_ARG,
|
||||
NOOPENCOUNT_ARG,
|
||||
@@ -95,6 +97,7 @@ enum {
|
||||
OPTIONS_ARG,
|
||||
TARGET_ARG,
|
||||
TREE_ARG,
|
||||
UID_ARG,
|
||||
UUID_ARG,
|
||||
VERBOSE_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]))
|
||||
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))
|
||||
goto out;
|
||||
|
||||
@@ -438,7 +450,8 @@ static int _rename(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;
|
||||
char *str;
|
||||
|
||||
@@ -455,7 +468,7 @@ static int _message(int argc, char **argv, void *data)
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (!dm_task_set_sector(dmt, atoll(argv[1])))
|
||||
if (!dm_task_set_sector(dmt, (uint64_t) atoll(argv[1])))
|
||||
goto out;
|
||||
|
||||
argc -= 2;
|
||||
@@ -495,6 +508,39 @@ static int _message(int argc, char **argv, void *data)
|
||||
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)
|
||||
{
|
||||
char version[80];
|
||||
@@ -502,7 +548,7 @@ static int _version(int argc, char **argv, void *data)
|
||||
if (dm_get_library_version(version, sizeof(version)))
|
||||
printf("Library version: %s\n", version);
|
||||
|
||||
if (dm_driver_version(version, sizeof(version)))
|
||||
if (!dm_driver_version(version, sizeof(version)))
|
||||
return 0;
|
||||
|
||||
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,
|
||||
(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,
|
||||
@@ -622,7 +668,7 @@ static int _process_all(int argc, char **argv,
|
||||
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;
|
||||
|
||||
@@ -635,7 +681,7 @@ static int _mknodes(int argc, char **argv, void *data)
|
||||
return dm_mknodes(argc > 1 ? argv[1] : NULL);
|
||||
}
|
||||
|
||||
static int _exec_command(char *name)
|
||||
static int _exec_command(const char *name)
|
||||
{
|
||||
int n;
|
||||
static char path[PATH_MAX];
|
||||
@@ -651,7 +697,7 @@ static int _exec_command(char *name)
|
||||
return 0;
|
||||
|
||||
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;
|
||||
|
||||
if (!argc) {
|
||||
@@ -704,7 +750,7 @@ static int _status(int argc, char **argv, void *data)
|
||||
char *params;
|
||||
int cmd;
|
||||
struct dm_names *names = (struct dm_names *) data;
|
||||
char *name = NULL;
|
||||
const char *name = NULL;
|
||||
int matched = 0;
|
||||
int ls_only = 0;
|
||||
struct dm_info info;
|
||||
@@ -742,7 +788,7 @@ static int _status(int argc, char **argv, void *data)
|
||||
goto out;
|
||||
|
||||
if (!name)
|
||||
name = (char *) dm_task_get_name(dmt);
|
||||
name = dm_task_get_name(dmt);
|
||||
|
||||
/* Fetch targets and print 'em */
|
||||
do {
|
||||
@@ -1292,6 +1338,7 @@ struct command {
|
||||
|
||||
static struct command _commands[] = {
|
||||
{"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>]",
|
||||
1, 2, _create},
|
||||
{"remove", "<device>", 0, 1, _remove},
|
||||
@@ -1312,6 +1359,7 @@ static struct command _commands[] = {
|
||||
{"mknodes", "[<device>]", 0, 1, _mknodes},
|
||||
{"targets", "", 0, 0, _targets},
|
||||
{"version", "", 0, 0, _version},
|
||||
{"setgeometry", "<device> <cyl> <head> <sect> <start>", 5, 5, _setgeometry},
|
||||
{NULL, NULL, 0, 0, NULL}
|
||||
};
|
||||
|
||||
@@ -1418,8 +1466,10 @@ static int _process_switches(int *argc, char ***argv)
|
||||
{"readonly", 0, &ind, READ_ONLY},
|
||||
{"columns", 0, &ind, COLS_ARG},
|
||||
{"exec", 1, &ind, EXEC_ARG},
|
||||
{"gid", 1, &ind, GID_ARG},
|
||||
{"major", 1, &ind, MAJOR_ARG},
|
||||
{"minor", 1, &ind, MINOR_ARG},
|
||||
{"mode", 1, &ind, MODE_ARG},
|
||||
{"noheadings", 0, &ind, NOHEADINGS_ARG},
|
||||
{"nolockfs", 0, &ind, NOLOCKFS_ARG},
|
||||
{"noopencount", 0, &ind, NOOPENCOUNT_ARG},
|
||||
@@ -1427,6 +1477,7 @@ static int _process_switches(int *argc, char ***argv)
|
||||
{"options", 1, &ind, OPTIONS_ARG},
|
||||
{"target", 1, &ind, TARGET_ARG},
|
||||
{"tree", 0, &ind, TREE_ARG},
|
||||
{"uid", 1, &ind, UID_ARG},
|
||||
{"uuid", 1, &ind, UUID_ARG},
|
||||
{"verbose", 1, &ind, VERBOSE_ARG},
|
||||
{"version", 0, &ind, VERSION_ARG},
|
||||
@@ -1478,7 +1529,7 @@ static int _process_switches(int *argc, char ***argv)
|
||||
|
||||
optarg = 0;
|
||||
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) {
|
||||
if (c == 'c' || c == 'C' || ind == COLS_ARG)
|
||||
_switches[COLS_ARG]++;
|
||||
@@ -1504,6 +1555,19 @@ static int _process_switches(int *argc, char ***argv)
|
||||
_switches[UUID_ARG]++;
|
||||
_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)) {
|
||||
_switches[EXEC_ARG]++;
|
||||
_command = optarg;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
@@ -21,6 +21,9 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
struct lvinfo info;
|
||||
int lv_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;
|
||||
|
||||
@@ -29,8 +32,27 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
!(lv_is_cow(lv)))
|
||||
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! */
|
||||
if (lv_info(cmd, lv, &info, 0) && info.exists)
|
||||
if (inkernel && snap_active)
|
||||
active_str = "ACTIVE ";
|
||||
else
|
||||
active_str = "inactive ";
|
||||
|
@@ -78,7 +78,7 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name)
|
||||
}
|
||||
|
||||
if (!dev) {
|
||||
log_error("Device %s not found.", name);
|
||||
log_error("Device %s not found (or ignored by filtering).", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
213
tools/vgreduce.c
213
tools/vgreduce.c
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "tools.h"
|
||||
#include "lv_alloc.h"
|
||||
|
||||
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,
|
||||
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 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 "
|
||||
"dependencies)", lv->vg->name, lv->name);
|
||||
|
||||
/* Deactivate if necessary */
|
||||
if (!lv_is_cow(lv)) {
|
||||
log_verbose("Deactivating (if active) logical volume %s",
|
||||
lv->name);
|
||||
/* FIXME Cope properly with stacked devices & snapshots. */
|
||||
|
||||
if (!deactivate_lv(cmd, lv)) {
|
||||
log_error("Failed to deactivate LV %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
} else if ((snap_seg = find_cow(lv))) {
|
||||
/* If snapshot device is missing, deactivate origin. */
|
||||
if (lv_is_cow(lv) && (snap_seg = find_cow(lv))) {
|
||||
log_verbose("Deactivating (if active) logical volume %s "
|
||||
"(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",
|
||||
snap_seg->origin->name);
|
||||
return 0;
|
||||
@@ -85,6 +84,13 @@ static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
origin_list);
|
||||
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! */
|
||||
if (!vg_remove_snapshot(cow)) {
|
||||
stack;
|
||||
@@ -96,13 +102,46 @@ static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
first = 0;
|
||||
}
|
||||
|
||||
/* Remove the LV itself */
|
||||
log_verbose("Removing LV %s from VG %s", lv->name, lv->vg->name);
|
||||
if (!lv_remove(lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
/*
|
||||
* If LV is active, replace it with error segment
|
||||
* and add to list of LVs to be removed later.
|
||||
* Doesn't apply to snapshots/origins yet - they're already deactivated.
|
||||
*/
|
||||
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;
|
||||
@@ -113,11 +152,16 @@ static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
|
||||
struct list *pvh, *pvht;
|
||||
struct list *lvh, *lvht;
|
||||
struct pv_list *pvl;
|
||||
struct lv_list *lvl, *lvl2, *lvlt;
|
||||
struct logical_volume *lv;
|
||||
struct physical_volume *pv;
|
||||
struct lv_segment *seg;
|
||||
struct lv_segment *seg, *mirrored_seg;
|
||||
struct lv_segment_area area;
|
||||
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 */
|
||||
restart_loop:
|
||||
@@ -136,7 +180,13 @@ static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
|
||||
|
||||
pv = seg_pv(seg, s);
|
||||
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;
|
||||
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 */
|
||||
list_iterate_safe(pvh, pvht, &vg->pvs) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -190,7 +350,7 @@ static int _vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
|
||||
list_del(&pvl->list);
|
||||
|
||||
pv->vg_name = ORPHAN;
|
||||
pv->status = ALLOCATABLE_PV;
|
||||
pv->status = ALLOCATABLE_PV;
|
||||
|
||||
if (!dev_get_size(pv->dev, &pv->size)) {
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
&& !arg_count(cmd, removemissing_ARG)) {
|
||||
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;
|
||||
}
|
||||
|
||||
init_partial(0);
|
||||
|
||||
vg->status &= ~PARTIAL_VG;
|
||||
vg->status |= LVM_WRITE;
|
||||
|
||||
if (!vg_write(vg) || !vg_commit(vg)) {
|
||||
log_error("Failed to write out a consistent VG for %s",
|
||||
vg_name);
|
||||
|
Reference in New Issue
Block a user