mirror of
git://sourceware.org/git/lvm2.git
synced 2025-12-25 20:23:49 +03:00
Compare commits
96 Commits
dm_v1_02_1
...
dm_v1_02_1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34a74e81e3 | ||
|
|
cb120ddb15 | ||
|
|
f9ee4395b0 | ||
|
|
71f06d51ed | ||
|
|
217f70952f | ||
|
|
f813d41a76 | ||
|
|
d851289d8a | ||
|
|
b115b8a2ea | ||
|
|
d0f7067471 | ||
|
|
be5b4c38a7 | ||
|
|
d6d597e3dd | ||
|
|
84e348fade | ||
|
|
910054657e | ||
|
|
8357a11249 | ||
|
|
9b021ba057 | ||
|
|
317e588efd | ||
|
|
b1d32a03c7 | ||
|
|
ee6e6529ee | ||
|
|
9d944d6cf9 | ||
|
|
13635d281a | ||
|
|
2493c46970 | ||
|
|
63e4217271 | ||
|
|
f4bd12e8e9 | ||
|
|
df15f46900 | ||
|
|
fb3a732361 | ||
|
|
2d74110feb | ||
|
|
19d102082d | ||
|
|
d2af2c9487 | ||
|
|
82980149fa | ||
|
|
a19bb7b909 | ||
|
|
9d98c3278d | ||
|
|
26376ac1c9 | ||
|
|
8459f99341 | ||
|
|
e5bdb0e0b5 | ||
|
|
1106b7775a | ||
|
|
ae2852156d | ||
|
|
44c6c36c43 | ||
|
|
a81926503d | ||
|
|
af13ccddda | ||
|
|
392e1bc2e8 | ||
|
|
9268d92c70 | ||
|
|
bb3366c07d | ||
|
|
d24d563ebc | ||
|
|
954bd9257b | ||
|
|
5d51a56c02 | ||
|
|
f48648552e | ||
|
|
edb9c3cc9f | ||
|
|
01dc83b936 | ||
|
|
3a8dff3a62 | ||
|
|
13b234ccba | ||
|
|
e451e93664 | ||
|
|
b4f9531475 | ||
|
|
3184ff75c4 | ||
|
|
43243f4d30 | ||
|
|
c975a100b1 | ||
|
|
02bf389425 | ||
|
|
bcb9a3dd04 | ||
|
|
cce3baa275 | ||
|
|
2b48fad426 | ||
|
|
d554b2bc94 | ||
|
|
f66943de43 | ||
|
|
9d1e9bc2fb | ||
|
|
2d6a014920 | ||
|
|
c1952bf257 | ||
|
|
a10227eb03 | ||
|
|
475ae29b85 | ||
|
|
0b9cfc278b | ||
|
|
b57b6b4fba | ||
|
|
7d948f7bc5 | ||
|
|
459023d171 | ||
|
|
fd6570720a | ||
|
|
7831665417 | ||
|
|
7c9920d982 | ||
|
|
cbdccf0a9c | ||
|
|
64fa83ec3f | ||
|
|
faff865cfd | ||
|
|
742ab55a9a | ||
|
|
66e623fb2a | ||
|
|
4ab17ee965 | ||
|
|
7f48ca5132 | ||
|
|
da983848b4 | ||
|
|
bc03f7bad3 | ||
|
|
a1c8bd3846 | ||
|
|
404bc284e0 | ||
|
|
9dee30ff0e | ||
|
|
f91aadbea8 | ||
|
|
aa15a10c91 | ||
|
|
5b03e36351 | ||
|
|
b9ba9ffad2 | ||
|
|
642be5d16c | ||
|
|
ee68d715bf | ||
|
|
224084f056 | ||
|
|
1cd8c849b8 | ||
|
|
169f68bfcd | ||
|
|
d2b7cfa2d1 | ||
|
|
a40c7dff5d |
73
WHATS_NEW
73
WHATS_NEW
@@ -1,5 +1,76 @@
|
||||
Version 2.02.16 -
|
||||
Version 2.02.20 - 25th January 2007
|
||||
===================================
|
||||
dmeventd mirror sets ignore_suspended_devices and avoids scanning mirrors.
|
||||
Add devices/ignore_suspended_devices to ignore suspended dm devices.
|
||||
Add some missing close() and fclose() return code checks.
|
||||
Fix exit statuses of reporting tools (2.02.19).
|
||||
Add init script for dmeventd monitoring.
|
||||
lvm.static no longer interacts with dmeventd unless explicitly asked to.
|
||||
Add field definitions to report help text.
|
||||
Remove unnecessary cmd arg from target_*monitor_events().
|
||||
Add private variable to dmeventd shared library interface.
|
||||
Long-lived processes write out persistent dev cache in refresh_toolcontext().
|
||||
Fix refresh_toolcontext() always to wipe persistent device filter cache.
|
||||
Add is_long_lived to toolcontext.
|
||||
Add --clustered to man pages.
|
||||
Streamline dm_report_field_* interface.
|
||||
Change remaining dmeventd terminology 'register' to 'monitor'.
|
||||
Update reporting man pages.
|
||||
No longer necessary to specify alignment type for report fields.
|
||||
|
||||
Version 2.02.19 - 17th January 2007
|
||||
===================================
|
||||
Fix a segfault if an empty config file section encountered.
|
||||
Move basic reporting functions into libdevmapper.
|
||||
Fix partition table processing after sparc changes (2.02.16).
|
||||
Fix cmdline PE range processing segfault (2.02.13).
|
||||
Some libdevmapper-event interface changes.
|
||||
Report dmeventd mirror monitoring status.
|
||||
Fix dmeventd mirror status line processing.
|
||||
|
||||
Version 2.02.18 - 11th January 2007
|
||||
===================================
|
||||
Revised libdevmapper-event interface for dmeventd.
|
||||
Remove dmeventd mirror status line word limit.
|
||||
Use CFLAGS when linking so mixed sparc builds can supply -m64.
|
||||
Prevent permission changes on active mirrors.
|
||||
Print warning instead of error message if lvconvert cannot zero volume.
|
||||
Add snapshot options to lvconvert man page.
|
||||
dumpconfig accepts a list of configuration variables to display.
|
||||
Change dumpconfig to use --file to redirect output to a file.
|
||||
Avoid vgreduce error when mirror code removes the log LV.
|
||||
Remove 3 redundant AC_MSG_RESULTs from configure.in.
|
||||
Free memory in _raw_read_mda_header() error paths.
|
||||
Fix ambiguous vgsplit error message for split LV.
|
||||
Fix lvextend man page typo.
|
||||
Add configure --with-dmdir to compile against a device-mapper source tree.
|
||||
Use no flush suspending for mirrors.
|
||||
Add dmeventd_mirror register_mutex, tidy initialisation & add memlock.
|
||||
Fix create mirror with name longer than 22 chars.
|
||||
Fix some activate.c prototypes when compiled without devmapper.
|
||||
Fix dmeventd mirror to cope if monitored device disappears.
|
||||
|
||||
Version 2.02.17 - 14th December 2006
|
||||
====================================
|
||||
Add missing pvremove error message when device doesn't exist.
|
||||
When lvconvert allocates a mirror log, respect parallel area constraints.
|
||||
Use loop to iterate through the now-ordered policy list in _allocate().
|
||||
Check for failure to allocate just the mirror log.
|
||||
Introduce calc_area_multiple().
|
||||
Support mirror log allocation when there is only one PV: area_count now 0.
|
||||
Fix detection of smallest area in _alloc_parallel_area() for cling policy.
|
||||
Add manpage entry for clvmd -T
|
||||
Fix gulm operation of clvmd, including a hang when doing lvchange -aey
|
||||
Fix hang in clvmd if a pre-command failed.
|
||||
|
||||
Version 2.02.16 - 1st December 2006
|
||||
===================================
|
||||
Fix VG clustered read locks to use PR not CR.
|
||||
Adjust some alignments for ia64/sparc.
|
||||
Fix mirror segment removal to use temporary error segment.
|
||||
Always compile debug logging into clvmd.
|
||||
Add startup timeout to RHEL4 clvmd startup script.
|
||||
Add -T (startup timeout) switch to clvmd.
|
||||
Improve lvm_dump.sh robustness.
|
||||
Update lvm2create_initrd to support gentoo.
|
||||
|
||||
|
||||
33
WHATS_NEW_DM
33
WHATS_NEW_DM
@@ -1,3 +1,36 @@
|
||||
Version 1.02.16 - 25th January 2007
|
||||
===================================
|
||||
Add some missing close() and fclose() return value checks.
|
||||
Migrate dmsetup column-based output over to new libdevmapper report framework.
|
||||
Add descriptions to reporting field definitions.
|
||||
Add a dso-private variable to dmeventd dso interface.
|
||||
Add dm_event_handler_[gs]et_timeout functions.
|
||||
Streamline dm_report_field_* interface.
|
||||
Add cmdline debug & version options to dmeventd.
|
||||
Add DM_LIB_VERSION definition to configure.h.
|
||||
Suppress 'Unrecognised field' error if report field is 'help'.
|
||||
Add --separator and --sort to dmsetup (unused).
|
||||
Make alignment flag optional when specifying report fields.
|
||||
|
||||
Version 1.02.15 - 17th January 2007
|
||||
===================================
|
||||
Add basic reporting functions to libdevmapper.
|
||||
Fix a malloc error path in dmsetup message.
|
||||
More libdevmapper-event interface changes and fixes.
|
||||
Rename dm_saprintf() to dm_asprintf().
|
||||
Report error if NULL pointer is supplied to dm_strdup_aux().
|
||||
Reinstate dm_event_get_registered_device.
|
||||
|
||||
Version 1.02.14 - 11th January 2007
|
||||
===================================
|
||||
Add dm_saprintf().
|
||||
Use CFLAGS when linking so mixed sparc builds can supply -m64.
|
||||
Add dm_tree_use_no_flush_suspend().
|
||||
Lots of dmevent changes including revised interface.
|
||||
Export dm_basename().
|
||||
Cope with a trailing space when comparing tables prior to possible reload.
|
||||
Fix dmeventd to cope if monitored device disappears.
|
||||
|
||||
Version 1.02.13 - 28 Nov 2006
|
||||
=============================
|
||||
Update dmsetup man page (setgeometry & message).
|
||||
|
||||
26
configure
vendored
26
configure
vendored
@@ -310,7 +310,7 @@ ac_includes_default="\
|
||||
#endif"
|
||||
|
||||
ac_default_prefix=/usr
|
||||
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CFLOW_CMD CSCOPE_CMD CPP EGREP ALLOCA LIBOBJS POW_LIB MSGFMT MODPROBE_CMD JOBS STATIC_LINK LVM1 POOL SNAPSHOTS MIRRORS OWNER GROUP COPTIMISE_FLAG CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LDDEPS LIB_SUFFIX LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX HAVE_REALTIME CMDLIB LOCALEDIR CONFDIR STATICDIR INTL_PACKAGE INTL CLVMD CLUSTER FSADM DMEVENTD LTLIBOBJS'
|
||||
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CFLOW_CMD CSCOPE_CMD CPP EGREP ALLOCA LIBOBJS POW_LIB MSGFMT MODPROBE_CMD JOBS STATIC_LINK LVM1 POOL SNAPSHOTS MIRRORS OWNER GROUP COPTIMISE_FLAG CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LDDEPS LIB_SUFFIX LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX HAVE_REALTIME CMDLIB LOCALEDIR CONFDIR STATICDIR DMDIR INTL_PACKAGE INTL CLVMD CLUSTER FSADM DMEVENTD LTLIBOBJS'
|
||||
ac_subst_files=''
|
||||
|
||||
# Initialize some variables set by options.
|
||||
@@ -883,6 +883,7 @@ Optional Packages:
|
||||
--with-localedir=DIR Translation files in DIR PREFIX/share/locale
|
||||
--with-confdir=DIR Configuration files in DIR /etc
|
||||
--with-staticdir=DIR Static binary in DIR EXEC_PREFIX/sbin
|
||||
--with-dmdir=DIR Build against device-mapper source tree in DIR
|
||||
|
||||
Some influential environment variables:
|
||||
CC C compiler command
|
||||
@@ -8267,8 +8268,6 @@ fi
|
||||
|
||||
################################################################################
|
||||
if test x$SELINUX = xyes; then
|
||||
echo "$as_me:$LINENO: checking for sepol_check_context function" >&5
|
||||
echo $ECHO_N "checking for sepol_check_context function... $ECHO_C" >&6
|
||||
echo "$as_me:$LINENO: checking for sepol_check_context in -lsepol" >&5
|
||||
echo $ECHO_N "checking for sepol_check_context in -lsepol... $ECHO_C" >&6
|
||||
if test "${ac_cv_lib_sepol_sepol_check_context+set}" = set; then
|
||||
@@ -8339,15 +8338,11 @@ else
|
||||
HAVE_SEPOL=no
|
||||
fi
|
||||
|
||||
echo "$as_me:$LINENO: result: $HAVE_SEPOL" >&5
|
||||
echo "${ECHO_T}$HAVE_SEPOL" >&6
|
||||
|
||||
if test x$HAVE_SEPOL = xyes; then
|
||||
LIBS="-lsepol $LIBS"
|
||||
fi
|
||||
|
||||
echo "$as_me:$LINENO: checking for is_selinux_enabled function" >&5
|
||||
echo $ECHO_N "checking for is_selinux_enabled function... $ECHO_C" >&6
|
||||
echo "$as_me:$LINENO: checking for is_selinux_enabled in -lselinux" >&5
|
||||
echo $ECHO_N "checking for is_selinux_enabled in -lselinux... $ECHO_C" >&6
|
||||
if test "${ac_cv_lib_selinux_is_selinux_enabled+set}" = set; then
|
||||
@@ -8418,8 +8413,6 @@ else
|
||||
HAVE_SELINUX=no
|
||||
fi
|
||||
|
||||
echo "$as_me:$LINENO: result: $HAVE_SELINUX" >&5
|
||||
echo "${ECHO_T}$HAVE_SELINUX" >&6
|
||||
|
||||
if test x$HAVE_SELINUX = xyes; then
|
||||
|
||||
@@ -8436,8 +8429,6 @@ fi
|
||||
|
||||
################################################################################
|
||||
if test x$REALTIME = xyes; then
|
||||
echo "$as_me:$LINENO: checking for clock_gettime function" >&5
|
||||
echo $ECHO_N "checking for clock_gettime function... $ECHO_C" >&6
|
||||
echo "$as_me:$LINENO: checking for clock_gettime in -lrt" >&5
|
||||
echo $ECHO_N "checking for clock_gettime in -lrt... $ECHO_C" >&6
|
||||
if test "${ac_cv_lib_rt_clock_gettime+set}" = set; then
|
||||
@@ -8508,8 +8499,6 @@ else
|
||||
HAVE_REALTIME=no
|
||||
fi
|
||||
|
||||
echo "$as_me:$LINENO: result: $HAVE_REALTIME" >&5
|
||||
echo "${ECHO_T}$HAVE_REALTIME" >&6
|
||||
|
||||
if test x$HAVE_REALTIME = xyes; then
|
||||
|
||||
@@ -8964,6 +8953,15 @@ else
|
||||
STATICDIR='${exec_prefix}/sbin'
|
||||
fi;
|
||||
|
||||
|
||||
# Check whether --with-dmdir or --without-dmdir was given.
|
||||
if test "${with_dmdir+set}" = set; then
|
||||
withval="$with_dmdir"
|
||||
DMDIR="$withval"
|
||||
else
|
||||
DMDIR=
|
||||
fi;
|
||||
|
||||
################################################################################
|
||||
if test x$READLINE = xyes; then
|
||||
|
||||
@@ -11200,6 +11198,7 @@ fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
################################################################################
|
||||
@@ -11900,6 +11899,7 @@ s,@CMDLIB@,$CMDLIB,;t t
|
||||
s,@LOCALEDIR@,$LOCALEDIR,;t t
|
||||
s,@CONFDIR@,$CONFDIR,;t t
|
||||
s,@STATICDIR@,$STATICDIR,;t t
|
||||
s,@DMDIR@,$DMDIR,;t t
|
||||
s,@INTL_PACKAGE@,$INTL_PACKAGE,;t t
|
||||
s,@INTL@,$INTL,;t t
|
||||
s,@CLVMD@,$CLVMD,;t t
|
||||
|
||||
12
configure.in
12
configure.in
@@ -438,17 +438,13 @@ fi
|
||||
################################################################################
|
||||
dnl -- Check for selinux
|
||||
if test x$SELINUX = xyes; then
|
||||
AC_MSG_CHECKING(for sepol_check_context function)
|
||||
AC_CHECK_LIB(sepol, sepol_check_context, HAVE_SEPOL=yes, HAVE_SEPOL=no)
|
||||
AC_MSG_RESULT($HAVE_SEPOL)
|
||||
|
||||
if test x$HAVE_SEPOL = xyes; then
|
||||
LIBS="-lsepol $LIBS"
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING(for is_selinux_enabled function)
|
||||
AC_CHECK_LIB(selinux, is_selinux_enabled, HAVE_SELINUX=yes, HAVE_SELINUX=no)
|
||||
AC_MSG_RESULT($HAVE_SELINUX)
|
||||
|
||||
if test x$HAVE_SELINUX = xyes; then
|
||||
AC_DEFINE([HAVE_SELINUX], 1, [Define to 1 to include support for selinux.])
|
||||
@@ -461,9 +457,7 @@ fi
|
||||
################################################################################
|
||||
dnl -- Check for realtime clock support
|
||||
if test x$REALTIME = xyes; then
|
||||
AC_MSG_CHECKING(for clock_gettime function)
|
||||
AC_CHECK_LIB(rt, clock_gettime, HAVE_REALTIME=yes, HAVE_REALTIME=no)
|
||||
AC_MSG_RESULT($HAVE_REALTIME)
|
||||
|
||||
if test x$HAVE_REALTIME = xyes; then
|
||||
AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.])
|
||||
@@ -526,6 +520,11 @@ AC_ARG_WITH(staticdir,
|
||||
[ STATICDIR="$withval" ],
|
||||
[ STATICDIR='${exec_prefix}/sbin' ])
|
||||
|
||||
AC_ARG_WITH(dmdir,
|
||||
[ --with-dmdir=DIR Build against device-mapper source tree in DIR],
|
||||
[ DMDIR="$withval" ],
|
||||
[ DMDIR= ])
|
||||
|
||||
################################################################################
|
||||
dnl -- Ensure additional headers required
|
||||
if test x$READLINE = xyes; then
|
||||
@@ -608,6 +607,7 @@ AC_SUBST(MSGFMT)
|
||||
AC_SUBST(LOCALEDIR)
|
||||
AC_SUBST(CONFDIR)
|
||||
AC_SUBST(STATICDIR)
|
||||
AC_SUBST(DMDIR)
|
||||
AC_SUBST(INTL_PACKAGE)
|
||||
AC_SUBST(INTL)
|
||||
AC_SUBST(CLVMD)
|
||||
|
||||
@@ -71,7 +71,8 @@ INSTALL_TARGETS = \
|
||||
install_clvmd
|
||||
|
||||
clvmd: $(OBJECTS) $(top_srcdir)/lib/liblvm.a
|
||||
$(CC) -o clvmd $(OBJECTS) $(LDFLAGS) $(LVMLIBS) $(LMLIBS) $(LIBS)
|
||||
$(CC) -o clvmd $(OBJECTS) $(CFLAGS) $(LDFLAGS) \
|
||||
$(LVMLIBS) $(LMLIBS) $(LIBS)
|
||||
|
||||
.PHONY: install_clvmd
|
||||
|
||||
|
||||
@@ -191,12 +191,16 @@ static int lock_vg(struct local_client *client)
|
||||
dm_hash_remove(lock_hash, lockname);
|
||||
}
|
||||
else {
|
||||
|
||||
/* Read locks need to be PR; other modes get passed through */
|
||||
if ((lock_cmd & LCK_TYPE_MASK) == LCK_READ) {
|
||||
lock_cmd &= ~LCK_TYPE_MASK;
|
||||
lock_cmd |= LCK_PREAD;
|
||||
}
|
||||
status = sync_lock(lockname, (int)lock_cmd, (lock_flags & LCK_NONBLOCK) ? LKF_NOQUEUE : 0, &lkid);
|
||||
if (status)
|
||||
status = errno;
|
||||
else
|
||||
dm_hash_insert(lock_hash, lockname, (void *)lkid);
|
||||
dm_hash_insert(lock_hash, lockname, (void *)(long)lkid);
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -220,7 +224,7 @@ int do_pre_command(struct local_client *client)
|
||||
switch (header->cmd) {
|
||||
case CLVMD_CMD_TEST:
|
||||
status = sync_lock("CLVMD_TEST", LKM_EXMODE, 0, &lockid);
|
||||
client->bits.localsock.private = (void *) lockid;
|
||||
client->bits.localsock.private = (void *)(long)lockid;
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_VG:
|
||||
|
||||
@@ -730,7 +730,7 @@ static int _lock_resource(char *resource, int mode, int flags, int *lockid)
|
||||
pthread_mutex_lock(&lwait.mutex);
|
||||
|
||||
/* This needs to be converted from DLM/LVM2 value for GULM */
|
||||
if (flags == LCK_NONBLOCK) flags = lg_lock_flag_Try;
|
||||
if (flags & LKF_NOQUEUE) flags = lg_lock_flag_Try;
|
||||
|
||||
dm_hash_insert(lock_hash, resource, &lwait);
|
||||
DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
|
||||
@@ -828,6 +828,7 @@ static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
|
||||
}
|
||||
break;
|
||||
|
||||
case LCK_PREAD:
|
||||
case LCK_READ:
|
||||
status = _lock_resource(lock1, lg_lock_state_Shared, flags, lockid);
|
||||
if (status)
|
||||
@@ -864,6 +865,7 @@ static int _sync_unlock(const char *resource, int lockid)
|
||||
/* The held lock mode is in the lock id */
|
||||
assert(lockid == LCK_EXCL ||
|
||||
lockid == LCK_READ ||
|
||||
lockid == LCK_PREAD ||
|
||||
lockid == LCK_WRITE);
|
||||
|
||||
status = _unlock_resource(lock1, lockid);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
|
||||
/* DLM constant that clvmd uses as a generic NONBLOCK lock flag */
|
||||
#define LKF_NOQUEUE 1
|
||||
|
||||
extern int get_next_node_csid(void **context, char *csid);
|
||||
extern void add_down_node(char *csid);
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
@@ -85,6 +86,7 @@ struct lvm_thread_cmd {
|
||||
int msglen;
|
||||
unsigned short xid;
|
||||
};
|
||||
static int debug = 0;
|
||||
static pthread_t lvm_thread;
|
||||
static pthread_mutex_t lvm_thread_mutex;
|
||||
static pthread_cond_t lvm_thread_cond;
|
||||
@@ -99,6 +101,7 @@ static int child_pipe[2];
|
||||
#define DFAIL_LOCAL_SOCK 2
|
||||
#define DFAIL_CLUSTER_IF 3
|
||||
#define DFAIL_MALLOC 4
|
||||
#define DFAIL_TIMEOUT 5
|
||||
#define SUCCESS 0
|
||||
|
||||
/* Prototypes for code further down */
|
||||
@@ -122,7 +125,7 @@ static int process_reply(struct clvm_header *msg, int msglen, char *csid);
|
||||
static int open_local_sock(void);
|
||||
static struct local_client *find_client(int clientid);
|
||||
static void main_loop(int local_sock, int cmd_timeout);
|
||||
static void be_daemon(void);
|
||||
static void be_daemon(int start_timeout);
|
||||
static int check_all_clvmds_running(struct local_client *client);
|
||||
static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
|
||||
int len, char *csid,
|
||||
@@ -146,6 +149,7 @@ static void usage(char *prog, FILE *file)
|
||||
fprintf(file, " -d Don't fork, run in the foreground\n");
|
||||
fprintf(file, " -R Tell all running clvmds in the cluster to reload their device cache\n");
|
||||
fprintf(file, " -t<secs> Command timeout (default 60 seconds)\n");
|
||||
fprintf(file, " -T<secs> Startup timeout (default none)\n");
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
|
||||
@@ -161,21 +165,36 @@ static void child_init_signal(int status)
|
||||
}
|
||||
|
||||
|
||||
void debuglog(const char *fmt, ...)
|
||||
{
|
||||
time_t P;
|
||||
va_list ap;
|
||||
|
||||
if (!debug)
|
||||
return;
|
||||
|
||||
va_start(ap,fmt);
|
||||
time(&P);
|
||||
fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime(&P)+4 );
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int local_sock;
|
||||
struct local_client *newfd;
|
||||
struct utsname nodeinfo;
|
||||
signed char opt;
|
||||
int debug = 0;
|
||||
int cmd_timeout = DEFAULT_CMD_TIMEOUT;
|
||||
int start_timeout = 0;
|
||||
sigset_t ss;
|
||||
int using_gulm = 0;
|
||||
|
||||
/* Deal with command-line arguments */
|
||||
opterr = 0;
|
||||
optind = 0;
|
||||
while ((opt = getopt(argc, argv, "?vVhdt:R")) != EOF) {
|
||||
while ((opt = getopt(argc, argv, "?vVhdt:RT:")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
usage(argv[0], stdout);
|
||||
@@ -200,6 +219,14 @@ int main(int argc, char *argv[])
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'T':
|
||||
start_timeout = atoi(optarg);
|
||||
if (start_timeout <= 0) {
|
||||
fprintf(stderr, "startup timeout is invalid\n");
|
||||
usage(argv[0], stderr);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
printf("Cluster LVM daemon version: %s\n", LVM_VERSION);
|
||||
@@ -214,7 +241,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
/* Fork into the background (unless requested not to) */
|
||||
if (!debug) {
|
||||
be_daemon();
|
||||
be_daemon(start_timeout);
|
||||
}
|
||||
|
||||
DEBUGLOG("CLVMD started\n");
|
||||
@@ -298,7 +325,8 @@ int main(int argc, char *argv[])
|
||||
/* This needs to be started after cluster initialisation
|
||||
as it may need to take out locks */
|
||||
DEBUGLOG("starting LVM thread\n");
|
||||
pthread_create(&lvm_thread, NULL, lvm_thread_fn, (void *)using_gulm);
|
||||
pthread_create(&lvm_thread, NULL, lvm_thread_fn,
|
||||
(void *)(long)using_gulm);
|
||||
|
||||
/* Tell the rest of the cluster our version number */
|
||||
/* CMAN can do this immediately, gulm needs to wait until
|
||||
@@ -385,16 +413,17 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
|
||||
|
||||
len = read(thisfd->fd, buffer, sizeof(int));
|
||||
|
||||
DEBUGLOG("read on PIPE %d: %d bytes: status: %d\n",
|
||||
thisfd->fd, len, *(int *) buffer);
|
||||
|
||||
if (len == sizeof(int)) {
|
||||
status = *(int *) buffer;
|
||||
memcpy(&status, buffer, sizeof(int));
|
||||
}
|
||||
|
||||
DEBUGLOG("read on PIPE %d: %d bytes: status: %d\n",
|
||||
thisfd->fd, len, status);
|
||||
|
||||
/* EOF on pipe or an error, close it */
|
||||
if (len <= 0) {
|
||||
int jstat;
|
||||
void *ret = &status;
|
||||
close(thisfd->fd);
|
||||
|
||||
/* Clear out the cross-link */
|
||||
@@ -404,9 +433,7 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
|
||||
|
||||
/* Reap child thread */
|
||||
if (thisfd->bits.pipe.threadid) {
|
||||
jstat =
|
||||
pthread_join(thisfd->bits.pipe.threadid,
|
||||
(void **) &status);
|
||||
jstat = pthread_join(thisfd->bits.pipe.threadid, &ret);
|
||||
thisfd->bits.pipe.threadid = 0;
|
||||
if (thisfd->bits.pipe.client != NULL)
|
||||
thisfd->bits.pipe.client->bits.localsock.
|
||||
@@ -647,16 +674,66 @@ static void main_loop(int local_sock, int cmd_timeout)
|
||||
close(local_sock);
|
||||
}
|
||||
|
||||
static __attribute__ ((noreturn)) void wait_for_child(int c_pipe, int timeout)
|
||||
{
|
||||
int child_status;
|
||||
int sstat;
|
||||
fd_set fds;
|
||||
struct timeval tv = {timeout, 0};
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(c_pipe, &fds);
|
||||
|
||||
sstat = select(c_pipe+1, &fds, NULL, NULL, timeout? &tv: NULL);
|
||||
if (sstat == 0) {
|
||||
fprintf(stderr, "clvmd startup timed out\n");
|
||||
exit(DFAIL_TIMEOUT);
|
||||
}
|
||||
if (sstat == 1) {
|
||||
if (read(c_pipe, &child_status, sizeof(child_status)) !=
|
||||
sizeof(child_status)) {
|
||||
|
||||
fprintf(stderr, "clvmd failed in initialisation\n");
|
||||
exit(DFAIL_INIT);
|
||||
}
|
||||
else {
|
||||
switch (child_status) {
|
||||
case SUCCESS:
|
||||
break;
|
||||
case DFAIL_INIT:
|
||||
fprintf(stderr, "clvmd failed in initialisation\n");
|
||||
break;
|
||||
case DFAIL_LOCAL_SOCK:
|
||||
fprintf(stderr, "clvmd could not create local socket\n");
|
||||
fprintf(stderr, "Another clvmd is probably already running\n");
|
||||
break;
|
||||
case DFAIL_CLUSTER_IF:
|
||||
fprintf(stderr, "clvmd could not connect to cluster manager\n");
|
||||
fprintf(stderr, "Consult syslog for more information\n");
|
||||
break;
|
||||
case DFAIL_MALLOC:
|
||||
fprintf(stderr, "clvmd failed, not enough memory\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "clvmd failed, error was %d\n", child_status);
|
||||
break;
|
||||
}
|
||||
exit(child_status);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "clvmd startup, select failed: %s\n", strerror(errno));
|
||||
exit(DFAIL_INIT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fork into the background and detach from our parent process.
|
||||
* In the interests of user-friendliness we wait for the daemon
|
||||
* to complete initialisation before returning its status
|
||||
* the the user.
|
||||
*/
|
||||
static void be_daemon()
|
||||
static void be_daemon(int timeout)
|
||||
{
|
||||
pid_t pid;
|
||||
int child_status;
|
||||
int devnull = open("/dev/null", O_RDWR);
|
||||
if (devnull == -1) {
|
||||
perror("Can't open /dev/null");
|
||||
@@ -676,36 +753,7 @@ static void be_daemon()
|
||||
|
||||
default: /* Parent */
|
||||
close(child_pipe[1]);
|
||||
if (read(child_pipe[0], &child_status, sizeof(child_status)) !=
|
||||
sizeof(child_status)) {
|
||||
|
||||
fprintf(stderr, "clvmd failed in initialisation\n");
|
||||
exit(DFAIL_INIT);
|
||||
}
|
||||
else {
|
||||
switch (child_status) {
|
||||
case SUCCESS:
|
||||
break;
|
||||
case DFAIL_INIT:
|
||||
fprintf(stderr, "clvmd failed in initialisation\n");
|
||||
break;
|
||||
case DFAIL_LOCAL_SOCK:
|
||||
fprintf(stderr, "clvmd could not create local socket\n");
|
||||
fprintf(stderr, "Another clvmd is probably already running\n");
|
||||
break;
|
||||
case DFAIL_CLUSTER_IF:
|
||||
fprintf(stderr, "clvmd could not connect to cluster manager\n");
|
||||
fprintf(stderr, "Consult syslog for more information\n");
|
||||
break;
|
||||
case DFAIL_MALLOC:
|
||||
fprintf(stderr, "clvmd failed, not enough memory\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "clvmd failed, error was %d\n", child_status);
|
||||
break;
|
||||
}
|
||||
exit(child_status);
|
||||
}
|
||||
wait_for_child(child_pipe[0], timeout);
|
||||
}
|
||||
|
||||
/* Detach ourself from the calling environment */
|
||||
@@ -1091,8 +1139,8 @@ static int distribute_command(struct local_client *thisfd)
|
||||
}
|
||||
|
||||
/* Process a command from a remote node and return the result */
|
||||
void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
char *csid)
|
||||
static void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
char *csid)
|
||||
{
|
||||
char *replyargs;
|
||||
char nodename[max_cluster_member_name_len];
|
||||
@@ -1116,11 +1164,12 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
(struct clvm_header *) malloc(msg->arglen +
|
||||
sizeof(struct clvm_header));
|
||||
if (newmsg) {
|
||||
if (system_lv_read_data
|
||||
(nodename, (char *) newmsg,
|
||||
(size_t *) &msglen) == 0) {
|
||||
ssize_t len;
|
||||
if (system_lv_read_data(nodename, (char *) newmsg,
|
||||
&len) == 0) {
|
||||
msg = newmsg;
|
||||
msg_malloced = 1;
|
||||
msglen = len;
|
||||
} else {
|
||||
struct clvm_header head;
|
||||
DEBUGLOG("System LV read failed\n");
|
||||
@@ -1166,8 +1215,11 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
/* Version check is internal - don't bother exposing it in
|
||||
clvmd-command.c */
|
||||
if (msg->cmd == CLVMD_CMD_VERSION) {
|
||||
int *version_nums = (int *) msg->args;
|
||||
int version_nums[3];
|
||||
char node[256];
|
||||
|
||||
memcpy(version_nums, msg->args, sizeof(version_nums));
|
||||
|
||||
clops->name_from_csid(csid, node);
|
||||
DEBUGLOG("Remote node %s is version %d.%d.%d\n",
|
||||
node,
|
||||
@@ -1339,7 +1391,7 @@ static void add_reply_to_list(struct local_client *client, int status,
|
||||
}
|
||||
|
||||
/* This is the thread that runs the PRE and post commands for a particular connection */
|
||||
static void *pre_and_post_thread(void *arg)
|
||||
static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
|
||||
{
|
||||
struct local_client *client = (struct local_client *) arg;
|
||||
int status;
|
||||
@@ -1374,6 +1426,8 @@ static void *pre_and_post_thread(void *arg)
|
||||
DEBUGLOG("Writing status %d down pipe %d\n", status, pipe_fd);
|
||||
/* Tell the parent process we have finished this bit */
|
||||
write(pipe_fd, &status, sizeof(int));
|
||||
if (status)
|
||||
continue; /* Wait for another PRE command */
|
||||
|
||||
/* We may need to wait for the condition variable before running the post command */
|
||||
pthread_mutex_lock(&client->bits.localsock.mutex);
|
||||
@@ -1407,7 +1461,6 @@ static void *pre_and_post_thread(void *arg)
|
||||
}
|
||||
DEBUGLOG("Subthread finished\n");
|
||||
pthread_exit((void *) 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Process a command on the local node and store the result */
|
||||
@@ -1516,7 +1569,7 @@ static void send_local_reply(struct local_client *client, int status, int fd)
|
||||
if (thisreply->status)
|
||||
clientreply->flags |= CLVMD_FLAG_NODEERRS;
|
||||
|
||||
*(int *) ptr = thisreply->status;
|
||||
memcpy(ptr, &thisreply->status, sizeof(int));
|
||||
ptr += sizeof(int);
|
||||
|
||||
if (thisreply->replymsg) {
|
||||
@@ -1572,19 +1625,22 @@ static void send_version_message()
|
||||
{
|
||||
char message[sizeof(struct clvm_header) + sizeof(int) * 3];
|
||||
struct clvm_header *msg = (struct clvm_header *) message;
|
||||
int *version_nums = (int *) msg->args;
|
||||
int version_nums[3];
|
||||
|
||||
msg->cmd = CLVMD_CMD_VERSION;
|
||||
msg->status = 0;
|
||||
msg->flags = 0;
|
||||
msg->clientid = 0;
|
||||
msg->arglen = sizeof(int) * 3;
|
||||
msg->arglen = sizeof(version_nums);
|
||||
|
||||
version_nums[0] = htonl(CLVMD_MAJOR_VERSION);
|
||||
version_nums[1] = htonl(CLVMD_MINOR_VERSION);
|
||||
version_nums[2] = htonl(CLVMD_PATCH_VERSION);
|
||||
|
||||
memcpy(&msg->args, version_nums, sizeof(version_nums));
|
||||
|
||||
hton_clvm(msg);
|
||||
|
||||
clops->cluster_send_message(message, sizeof(message), NULL,
|
||||
"Error Sending version number");
|
||||
}
|
||||
@@ -1641,11 +1697,11 @@ static int process_work_item(struct lvm_thread_cmd *cmd)
|
||||
/*
|
||||
* Routine that runs in the "LVM thread".
|
||||
*/
|
||||
static void *lvm_thread_fn(void *arg)
|
||||
static __attribute__ ((noreturn)) void *lvm_thread_fn(void *arg)
|
||||
{
|
||||
struct list *cmdl, *tmp;
|
||||
sigset_t ss;
|
||||
int using_gulm = (int)arg;
|
||||
int using_gulm = (int)(long)arg;
|
||||
|
||||
/* Don't let anyone else to do work until we are started */
|
||||
pthread_mutex_lock(&lvm_start_mutex);
|
||||
@@ -1689,7 +1745,6 @@ static void *lvm_thread_fn(void *arg)
|
||||
}
|
||||
pthread_mutex_unlock(&lvm_thread_mutex);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Pass down some work to the LVM thread */
|
||||
|
||||
@@ -95,11 +95,7 @@ struct local_client {
|
||||
} bits;
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUGLOG(fmt, args...) {time_t P; time(&P); fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime(&P)+4 ); fprintf(stderr, fmt, ## args);}
|
||||
#else
|
||||
#define DEBUGLOG(fmt, args...)
|
||||
#endif
|
||||
#define DEBUGLOG(fmt, args...) debuglog(fmt, ## args);
|
||||
|
||||
#ifndef max
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
@@ -117,6 +113,7 @@ extern int add_client(struct local_client *new_client);
|
||||
|
||||
extern void clvmd_cluster_init_completed(void);
|
||||
extern void process_message(struct local_client *client, char *buf, int len, char *csid);
|
||||
extern void debuglog(const char *fmt, ... );
|
||||
|
||||
int sync_lock(const char *resource, int mode, int flags, int *lockid);
|
||||
int sync_unlock(const char *resource, int lockid);
|
||||
|
||||
@@ -325,8 +325,8 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
|
||||
init_mirror_in_sync(1);
|
||||
|
||||
if (!(lock_flags & LCK_DMEVENTD_REGISTER_MODE))
|
||||
init_dmeventd_register(0);
|
||||
if (!(lock_flags & LCK_DMEVENTD_MONITOR_MODE))
|
||||
init_dmeventd_monitor(0);
|
||||
|
||||
switch (command) {
|
||||
case LCK_LV_EXCLUSIVE:
|
||||
@@ -362,8 +362,8 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
|
||||
init_mirror_in_sync(0);
|
||||
|
||||
if (!(lock_flags & LCK_DMEVENTD_REGISTER_MODE))
|
||||
init_dmeventd_register(DEFAULT_DMEVENTD_MONITOR);
|
||||
if (!(lock_flags & LCK_DMEVENTD_MONITOR_MODE))
|
||||
init_dmeventd_monitor(DEFAULT_DMEVENTD_MONITOR);
|
||||
|
||||
/* clean the pool for another command */
|
||||
dm_pool_empty(cmd->mem);
|
||||
@@ -473,7 +473,8 @@ static void drop_vg_locks()
|
||||
sync_unlock(vg, LCK_EXCL);
|
||||
|
||||
}
|
||||
fclose(vgs);
|
||||
if (fclose(vgs))
|
||||
DEBUGLOG("vgs fclose failed: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -523,7 +524,8 @@ static void *get_initial_state()
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(lvs);
|
||||
if (fclose(lvs))
|
||||
DEBUGLOG("lvs fclose failed: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -575,7 +577,7 @@ void init_lvhash()
|
||||
/* Called to initialise the LVM context of the daemon */
|
||||
int init_lvm(int using_gulm)
|
||||
{
|
||||
if (!(cmd = create_toolcontext(NULL, 0))) {
|
||||
if (!(cmd = create_toolcontext(NULL, 0, 1))) {
|
||||
log_error("Failed to allocate command context");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -183,7 +183,6 @@ static int _cluster_request(char cmd, const char *node, void *data, int len,
|
||||
lvm_response_t ** response, int *num)
|
||||
{
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
|
||||
int *outptr;
|
||||
char *inptr;
|
||||
char *retbuf = NULL;
|
||||
int status;
|
||||
@@ -223,17 +222,14 @@ static int _cluster_request(char cmd, const char *node, void *data, int len,
|
||||
* With an extra pair of INTs on the front to sanity
|
||||
* check the pointer when we are given it back to free
|
||||
*/
|
||||
outptr = dm_malloc(sizeof(lvm_response_t) * num_responses +
|
||||
*response = dm_malloc(sizeof(lvm_response_t) * num_responses +
|
||||
sizeof(int) * 2);
|
||||
if (!outptr) {
|
||||
if (!*response) {
|
||||
errno = ENOMEM;
|
||||
status = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*response = (lvm_response_t *) (outptr + 2);
|
||||
outptr[0] = LVM_SIGNATURE;
|
||||
outptr[1] = num_responses;
|
||||
rarray = *response;
|
||||
|
||||
/* Unpack the response into an lvm_response_t array */
|
||||
@@ -252,7 +248,7 @@ static int _cluster_request(char cmd, const char *node, void *data, int len,
|
||||
int j;
|
||||
for (j = 0; j < i; j++)
|
||||
dm_free(rarray[i].response);
|
||||
free(outptr);
|
||||
free(*response);
|
||||
errno = ENOMEM;
|
||||
status = -1;
|
||||
goto out;
|
||||
@@ -274,25 +270,15 @@ static int _cluster_request(char cmd, const char *node, void *data, int len,
|
||||
}
|
||||
|
||||
/* Free reply array */
|
||||
static int _cluster_free_request(lvm_response_t * response)
|
||||
static int _cluster_free_request(lvm_response_t * response, int num)
|
||||
{
|
||||
int *ptr = (int *) response - 2;
|
||||
int i;
|
||||
int num;
|
||||
|
||||
/* Check it's ours to free */
|
||||
if (response == NULL || *ptr != LVM_SIGNATURE) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
num = ptr[1];
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
dm_free(response[i].response);
|
||||
}
|
||||
|
||||
dm_free(ptr);
|
||||
dm_free(response);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -327,7 +313,7 @@ int refresh_clvmd()
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
_cluster_free_request(response);
|
||||
_cluster_free_request(response, num_responses);
|
||||
errno = saved_errno;
|
||||
|
||||
return status;
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
dm_event_register
|
||||
dm_event_unregister
|
||||
dm_event_handler_create
|
||||
dm_event_handler_destroy
|
||||
dm_event_handler_set_dso
|
||||
dm_event_handler_set_dev_name
|
||||
dm_event_handler_set_uuid
|
||||
dm_event_handler_set_major
|
||||
dm_event_handler_set_minor
|
||||
dm_event_handler_set_event_mask
|
||||
dm_event_handler_get_dso
|
||||
dm_event_handler_get_devname
|
||||
dm_event_handler_get_uuid
|
||||
dm_event_handler_get_major
|
||||
dm_event_handler_get_minor
|
||||
dm_event_handler_get_event_mask
|
||||
dm_event_register_handler
|
||||
dm_event_unregister_handler
|
||||
dm_event_get_registered_device
|
||||
dm_event_set_timeout
|
||||
dm_event_get_timeout
|
||||
dm_event_handler_set_timeout
|
||||
dm_event_handler_get_timeout
|
||||
|
||||
@@ -15,8 +15,7 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
SOURCES = libdevmapper-event.c \
|
||||
dmeventd.c
|
||||
SOURCES = libdevmapper-event.c
|
||||
|
||||
LIB_STATIC = libdevmapper-event.a
|
||||
|
||||
@@ -26,12 +25,20 @@ else
|
||||
LIB_SHARED = libdevmapper-event.so
|
||||
endif
|
||||
|
||||
TARGETS = dmeventd
|
||||
CLEAN_TARGETS = dmeventd.o
|
||||
|
||||
include ../make.tmpl
|
||||
|
||||
LDFLAGS += -ldl -ldevmapper -lpthread
|
||||
CLDFLAGS += -ldl -ldevmapper -lpthread
|
||||
|
||||
dmeventd: $(LIB_SHARED) dmeventd.o
|
||||
$(CC) -o $@ dmeventd.o $(CFLAGS) $(LDFLAGS) \
|
||||
-L. -ldevmapper-event $(LIBS) -rdynamic
|
||||
|
||||
.PHONY: install_dynamic install_static install_include \
|
||||
install_pkgconfig
|
||||
install_pkgconfig install_dmeventd
|
||||
|
||||
INSTALL_TYPE = install_dynamic
|
||||
|
||||
@@ -43,7 +50,7 @@ ifeq ("@PKGCONFIG@", "yes")
|
||||
INSTALL_TYPE += install_pkgconfig
|
||||
endif
|
||||
|
||||
install: $(INSTALL_TYPE) install_include
|
||||
install: $(INSTALL_TYPE) install_include install_dmeventd
|
||||
|
||||
install_include:
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper-event.h \
|
||||
@@ -55,6 +62,9 @@ install_dynamic: libdevmapper-event.$(LIB_SUFFIX)
|
||||
$(LN_S) -f libdevmapper-event.$(LIB_SUFFIX).$(LIB_VERSION) \
|
||||
$(libdir)/libdevmapper-event.$(LIB_SUFFIX)
|
||||
|
||||
install_dmeventd: dmeventd
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< $(sbindir)/$<
|
||||
|
||||
install_pkgconfig:
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 444 libdevmapper-event.pc \
|
||||
$(usrlibdir)/pkgconfig/devmapper-event.pc
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,51 @@
|
||||
#ifndef __DMEVENTD_DOT_H__
|
||||
#define __DMEVENTD_DOT_H__
|
||||
|
||||
/* FIXME This stuff must be configurable. */
|
||||
|
||||
#define DM_EVENT_DAEMON "/sbin/dmeventd"
|
||||
#define DM_EVENT_LOCKFILE "/var/lock/dmeventd"
|
||||
#define DM_EVENT_FIFO_CLIENT "/var/run/dmeventd-client"
|
||||
#define DM_EVENT_FIFO_SERVER "/var/run/dmeventd-server"
|
||||
#define DM_EVENT_PIDFILE "/var/run/dmeventd.pid"
|
||||
|
||||
#define DM_EVENT_DEFAULT_TIMEOUT 10
|
||||
|
||||
/* Commands for the daemon passed in the message below. */
|
||||
enum dm_event_command {
|
||||
DM_EVENT_CMD_ACTIVE = 1,
|
||||
DM_EVENT_CMD_REGISTER_FOR_EVENT,
|
||||
DM_EVENT_CMD_UNREGISTER_FOR_EVENT,
|
||||
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
|
||||
DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE,
|
||||
DM_EVENT_CMD_SET_TIMEOUT,
|
||||
DM_EVENT_CMD_GET_TIMEOUT,
|
||||
};
|
||||
|
||||
/* Message passed between client and daemon. */
|
||||
struct dm_event_daemon_message {
|
||||
uint32_t cmd;
|
||||
uint32_t size;
|
||||
char *data;
|
||||
};
|
||||
|
||||
/* FIXME Is this meant to be exported? I can't see where the
|
||||
interface uses it. */
|
||||
/* Fifos for client/daemon communication. */
|
||||
struct dm_event_fifos {
|
||||
int client;
|
||||
int server;
|
||||
const char *client_path;
|
||||
const char *server_path;
|
||||
};
|
||||
|
||||
/* EXIT_SUCCESS 0 -- stdlib.h */
|
||||
/* EXIT_FAILURE 1 -- stdlib.h */
|
||||
#define EXIT_LOCKFILE_INUSE 2
|
||||
#define EXIT_DESC_CLOSE_FAILURE 3
|
||||
#define EXIT_OPEN_PID_FAILURE 4
|
||||
#define EXIT_FIFO_FAILURE 5
|
||||
#define EXIT_CHDIR_FAILURE 6
|
||||
|
||||
void dmeventd(void)
|
||||
__attribute((noreturn));
|
||||
#define EXIT_DESC_OPEN_FAILURE 4
|
||||
#define EXIT_OPEN_PID_FAILURE 5
|
||||
#define EXIT_FIFO_FAILURE 6
|
||||
#define EXIT_CHDIR_FAILURE 7
|
||||
|
||||
#endif /* __DMEVENTD_DOT_H__ */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,86 +23,84 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* FIXME This stuff must be configurable. */
|
||||
/*
|
||||
* Event library interface.
|
||||
*/
|
||||
|
||||
#define DM_EVENT_DAEMON "/sbin/dmeventd"
|
||||
#define DM_EVENT_LOCKFILE "/var/lock/dmeventd"
|
||||
#define DM_EVENT_FIFO_CLIENT "/var/run/dmeventd-client"
|
||||
#define DM_EVENT_FIFO_SERVER "/var/run/dmeventd-server"
|
||||
#define DM_EVENT_PIDFILE "/var/run/dmeventd.pid"
|
||||
enum dm_event_mask {
|
||||
DM_EVENT_SETTINGS_MASK = 0x0000FF,
|
||||
DM_EVENT_SINGLE = 0x000001, /* Report multiple errors just once. */
|
||||
DM_EVENT_MULTI = 0x000002, /* Report all of them. */
|
||||
|
||||
#define DM_EVENT_DEFAULT_TIMEOUT 10
|
||||
DM_EVENT_ERROR_MASK = 0x00FF00,
|
||||
DM_EVENT_SECTOR_ERROR = 0x000100, /* Failure on a particular sector. */
|
||||
DM_EVENT_DEVICE_ERROR = 0x000200, /* Device failure. */
|
||||
DM_EVENT_PATH_ERROR = 0x000400, /* Failure on an io path. */
|
||||
DM_EVENT_ADAPTOR_ERROR = 0x000800, /* Failure of a host adaptor. */
|
||||
|
||||
/* Commands for the daemon passed in the message below. */
|
||||
enum dm_event_command {
|
||||
DM_EVENT_CMD_ACTIVE = 1,
|
||||
DM_EVENT_CMD_REGISTER_FOR_EVENT,
|
||||
DM_EVENT_CMD_UNREGISTER_FOR_EVENT,
|
||||
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
|
||||
DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE,
|
||||
DM_EVENT_CMD_SET_TIMEOUT,
|
||||
DM_EVENT_CMD_GET_TIMEOUT,
|
||||
DM_EVENT_STATUS_MASK = 0xFF0000,
|
||||
DM_EVENT_SYNC_STATUS = 0x010000, /* Mirror synchronization completed/failed. */
|
||||
DM_EVENT_TIMEOUT = 0x020000, /* Timeout has occured */
|
||||
|
||||
DM_EVENT_REGISTRATION_PENDING = 0x1000000, /* Monitor thread is setting-up/shutting-down */
|
||||
};
|
||||
|
||||
/* Message passed between client and daemon. */
|
||||
struct dm_event_daemon_message {
|
||||
union {
|
||||
unsigned int cmd; /* FIXME Use fixed size. */
|
||||
int status; /* FIXME Use fixed size. */
|
||||
} opcode;
|
||||
char msg[252]; /* FIXME Why is this 252 ? */
|
||||
} __attribute__((packed)); /* FIXME Do this properly! */
|
||||
#define DM_EVENT_ALL_ERRORS DM_EVENT_ERROR_MASK
|
||||
|
||||
/* FIXME Is this meant to be exported? I can't see where the interface uses it. */
|
||||
/* Fifos for client/daemon communication. */
|
||||
struct dm_event_fifos {
|
||||
int client;
|
||||
int server;
|
||||
const char *client_path;
|
||||
const char *server_path;
|
||||
};
|
||||
struct dm_event_handler;
|
||||
|
||||
/* Event type definitions. */
|
||||
/* FIXME Use masks to separate the types and provide for extension. */
|
||||
enum dm_event_type {
|
||||
DM_EVENT_SINGLE = 0x01, /* Report multiple errors just once. */
|
||||
DM_EVENT_MULTI = 0x02, /* Report all of them. */
|
||||
struct dm_event_handler *dm_event_handler_create(void);
|
||||
void dm_event_handler_destroy(struct dm_event_handler *dmevh);
|
||||
|
||||
DM_EVENT_SECTOR_ERROR = 0x04, /* Failure on a particular sector. */
|
||||
DM_EVENT_DEVICE_ERROR = 0x08, /* Device failure. */
|
||||
DM_EVENT_PATH_ERROR = 0x10, /* Failure on an io path. */
|
||||
DM_EVENT_ADAPTOR_ERROR = 0x20, /* Failure off a host adaptor. */
|
||||
/*
|
||||
* Path of shared library to handle events.
|
||||
*
|
||||
* All of dso, device_name and uuid strings are duplicated, you do not
|
||||
* need to keep the pointers valid after the call succeeds. Thes may
|
||||
* return -ENOMEM though.
|
||||
*/
|
||||
int dm_event_handler_set_dso(struct dm_event_handler *dmevh, const char *path);
|
||||
|
||||
DM_EVENT_SYNC_STATUS = 0x40, /* Mirror synchronization completed/failed. */
|
||||
DM_EVENT_TIMEOUT = 0x80, /* Timeout has occured */
|
||||
};
|
||||
/*
|
||||
* Identify the device to monitor by exactly one of device_name, uuid or
|
||||
* device number. String arguments are duplicated, see above.
|
||||
*/
|
||||
int dm_event_handler_set_dev_name(struct dm_event_handler *dmevh, const char *device_name);
|
||||
|
||||
/* FIXME Use a mask. */
|
||||
#define DM_EVENT_ALL_ERRORS (DM_EVENT_SECTOR_ERROR | DM_EVENT_DEVICE_ERROR | \
|
||||
DM_EVENT_PATH_ERROR | DM_EVENT_ADAPTOR_ERROR)
|
||||
int dm_event_handler_set_uuid(struct dm_event_handler *dmevh, const char *uuid);
|
||||
|
||||
/* Prototypes for event lib interface. */
|
||||
void dm_event_handler_set_major(struct dm_event_handler *dmevh, int major);
|
||||
void dm_event_handler_set_minor(struct dm_event_handler *dmevh, int minor);
|
||||
void dm_event_handler_set_timeout(struct dm_event_handler *dmevh, int timeout);
|
||||
|
||||
/* FIXME Replace device with standard name/uuid/devno choice */
|
||||
/* Interface changes:
|
||||
First register a handler, passing in a unique ref for the device. */
|
||||
// int dm_event_register_handler(const char *dso_name, const char *device);
|
||||
// int dm_event_register(const char *dso_name, const char *name, const char *uuid, uint32_t major, uint32_t minor, enum dm_event_type events);
|
||||
/* Or (better?) add to task structure and use existing functions - run a task to register/unregister events - we may need to run task withe that with the new event mechanism anyway, then the dso calls just hook in.
|
||||
*/
|
||||
|
||||
/* FIXME Missing consts? */
|
||||
int dm_event_register(char *dso_name, char *device, enum dm_event_type events);
|
||||
int dm_event_unregister(char *dso_name, char *device,
|
||||
enum dm_event_type events);
|
||||
int dm_event_get_registered_device(char **dso_name, char **device,
|
||||
enum dm_event_type *events, int next);
|
||||
int dm_event_set_timeout(char *device, uint32_t timeout);
|
||||
int dm_event_get_timeout(char *device, uint32_t *timeout);
|
||||
/*
|
||||
* Specify mask for events to monitor.
|
||||
*/
|
||||
void dm_event_handler_set_event_mask(struct dm_event_handler *dmevh,
|
||||
enum dm_event_mask evmask);
|
||||
|
||||
/* Prototypes for DSO interface. */
|
||||
void process_event(const char *device, enum dm_event_type event);
|
||||
int register_device(const char *device);
|
||||
int unregister_device(const char *device);
|
||||
const char *dm_event_handler_get_dso(const struct dm_event_handler *dmevh);
|
||||
const char *dm_event_handler_get_dev_name(const struct dm_event_handler *dmevh);
|
||||
const char *dm_event_handler_get_uuid(const struct dm_event_handler *dmevh);
|
||||
int dm_event_handler_get_major(const struct dm_event_handler *dmevh);
|
||||
int dm_event_handler_get_minor(const struct dm_event_handler *dmevh);
|
||||
int dm_event_handler_get_timeout(const struct dm_event_handler *dmevh);
|
||||
enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler *dmevh);
|
||||
|
||||
/* FIXME Review interface (what about this next thing?) */
|
||||
int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next);
|
||||
|
||||
/*
|
||||
* Initiate monitoring using dmeventd.
|
||||
*/
|
||||
int dm_event_register_handler(const struct dm_event_handler *dmevh);
|
||||
int dm_event_unregister_handler(const struct dm_event_handler *dmevh);
|
||||
|
||||
/* Prototypes for DSO interface, see dmeventd.c, struct dso_data for
|
||||
detailed descriptions. */
|
||||
void process_event(struct dm_task *dmt, enum dm_event_mask evmask, void **user);
|
||||
int register_device(const char *device_name, const char *uuid, int major, int minor, void **user);
|
||||
int unregister_device(const char *device_name, const char *uuid, int major,
|
||||
int minor, void **user);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "libdevmapper.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
@@ -26,79 +25,104 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||
/* FIXME Missing openlog? */
|
||||
|
||||
#define ME_IGNORE 0
|
||||
#define ME_INSYNC 1
|
||||
#define ME_FAILURE 2
|
||||
|
||||
static pthread_mutex_t _lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
/*
|
||||
* register_device() is called first and performs initialisation.
|
||||
* Only one device may be registered or unregistered at a time.
|
||||
*/
|
||||
static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/* FIXME: We may need to lock around operations to these */
|
||||
static int register_count = 0;
|
||||
static struct dm_pool *mem_pool = NULL;
|
||||
/*
|
||||
* Number of active registrations.
|
||||
*/
|
||||
static int _register_count = 0;
|
||||
|
||||
static struct dm_pool *_mem_pool = NULL;
|
||||
static void *_lvm_handle = NULL;
|
||||
|
||||
/*
|
||||
* Currently only one event can be processed at a time.
|
||||
*/
|
||||
static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
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];
|
||||
int i, r = ME_INSYNC;
|
||||
char **args = NULL;
|
||||
char *dev_status_str;
|
||||
char *log_status_str;
|
||||
char *sync_str;
|
||||
char *p;
|
||||
int log_argc, num_devs, num_failures=0;
|
||||
|
||||
if (max_args <= dm_split_words(params, max_args, 0, args)) {
|
||||
syslog(LOG_ERR, "Unable to split mirror parameters: Arg list too long");
|
||||
return -E2BIG;
|
||||
}
|
||||
char *p = NULL;
|
||||
int log_argc, num_devs;
|
||||
|
||||
/*
|
||||
* 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];
|
||||
* dm core parms: 0 409600 mirror
|
||||
* Mirror core parms: 2 253:4 253:5 400/400
|
||||
* New-style failure params: 1 AA
|
||||
* New-style log params: 3 cluster 253:3 A
|
||||
* or 3 disk 253:3 A
|
||||
* or 1 core
|
||||
*/
|
||||
|
||||
/* number of devices */
|
||||
if (!dm_split_words(params, 1, 0, &p))
|
||||
goto out_parse;
|
||||
|
||||
if (!(num_devs = atoi(p)))
|
||||
goto out_parse;
|
||||
p += strlen(p) + 1;
|
||||
|
||||
/* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */
|
||||
args = dm_malloc((num_devs + 7) * sizeof(char *));
|
||||
if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5)
|
||||
goto out_parse;
|
||||
|
||||
dev_status_str = args[2 + num_devs];
|
||||
log_argc = atoi(args[3 + num_devs]);
|
||||
log_status_str = args[3 + num_devs + log_argc];
|
||||
sync_str = args[num_devs];
|
||||
|
||||
/* Check for bad mirror devices */
|
||||
for (i = 0; i < num_devs; i++) {
|
||||
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++;
|
||||
syslog(LOG_ERR, "Mirror device, %s, has failed.\n", args[i]);
|
||||
r = ME_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for bad log device */
|
||||
if (log_status_str[0] == 'D') {
|
||||
/* Check for bad disk log device */
|
||||
if (log_argc > 1 && log_status_str[0] == 'D') {
|
||||
syslog(LOG_ERR, "Log device, %s, has failed.\n",
|
||||
args[3 + num_devs + log_argc]);
|
||||
num_failures++;
|
||||
args[2 + num_devs + log_argc]);
|
||||
r = ME_FAILURE;
|
||||
}
|
||||
|
||||
if (num_failures) {
|
||||
rtn = ME_FAILURE;
|
||||
if (r == ME_FAILURE)
|
||||
goto out;
|
||||
}
|
||||
|
||||
p = strstr(sync_str, "/");
|
||||
if (p) {
|
||||
p[0] = '\0';
|
||||
if (strcmp(sync_str, p+1))
|
||||
rtn = ME_IGNORE;
|
||||
r = 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;
|
||||
} else
|
||||
goto out_parse;
|
||||
|
||||
out:
|
||||
if (args)
|
||||
dm_free(args);
|
||||
return r;
|
||||
|
||||
out_parse:
|
||||
if (args)
|
||||
dm_free(args);
|
||||
syslog(LOG_ERR, "Unable to parse mirror status string.");
|
||||
return ME_IGNORE;
|
||||
}
|
||||
|
||||
static void _temporary_log_fn(int level, const char *file,
|
||||
@@ -113,69 +137,55 @@ static void _temporary_log_fn(int level, const char *file,
|
||||
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];
|
||||
#define 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 (strlen(device) > 200) /* FIXME Use real restriction */
|
||||
return -ENAMETOOLONG; /* FIXME These return code distinctions are not used so remove them! */
|
||||
|
||||
if (!dm_split_lvm_name(mem_pool, device, &vg, &lv, &layer)) {
|
||||
if (!dm_split_lvm_name(_mem_pool, device, &vg, &lv, &layer)) {
|
||||
syslog(LOG_ERR, "Unable to determine VG name from %s",
|
||||
device);
|
||||
return -ENOMEM;
|
||||
return -ENOMEM; /* FIXME Replace with generic error return - reason for failure has already got logged */
|
||||
}
|
||||
|
||||
/* FIXME Is any sanity-checking required on %s? */
|
||||
if (cmd_size <= snprintf(cmd_str, cmd_size, "vgreduce --removemissing %s", vg)) {
|
||||
if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "vgreduce --config devices{ignore_suspended_devices=1} --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;
|
||||
dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */
|
||||
return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */
|
||||
}
|
||||
|
||||
lvm2_log_fn(_temporary_log_fn);
|
||||
handle = lvm2_init();
|
||||
lvm2_log_level(handle, 1);
|
||||
r = lvm2_run(handle, cmd_str);
|
||||
r = lvm2_run(_lvm_handle, cmd_str);
|
||||
|
||||
dm_pool_empty(mem_pool); /* FIXME: not safe with multiple threads */
|
||||
return (r == 1)? 0: -1;
|
||||
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)
|
||||
void process_event(struct dm_task *dmt, enum dm_event_mask event,
|
||||
void **unused __attribute((unused)))
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
const char *device = dm_task_get_name(dmt);
|
||||
|
||||
if (pthread_mutex_trylock(&_lock)) {
|
||||
if (pthread_mutex_trylock(&_event_mutex)) {
|
||||
syslog(LOG_NOTICE, "Another thread is handling an event. Waiting...");
|
||||
pthread_mutex_lock(&_lock);
|
||||
pthread_mutex_lock(&_event_mutex);
|
||||
}
|
||||
/* 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 (!target_type) {
|
||||
syslog(LOG_INFO, "%s mapping lost.\n", device);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(target_type, "mirror")) {
|
||||
syslog(LOG_INFO, "%s has unmirrored portion.\n", device);
|
||||
continue;
|
||||
@@ -192,6 +202,7 @@ void process_event(const char *device, enum dm_event_type event)
|
||||
case ME_FAILURE:
|
||||
syslog(LOG_ERR, "Device failure in %s\n", device);
|
||||
if (_remove_failed_devices(device))
|
||||
/* FIXME Why are all the error return codes unused? Get rid of them? */
|
||||
syslog(LOG_ERR, "Failed to remove faulty devices in %s\n",
|
||||
device);
|
||||
/* Should check before warning user that device is now linear
|
||||
@@ -203,52 +214,68 @@ void process_event(const char *device, enum dm_event_type event)
|
||||
case ME_IGNORE:
|
||||
break;
|
||||
default:
|
||||
/* FIXME Provide value then! */
|
||||
syslog(LOG_INFO, "Unknown event received.\n");
|
||||
}
|
||||
} while (next);
|
||||
|
||||
fail:
|
||||
if (dmt)
|
||||
dm_task_destroy(dmt);
|
||||
pthread_mutex_unlock(&_lock);
|
||||
pthread_mutex_unlock(&_event_mutex);
|
||||
}
|
||||
|
||||
int register_device(const char *device)
|
||||
int register_device(const char *device, const char *uuid, int major, int minor,
|
||||
void **unused __attribute((unused)))
|
||||
{
|
||||
syslog(LOG_INFO, "Monitoring mirror device, %s for events\n", device);
|
||||
int r = 0;
|
||||
|
||||
pthread_mutex_lock(&_register_mutex);
|
||||
|
||||
syslog(LOG_INFO, "Monitoring mirror device %s for events\n", device);
|
||||
|
||||
/*
|
||||
* Need some space for allocations. 1024 should be more
|
||||
* than enough for what we need (device mapper name splitting)
|
||||
*/
|
||||
if (!mem_pool)
|
||||
mem_pool = dm_pool_create("mirror_dso", 1024);
|
||||
if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024)))
|
||||
goto out;
|
||||
|
||||
if (!mem_pool)
|
||||
return 0;
|
||||
|
||||
register_count++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int unregister_device(const char *device)
|
||||
{
|
||||
if (!(--register_count)) {
|
||||
dm_pool_destroy(mem_pool);
|
||||
mem_pool = NULL;
|
||||
if (!_lvm_handle) {
|
||||
lvm2_log_fn(_temporary_log_fn);
|
||||
if (!(_lvm_handle = lvm2_init())) {
|
||||
dm_pool_destroy(_mem_pool);
|
||||
_mem_pool = NULL;
|
||||
goto out;
|
||||
}
|
||||
lvm2_log_level(_lvm_handle, LVM2_LOG_SUPPRESS);
|
||||
/* FIXME Temporary: move to dmeventd core */
|
||||
lvm2_run(_lvm_handle, "_memlock_inc");
|
||||
}
|
||||
|
||||
return 1;
|
||||
_register_count++;
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&_register_mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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:
|
||||
*/
|
||||
int unregister_device(const char *device, const char *uuid, int major, int minor,
|
||||
void **unused __attribute((unused)))
|
||||
{
|
||||
pthread_mutex_lock(&_register_mutex);
|
||||
|
||||
syslog(LOG_INFO, "No longer monitoring mirror device %s for events\n",
|
||||
device);
|
||||
|
||||
if (!--_register_count) {
|
||||
dm_pool_destroy(_mem_pool);
|
||||
_mem_pool = NULL;
|
||||
lvm2_run(_lvm_handle, "_memlock_dec");
|
||||
lvm2_exit(_lvm_handle);
|
||||
_lvm_handle = NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_register_mutex);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "libdevmapper.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
@@ -26,79 +25,104 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <syslog.h> /* FIXME Replace syslog with multilog */
|
||||
/* FIXME Missing openlog? */
|
||||
|
||||
#define ME_IGNORE 0
|
||||
#define ME_INSYNC 1
|
||||
#define ME_FAILURE 2
|
||||
|
||||
static pthread_mutex_t _lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
/*
|
||||
* register_device() is called first and performs initialisation.
|
||||
* Only one device may be registered or unregistered at a time.
|
||||
*/
|
||||
static pthread_mutex_t _register_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/* FIXME: We may need to lock around operations to these */
|
||||
static int register_count = 0;
|
||||
static struct dm_pool *mem_pool = NULL;
|
||||
/*
|
||||
* Number of active registrations.
|
||||
*/
|
||||
static int _register_count = 0;
|
||||
|
||||
static struct dm_pool *_mem_pool = NULL;
|
||||
static void *_lvm_handle = NULL;
|
||||
|
||||
/*
|
||||
* Currently only one event can be processed at a time.
|
||||
*/
|
||||
static pthread_mutex_t _event_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
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];
|
||||
int i, r = ME_INSYNC;
|
||||
char **args = NULL;
|
||||
char *dev_status_str;
|
||||
char *log_status_str;
|
||||
char *sync_str;
|
||||
char *p;
|
||||
int log_argc, num_devs, num_failures=0;
|
||||
|
||||
if (max_args <= dm_split_words(params, max_args, 0, args)) {
|
||||
syslog(LOG_ERR, "Unable to split mirror parameters: Arg list too long");
|
||||
return -E2BIG;
|
||||
}
|
||||
char *p = NULL;
|
||||
int log_argc, num_devs;
|
||||
|
||||
/*
|
||||
* 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];
|
||||
* dm core parms: 0 409600 mirror
|
||||
* Mirror core parms: 2 253:4 253:5 400/400
|
||||
* New-style failure params: 1 AA
|
||||
* New-style log params: 3 cluster 253:3 A
|
||||
* or 3 disk 253:3 A
|
||||
* or 1 core
|
||||
*/
|
||||
|
||||
/* number of devices */
|
||||
if (!dm_split_words(params, 1, 0, &p))
|
||||
goto out_parse;
|
||||
|
||||
if (!(num_devs = atoi(p)))
|
||||
goto out_parse;
|
||||
p += strlen(p) + 1;
|
||||
|
||||
/* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */
|
||||
args = dm_malloc((num_devs + 7) * sizeof(char *));
|
||||
if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5)
|
||||
goto out_parse;
|
||||
|
||||
dev_status_str = args[2 + num_devs];
|
||||
log_argc = atoi(args[3 + num_devs]);
|
||||
log_status_str = args[3 + num_devs + log_argc];
|
||||
sync_str = args[num_devs];
|
||||
|
||||
/* Check for bad mirror devices */
|
||||
for (i = 0; i < num_devs; i++) {
|
||||
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++;
|
||||
syslog(LOG_ERR, "Mirror device, %s, has failed.\n", args[i]);
|
||||
r = ME_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for bad log device */
|
||||
if (log_status_str[0] == 'D') {
|
||||
/* Check for bad disk log device */
|
||||
if (log_argc > 1 && log_status_str[0] == 'D') {
|
||||
syslog(LOG_ERR, "Log device, %s, has failed.\n",
|
||||
args[3 + num_devs + log_argc]);
|
||||
num_failures++;
|
||||
args[2 + num_devs + log_argc]);
|
||||
r = ME_FAILURE;
|
||||
}
|
||||
|
||||
if (num_failures) {
|
||||
rtn = ME_FAILURE;
|
||||
if (r == ME_FAILURE)
|
||||
goto out;
|
||||
}
|
||||
|
||||
p = strstr(sync_str, "/");
|
||||
if (p) {
|
||||
p[0] = '\0';
|
||||
if (strcmp(sync_str, p+1))
|
||||
rtn = ME_IGNORE;
|
||||
r = 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;
|
||||
} else
|
||||
goto out_parse;
|
||||
|
||||
out:
|
||||
if (args)
|
||||
dm_free(args);
|
||||
return r;
|
||||
|
||||
out_parse:
|
||||
if (args)
|
||||
dm_free(args);
|
||||
syslog(LOG_ERR, "Unable to parse mirror status string.");
|
||||
return ME_IGNORE;
|
||||
}
|
||||
|
||||
static void _temporary_log_fn(int level, const char *file,
|
||||
@@ -113,69 +137,55 @@ static void _temporary_log_fn(int level, const char *file,
|
||||
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];
|
||||
#define 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 (strlen(device) > 200) /* FIXME Use real restriction */
|
||||
return -ENAMETOOLONG; /* FIXME These return code distinctions are not used so remove them! */
|
||||
|
||||
if (!dm_split_lvm_name(mem_pool, device, &vg, &lv, &layer)) {
|
||||
if (!dm_split_lvm_name(_mem_pool, device, &vg, &lv, &layer)) {
|
||||
syslog(LOG_ERR, "Unable to determine VG name from %s",
|
||||
device);
|
||||
return -ENOMEM;
|
||||
return -ENOMEM; /* FIXME Replace with generic error return - reason for failure has already got logged */
|
||||
}
|
||||
|
||||
/* FIXME Is any sanity-checking required on %s? */
|
||||
if (cmd_size <= snprintf(cmd_str, cmd_size, "vgreduce --removemissing %s", vg)) {
|
||||
if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "vgreduce --config devices{ignore_suspended_devices=1} --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;
|
||||
dm_pool_empty(_mem_pool); /* FIXME: not safe with multiple threads */
|
||||
return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */
|
||||
}
|
||||
|
||||
lvm2_log_fn(_temporary_log_fn);
|
||||
handle = lvm2_init();
|
||||
lvm2_log_level(handle, 1);
|
||||
r = lvm2_run(handle, cmd_str);
|
||||
r = lvm2_run(_lvm_handle, cmd_str);
|
||||
|
||||
dm_pool_empty(mem_pool); /* FIXME: not safe with multiple threads */
|
||||
return (r == 1)? 0: -1;
|
||||
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)
|
||||
void process_event(struct dm_task *dmt, enum dm_event_mask event,
|
||||
void **unused __attribute((unused)))
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
const char *device = dm_task_get_name(dmt);
|
||||
|
||||
if (pthread_mutex_trylock(&_lock)) {
|
||||
if (pthread_mutex_trylock(&_event_mutex)) {
|
||||
syslog(LOG_NOTICE, "Another thread is handling an event. Waiting...");
|
||||
pthread_mutex_lock(&_lock);
|
||||
pthread_mutex_lock(&_event_mutex);
|
||||
}
|
||||
/* 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 (!target_type) {
|
||||
syslog(LOG_INFO, "%s mapping lost.\n", device);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(target_type, "mirror")) {
|
||||
syslog(LOG_INFO, "%s has unmirrored portion.\n", device);
|
||||
continue;
|
||||
@@ -192,6 +202,7 @@ void process_event(const char *device, enum dm_event_type event)
|
||||
case ME_FAILURE:
|
||||
syslog(LOG_ERR, "Device failure in %s\n", device);
|
||||
if (_remove_failed_devices(device))
|
||||
/* FIXME Why are all the error return codes unused? Get rid of them? */
|
||||
syslog(LOG_ERR, "Failed to remove faulty devices in %s\n",
|
||||
device);
|
||||
/* Should check before warning user that device is now linear
|
||||
@@ -203,52 +214,68 @@ void process_event(const char *device, enum dm_event_type event)
|
||||
case ME_IGNORE:
|
||||
break;
|
||||
default:
|
||||
/* FIXME Provide value then! */
|
||||
syslog(LOG_INFO, "Unknown event received.\n");
|
||||
}
|
||||
} while (next);
|
||||
|
||||
fail:
|
||||
if (dmt)
|
||||
dm_task_destroy(dmt);
|
||||
pthread_mutex_unlock(&_lock);
|
||||
pthread_mutex_unlock(&_event_mutex);
|
||||
}
|
||||
|
||||
int register_device(const char *device)
|
||||
int register_device(const char *device, const char *uuid, int major, int minor,
|
||||
void **unused __attribute((unused)))
|
||||
{
|
||||
syslog(LOG_INFO, "Monitoring mirror device, %s for events\n", device);
|
||||
int r = 0;
|
||||
|
||||
pthread_mutex_lock(&_register_mutex);
|
||||
|
||||
syslog(LOG_INFO, "Monitoring mirror device %s for events\n", device);
|
||||
|
||||
/*
|
||||
* Need some space for allocations. 1024 should be more
|
||||
* than enough for what we need (device mapper name splitting)
|
||||
*/
|
||||
if (!mem_pool)
|
||||
mem_pool = dm_pool_create("mirror_dso", 1024);
|
||||
if (!_mem_pool && !(_mem_pool = dm_pool_create("mirror_dso", 1024)))
|
||||
goto out;
|
||||
|
||||
if (!mem_pool)
|
||||
return 0;
|
||||
|
||||
register_count++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int unregister_device(const char *device)
|
||||
{
|
||||
if (!(--register_count)) {
|
||||
dm_pool_destroy(mem_pool);
|
||||
mem_pool = NULL;
|
||||
if (!_lvm_handle) {
|
||||
lvm2_log_fn(_temporary_log_fn);
|
||||
if (!(_lvm_handle = lvm2_init())) {
|
||||
dm_pool_destroy(_mem_pool);
|
||||
_mem_pool = NULL;
|
||||
goto out;
|
||||
}
|
||||
lvm2_log_level(_lvm_handle, LVM2_LOG_SUPPRESS);
|
||||
/* FIXME Temporary: move to dmeventd core */
|
||||
lvm2_run(_lvm_handle, "_memlock_inc");
|
||||
}
|
||||
|
||||
return 1;
|
||||
_register_count++;
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&_register_mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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:
|
||||
*/
|
||||
int unregister_device(const char *device, const char *uuid, int major, int minor,
|
||||
void **unused __attribute((unused)))
|
||||
{
|
||||
pthread_mutex_lock(&_register_mutex);
|
||||
|
||||
syslog(LOG_INFO, "No longer monitoring mirror device %s for events\n",
|
||||
device);
|
||||
|
||||
if (!--_register_count) {
|
||||
dm_pool_destroy(_mem_pool);
|
||||
_mem_pool = NULL;
|
||||
lvm2_run(_lvm_handle, "_memlock_dec");
|
||||
lvm2_exit(_lvm_handle);
|
||||
_lvm_handle = NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_register_mutex);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -79,6 +79,12 @@ devices {
|
||||
# software RAID (md) devices by looking for md superblocks.
|
||||
# 1 enables; 0 disables.
|
||||
md_component_detection = 1
|
||||
|
||||
# If, while scanning the system for PVs, LVM2 encounters a device-mapper
|
||||
# device that has its I/O suspended, it waits for it to become accessible.
|
||||
# Set this to 1 to skip such devices. This should only be needed
|
||||
# in recovery situations.
|
||||
ignore_suspended_devices = 0
|
||||
}
|
||||
|
||||
# This section that allows you to configure the nature of the
|
||||
|
||||
@@ -141,7 +141,7 @@ int target_version(const char *target_name, uint32_t *maj,
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int target_present(const char *target_name)
|
||||
int target_present(const char *target_name, int use_modprobe)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -211,7 +211,7 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pv_uses_vg(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
int pv_uses_vg(struct physical_volume *pv,
|
||||
struct volume_group *vg)
|
||||
{
|
||||
return 0;
|
||||
@@ -640,50 +640,89 @@ int lvs_in_vg_opened(struct volume_group *vg)
|
||||
}
|
||||
|
||||
/*
|
||||
* register_dev_for_events
|
||||
*
|
||||
* This function uses proper error codes (but breaks convention)
|
||||
* to return:
|
||||
* -1 on error
|
||||
* 0 if the lv's targets don't do event [un]registration
|
||||
* 0 if the lv is already [un]registered -- FIXME: not implemented
|
||||
* 1 if the lv had a segment which was [un]registered
|
||||
*
|
||||
* Returns: -1 on error
|
||||
* Returns 0 if an attempt to (un)monitor the device failed.
|
||||
* Returns 1 otherwise.
|
||||
*/
|
||||
int register_dev_for_events(struct cmd_context *cmd,
|
||||
struct logical_volume *lv, int do_reg)
|
||||
int monitor_dev_for_events(struct cmd_context *cmd,
|
||||
struct logical_volume *lv, int monitor)
|
||||
{
|
||||
#ifdef DMEVENTD
|
||||
int r = 0;
|
||||
int i, pending = 0, monitored;
|
||||
int r = 1;
|
||||
struct list *tmp;
|
||||
struct lv_segment *seg;
|
||||
int (*reg) (struct lv_segment *, int events);
|
||||
int (*monitor_fn) (struct lv_segment *s, int e);
|
||||
|
||||
if (do_reg && !dmeventd_register_mode())
|
||||
/* skip dmeventd code altogether */
|
||||
if (dmeventd_monitor_mode() == DMEVENTD_MONITOR_IGNORE)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Nothing to do if dmeventd configured not to be used.
|
||||
*/
|
||||
if (monitor && !dmeventd_monitor_mode())
|
||||
return 1;
|
||||
|
||||
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)
|
||||
if (!seg_monitored(seg) || (seg->status & PVMOVE))
|
||||
continue;
|
||||
|
||||
/* FIXME specify events */
|
||||
if (!reg(seg, 0)) {
|
||||
stack;
|
||||
return -1;
|
||||
monitor_fn = NULL;
|
||||
|
||||
/* Check monitoring status */
|
||||
if (seg->segtype->ops->target_monitored)
|
||||
monitored = seg->segtype->ops->target_monitored(seg, &pending);
|
||||
else
|
||||
continue; /* segtype doesn't support registration */
|
||||
|
||||
/*
|
||||
* FIXME: We should really try again if pending
|
||||
*/
|
||||
monitored = (pending) ? 0 : monitored;
|
||||
|
||||
if (monitor) {
|
||||
if (monitored)
|
||||
log_verbose("%s/%s already monitored.", lv->vg->name, lv->name);
|
||||
else if (seg->segtype->ops->target_monitor_events)
|
||||
monitor_fn = seg->segtype->ops->target_monitor_events;
|
||||
} else {
|
||||
if (!monitored)
|
||||
log_verbose("%s/%s already not monitored.", lv->vg->name, lv->name);
|
||||
else if (seg->segtype->ops->target_unmonitor_events)
|
||||
monitor_fn = seg->segtype->ops->target_unmonitor_events;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
/* Do [un]monitor */
|
||||
if (!monitor_fn)
|
||||
continue;
|
||||
|
||||
log_verbose("%sonitoring %s/%s", monitor ? "M" : "Not m", lv->vg->name, lv->name);
|
||||
|
||||
/* FIXME specify events */
|
||||
if (!monitor_fn(seg, 0)) {
|
||||
log_error("%s/%s: %s segment monitoring function failed.",
|
||||
lv->vg->name, lv->name, seg->segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check [un]monitor results */
|
||||
/* Try a couple times if pending, but not forever... */
|
||||
for (i = 0; i < 10; i++) {
|
||||
pending = 0;
|
||||
monitored = seg->segtype->ops->target_monitored(seg, &pending);
|
||||
if (pending ||
|
||||
(!monitored && monitor) ||
|
||||
(monitored && !monitor))
|
||||
log_very_verbose("%s/%s %smonitoring still pending: waiting...",
|
||||
lv->vg->name, lv->name, monitor ? "" : "un");
|
||||
else
|
||||
break;
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
r = (monitored && monitor) || (!monitored && !monitor);
|
||||
}
|
||||
|
||||
return r;
|
||||
@@ -728,7 +767,7 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
}
|
||||
}
|
||||
|
||||
if (register_dev_for_events(cmd, lv, 0) != 1)
|
||||
if (!monitor_dev_for_events(cmd, lv, 0))
|
||||
/* FIXME Consider aborting here */
|
||||
stack;
|
||||
|
||||
@@ -786,7 +825,7 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
||||
memlock_dec();
|
||||
fs_unlock();
|
||||
|
||||
if (register_dev_for_events(cmd, lv, 1) != 1)
|
||||
if (!monitor_dev_for_events(cmd, lv, 1))
|
||||
stack;
|
||||
|
||||
return 1;
|
||||
@@ -832,7 +871,7 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (register_dev_for_events(cmd, lv, 0) != 1)
|
||||
if (!monitor_dev_for_events(cmd, lv, 0))
|
||||
stack;
|
||||
|
||||
memlock_inc();
|
||||
@@ -905,7 +944,7 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
memlock_dec();
|
||||
fs_unlock();
|
||||
|
||||
if (!register_dev_for_events(cmd, lv, 1) != 1)
|
||||
if (!monitor_dev_for_events(cmd, lv, 1))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
|
||||
@@ -86,7 +86,7 @@ int lvs_in_vg_activated(struct volume_group *vg);
|
||||
int lvs_in_vg_opened(struct volume_group *vg);
|
||||
|
||||
|
||||
int register_dev_for_events(struct cmd_context *cmd,
|
||||
int monitor_dev_for_events(struct cmd_context *cmd,
|
||||
struct logical_volume *lv, int do_reg);
|
||||
|
||||
/*
|
||||
@@ -95,4 +95,9 @@ int register_dev_for_events(struct cmd_context *cmd,
|
||||
int pv_uses_vg(struct physical_volume *pv,
|
||||
struct volume_group *vg);
|
||||
|
||||
/*
|
||||
* Returns 1 if mapped device is not suspended.
|
||||
*/
|
||||
int device_is_usable(dev_t dev);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "targets.h"
|
||||
#include "config.h"
|
||||
#include "filter.h"
|
||||
#include "activate.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
@@ -154,6 +155,58 @@ static int _info_run(const char *name, const char *dlid, struct dm_info *info,
|
||||
return r;
|
||||
}
|
||||
|
||||
int device_is_usable(dev_t dev)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
struct dm_info info;
|
||||
const char *name;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
void *next = NULL;
|
||||
int r = 0;
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) {
|
||||
log_error("Failed to allocate dm_task struct to check dev status");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dm_task_set_major(dmt, MAJOR(dev)) || !dm_task_set_minor(dmt, MINOR(dev)))
|
||||
goto_out;
|
||||
|
||||
if (!dm_task_run(dmt)) {
|
||||
log_error("Failed to get state of mapped device");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!dm_task_get_info(dmt, &info))
|
||||
goto_out;
|
||||
|
||||
if (!info.exists || info.suspended)
|
||||
goto out;
|
||||
|
||||
name = dm_task_get_name(dmt);
|
||||
|
||||
/* FIXME Also check for mirror block_on_error and mpath no paths */
|
||||
/* For now, we exclude all mirrors */
|
||||
|
||||
do {
|
||||
next = dm_get_next_target(dmt, next, &start, &length,
|
||||
&target_type, ¶ms);
|
||||
/* Skip if target type doesn't match */
|
||||
if (!strcmp(target_type, "mirror"))
|
||||
goto out;
|
||||
} while (next);
|
||||
|
||||
/* FIXME Also check dependencies? */
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _info(const char *name, const char *dlid, int mknodes,
|
||||
int with_open_count, struct dm_info *info,
|
||||
struct dm_pool *mem, char **uuid_out)
|
||||
@@ -993,6 +1046,8 @@ static int _tree_action(struct dev_manager *dm, struct logical_volume *lv, actio
|
||||
break;
|
||||
case SUSPEND:
|
||||
dm_tree_skip_lockfs(root);
|
||||
if ((lv->status & MIRRORED) && !(lv->status & PVMOVE))
|
||||
dm_tree_use_no_flush_suspend(root);
|
||||
case SUSPEND_WITH_LOCKFS:
|
||||
if (!dm_tree_suspend_children(root, dlid, ID_LEN + sizeof(UUID_PREFIX) - 1))
|
||||
goto_out;
|
||||
@@ -1072,7 +1127,7 @@ int dev_manager_device_uses_vg(struct device *dev,
|
||||
{
|
||||
struct dm_tree *dtree;
|
||||
struct dm_tree_node *root;
|
||||
char dlid[sizeof(UUID_PREFIX) + sizeof(struct id) - 1];
|
||||
char dlid[sizeof(UUID_PREFIX) + sizeof(struct id) - 1] __attribute((aligned(8)));
|
||||
int r = 1;
|
||||
|
||||
if (!(dtree = dm_tree_create())) {
|
||||
|
||||
13
lib/cache/lvmcache.c
vendored
13
lib/cache/lvmcache.c
vendored
@@ -114,7 +114,7 @@ const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid)
|
||||
struct list *devh, *tmp;
|
||||
struct list devs;
|
||||
struct device_list *devl;
|
||||
char vgid_found[ID_LEN + 1];
|
||||
char vgid_found[ID_LEN + 1] __attribute((aligned(8)));
|
||||
|
||||
if (!(vginfo = vginfo_from_vgname(vgname, vgid)))
|
||||
return NULL;
|
||||
@@ -151,7 +151,7 @@ const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid)
|
||||
struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
char id[ID_LEN + 1];
|
||||
char id[ID_LEN + 1] __attribute((aligned(8)));
|
||||
|
||||
if (!_vgid_hash || !vgid)
|
||||
return NULL;
|
||||
@@ -186,7 +186,7 @@ const char *vgname_from_vgid(struct dm_pool *mem, const char *vgid)
|
||||
struct lvmcache_info *info_from_pvid(const char *pvid)
|
||||
{
|
||||
struct lvmcache_info *info;
|
||||
char id[ID_LEN + 1];
|
||||
char id[ID_LEN + 1] __attribute((aligned(8)));
|
||||
|
||||
if (!_pvid_hash || !pvid)
|
||||
return NULL;
|
||||
@@ -476,7 +476,8 @@ static int _insert_vginfo(struct lvmcache_vginfo *new_vginfo, const char *vgid,
|
||||
struct lvmcache_vginfo *primary_vginfo)
|
||||
{
|
||||
struct lvmcache_vginfo *last_vginfo = primary_vginfo;
|
||||
char uuid_primary[64], uuid_new[64];
|
||||
char uuid_primary[64] __attribute((aligned(8)));
|
||||
char uuid_new[64] __attribute((aligned(8)));
|
||||
int use_new = 0;
|
||||
|
||||
/* Pre-existing VG takes precedence. Unexported VG takes precedence. */
|
||||
@@ -709,7 +710,7 @@ int lvmcache_update_vg(struct volume_group *vg)
|
||||
{
|
||||
struct pv_list *pvl;
|
||||
struct lvmcache_info *info;
|
||||
char pvid_s[ID_LEN + 1];
|
||||
char pvid_s[ID_LEN + 1] __attribute((aligned(8)));
|
||||
|
||||
pvid_s[sizeof(pvid_s) - 1] = '\0';
|
||||
|
||||
@@ -733,7 +734,7 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||
{
|
||||
struct label *label;
|
||||
struct lvmcache_info *existing, *info;
|
||||
char pvid_s[ID_LEN + 1];
|
||||
char pvid_s[ID_LEN + 1] __attribute((aligned(8)));
|
||||
|
||||
if (!_vgname_hash && !lvmcache_init()) {
|
||||
log_error("Internal cache initialisation failed");
|
||||
|
||||
@@ -59,8 +59,6 @@
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
|
||||
static FILE *_log;
|
||||
|
||||
static int _get_env_vars(struct cmd_context *cmd)
|
||||
{
|
||||
const char *e;
|
||||
@@ -575,7 +573,7 @@ static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
|
||||
filters[0] : composite_filter_create(nr_filt, filters);
|
||||
}
|
||||
|
||||
static int _init_filters(struct cmd_context *cmd)
|
||||
static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
|
||||
{
|
||||
const char *dev_cache;
|
||||
struct dev_filter *f3, *f4;
|
||||
@@ -594,6 +592,9 @@ static int _init_filters(struct cmd_context *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
init_ignore_suspended_devices(find_config_tree_int(cmd,
|
||||
"devices/ignore_suspended_devices", DEFAULT_IGNORE_SUSPENDED_DEVICES));
|
||||
|
||||
dev_cache = find_config_tree_str(cmd, "devices/cache",
|
||||
cache_file);
|
||||
if (!(f4 = persistent_filter_create(f3, dev_cache))) {
|
||||
@@ -608,8 +609,13 @@ static int _init_filters(struct cmd_context *cmd)
|
||||
if (!*cmd->sys_dir)
|
||||
cmd->dump_filter = 0;
|
||||
|
||||
if (!stat(dev_cache, &st) &&
|
||||
(st.st_ctime != config_file_timestamp(cmd->cft)) &&
|
||||
/*
|
||||
* Only load persistent filter device cache on startup if it is newer
|
||||
* than the config file and this is not a long-lived process.
|
||||
*/
|
||||
if (load_persistent_cache && !cmd->is_long_lived &&
|
||||
!stat(dev_cache, &st) &&
|
||||
(st.st_ctime > config_file_timestamp(cmd->cft)) &&
|
||||
!persistent_filter_load(f4, NULL))
|
||||
log_verbose("Failed to load existing device cache from %s",
|
||||
dev_cache);
|
||||
@@ -881,7 +887,8 @@ static int _init_backup(struct cmd_context *cmd)
|
||||
}
|
||||
|
||||
/* Entry point */
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static)
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static,
|
||||
unsigned is_long_lived)
|
||||
{
|
||||
struct cmd_context *cmd;
|
||||
|
||||
@@ -905,6 +912,7 @@ struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static)
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->args = the_args;
|
||||
cmd->is_static = is_static;
|
||||
cmd->is_long_lived = is_long_lived;
|
||||
cmd->hosttags = 0;
|
||||
list_init(&cmd->formats);
|
||||
list_init(&cmd->segtypes);
|
||||
@@ -953,7 +961,7 @@ struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static)
|
||||
if (!_init_dev_cache(cmd))
|
||||
goto error;
|
||||
|
||||
if (!_init_filters(cmd))
|
||||
if (!_init_filters(cmd, 1))
|
||||
goto error;
|
||||
|
||||
if (!(cmd->mem = dm_pool_create("command", 4 * 1024))) {
|
||||
@@ -1022,10 +1030,10 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
{
|
||||
log_verbose("Reloading config files");
|
||||
|
||||
if (cmd->config_valid) {
|
||||
if (cmd->dump_filter)
|
||||
persistent_filter_dump(cmd->filter);
|
||||
}
|
||||
/*
|
||||
* Don't update the persistent filter cache as we will
|
||||
* perform a full rescan.
|
||||
*/
|
||||
|
||||
activation_release();
|
||||
lvmcache_destroy();
|
||||
@@ -1064,7 +1072,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
if (!_init_dev_cache(cmd))
|
||||
return 0;
|
||||
|
||||
if (!_init_filters(cmd))
|
||||
if (!_init_filters(cmd, 0))
|
||||
return 0;
|
||||
|
||||
if (!_init_formats(cmd))
|
||||
@@ -1073,6 +1081,13 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
if (!_init_segtypes(cmd))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If we are a long-lived process, write out the updated persistent
|
||||
* device cache for the benefit of short-lived processes.
|
||||
*/
|
||||
if (cmd->is_long_lived && cmd->dump_filter)
|
||||
persistent_filter_dump(cmd->filter);
|
||||
|
||||
cmd->config_valid = 1;
|
||||
return 1;
|
||||
}
|
||||
@@ -1100,8 +1115,4 @@ void destroy_toolcontext(struct cmd_context *cmd)
|
||||
activation_exit();
|
||||
fin_log();
|
||||
fin_syslog();
|
||||
|
||||
if (_log)
|
||||
fclose(_log);
|
||||
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ struct cmd_context {
|
||||
struct arg *args;
|
||||
char **argv;
|
||||
unsigned is_static; /* Static binary? */
|
||||
unsigned is_long_lived; /* Optimises persistent_filter handling */
|
||||
|
||||
struct dev_filter *filter;
|
||||
int dump_filter; /* Dump filter when exiting? */
|
||||
@@ -88,7 +89,7 @@ struct cmd_context {
|
||||
char proc_dir[PATH_MAX];
|
||||
};
|
||||
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static);
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args, unsigned is_static, unsigned is_long_lived);
|
||||
void destroy_toolcontext(struct cmd_context *cmd);
|
||||
int refresh_toolcontext(struct cmd_context *cmd);
|
||||
int config_files_changed(struct cmd_context *cmd);
|
||||
|
||||
@@ -373,7 +373,8 @@ static void _write_value(FILE *fp, struct config_value *v)
|
||||
}
|
||||
}
|
||||
|
||||
static int _write_config(struct config_node *n, FILE *fp, int level)
|
||||
static int _write_config(struct config_node *n, int only_one, FILE *fp,
|
||||
int level)
|
||||
{
|
||||
char space[MAX_INDENT + 1];
|
||||
int l = (level < MAX_INDENT) ? level : MAX_INDENT;
|
||||
@@ -386,12 +387,12 @@ static int _write_config(struct config_node *n, FILE *fp, int level)
|
||||
space[i] = '\t';
|
||||
space[i] = '\0';
|
||||
|
||||
while (n) {
|
||||
do {
|
||||
fprintf(fp, "%s%s", space, n->key);
|
||||
if (!n->v) {
|
||||
/* it's a sub section */
|
||||
fprintf(fp, " {\n");
|
||||
_write_config(n->child, fp, level + 1);
|
||||
_write_config(n->child, 0, fp, level + 1);
|
||||
fprintf(fp, "%s}", space);
|
||||
} else {
|
||||
/* it's a value */
|
||||
@@ -411,13 +412,15 @@ static int _write_config(struct config_node *n, FILE *fp, int level)
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
n = n->sib;
|
||||
}
|
||||
} while (n && !only_one);
|
||||
/* FIXME: add error checking */
|
||||
return 1;
|
||||
}
|
||||
|
||||
int write_config_file(struct config_tree *cft, const char *file)
|
||||
int write_config_file(struct config_tree *cft, const char *file,
|
||||
int argc, char **argv)
|
||||
{
|
||||
struct config_node *cn;
|
||||
int r = 1;
|
||||
FILE *fp;
|
||||
|
||||
@@ -430,13 +433,28 @@ int write_config_file(struct config_tree *cft, const char *file)
|
||||
}
|
||||
|
||||
log_verbose("Dumping configuration to %s", file);
|
||||
if (!_write_config(cft->root, fp, 0)) {
|
||||
log_error("Failure while writing configuration");
|
||||
r = 0;
|
||||
if (!argc) {
|
||||
if (!_write_config(cft->root, 0, fp, 0)) {
|
||||
log_error("Failure while writing to %s", file);
|
||||
r = 0;
|
||||
}
|
||||
} else while (argc--) {
|
||||
if ((cn = find_config_node(cft->root, *argv))) {
|
||||
if (!_write_config(cn, 1, fp, 0)) {
|
||||
log_error("Failure while writing to %s", file);
|
||||
r = 0;
|
||||
}
|
||||
} else {
|
||||
log_error("Configuration node %s not found", *argv);
|
||||
r = 0;
|
||||
}
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (fp != stdout)
|
||||
fclose(fp);
|
||||
if ((fp != stdout) && fclose(fp)) {
|
||||
log_sys_error("fclose", file);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -837,7 +855,7 @@ static const char *_find_config_str(const struct config_node *cn1,
|
||||
const struct config_node *n = _find_first_config_node(cn1, cn2, path);
|
||||
|
||||
/* Empty strings are ignored */
|
||||
if ((n && n->v->type == CFG_STRING) && (*n->v->v.str)) {
|
||||
if ((n && n->v && n->v->type == CFG_STRING) && (*n->v->v.str)) {
|
||||
log_very_verbose("Setting %s to %s", path, n->v->v.str);
|
||||
return n->v->v.str;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,8 @@ int read_config_fd(struct config_tree *cft, struct device *dev,
|
||||
checksum_fn_t checksum_fn, uint32_t checksum);
|
||||
|
||||
int read_config_file(struct config_tree *cft);
|
||||
int write_config_file(struct config_tree *cft, const char *file);
|
||||
int write_config_file(struct config_tree *cft, const char *file,
|
||||
int argc, char **argv);
|
||||
time_t config_file_timestamp(struct config_tree *cft);
|
||||
int config_file_changed(struct config_tree *cft);
|
||||
int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#define DEFAULT_PROC_DIR "/proc"
|
||||
#define DEFAULT_SYSFS_SCAN 1
|
||||
#define DEFAULT_MD_COMPONENT_DETECTION 1
|
||||
#define DEFAULT_IGNORE_SUSPENDED_DEVICES 1
|
||||
|
||||
#define DEFAULT_LOCK_DIR "/var/lock/lvm"
|
||||
#define DEFAULT_LOCKING_LIB "liblvm2clusterlock.so"
|
||||
|
||||
@@ -292,11 +292,14 @@ int dev_get_sectsize(struct device *dev, uint32_t *size)
|
||||
|
||||
if (ioctl(fd, BLKSSZGET, &s) < 0) {
|
||||
log_sys_error("ioctl BLKSSZGET", name);
|
||||
close(fd);
|
||||
if (close(fd))
|
||||
log_sys_error("close", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
if (close(fd))
|
||||
log_sys_error("close", name);
|
||||
|
||||
*size = (uint32_t) s;
|
||||
|
||||
log_very_verbose("%s: sector size is %" PRIu32 " bytes", name, *size);
|
||||
@@ -605,7 +608,7 @@ int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer)
|
||||
int dev_set(struct device *dev, uint64_t offset, size_t len, int value)
|
||||
{
|
||||
size_t s;
|
||||
char buffer[4096];
|
||||
char buffer[4096] __attribute((aligned(8)));
|
||||
|
||||
if (!dev_open(dev)) {
|
||||
stack;
|
||||
|
||||
@@ -53,7 +53,7 @@ static int _has_partition_table(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned p;
|
||||
uint8_t buf[SECTOR_SIZE];
|
||||
uint16_t buf[SECTOR_SIZE/sizeof(uint16_t)];
|
||||
uint16_t *part_magic;
|
||||
struct partition *part;
|
||||
|
||||
@@ -70,9 +70,9 @@ static int _has_partition_table(struct device *dev)
|
||||
/* FIXME Check for other types of partition table too */
|
||||
|
||||
/* Check for msdos partition table */
|
||||
part_magic = (uint16_t *)(buf + PART_MAGIC_OFFSET);
|
||||
part_magic = buf + PART_MAGIC_OFFSET/sizeof(buf[0]);
|
||||
if ((*part_magic == xlate16(PART_MAGIC))) {
|
||||
part = (struct partition *) (buf + PART_OFFSET);
|
||||
part = (struct partition *) (buf + PART_OFFSET/sizeof(buf[0]));
|
||||
for (p = 0; p < 4; p++, part++) {
|
||||
/* Table is invalid if boot indicator not 0 or 0x80 */
|
||||
if ((part->boot_ind & 0x7f)) {
|
||||
|
||||
@@ -234,7 +234,7 @@ const char *display_size(struct cmd_context *cmd, uint64_t size)
|
||||
|
||||
void pvdisplay_colons(struct physical_volume *pv)
|
||||
{
|
||||
char uuid[64];
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
if (!pv)
|
||||
return;
|
||||
@@ -262,7 +262,7 @@ void pvdisplay_colons(struct physical_volume *pv)
|
||||
void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
void *handle __attribute((unused)))
|
||||
{
|
||||
char uuid[64];
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
const char *size;
|
||||
|
||||
uint32_t pe_free;
|
||||
@@ -324,7 +324,7 @@ int pvdisplay_short(struct cmd_context *cmd __attribute((unused)),
|
||||
struct physical_volume *pv,
|
||||
void *handle __attribute((unused)))
|
||||
{
|
||||
char uuid[64];
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
if (!pv)
|
||||
return 0;
|
||||
@@ -371,7 +371,7 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
{
|
||||
struct lvinfo info;
|
||||
int inkernel, snap_active = 0;
|
||||
char uuid[64];
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
struct lv_segment *snap_seg = NULL;
|
||||
float snap_percent; /* fused, fsize; */
|
||||
|
||||
@@ -537,7 +537,7 @@ void vgdisplay_full(struct volume_group *vg)
|
||||
{
|
||||
uint32_t access;
|
||||
uint32_t active_pvs;
|
||||
char uuid[64];
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
if (vg->status & PARTIAL_VG)
|
||||
active_pvs = list_size(&vg->pvs);
|
||||
@@ -616,7 +616,7 @@ void vgdisplay_colons(struct volume_group *vg)
|
||||
{
|
||||
uint32_t active_pvs;
|
||||
const char *access;
|
||||
char uuid[64];
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
if (vg->status & PARTIAL_VG)
|
||||
active_pvs = list_size(&vg->pvs);
|
||||
|
||||
@@ -239,7 +239,10 @@ int persistent_filter_dump(struct dev_filter *f)
|
||||
/* _write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE); */
|
||||
|
||||
fprintf(fp, "}\n");
|
||||
fclose(fp);
|
||||
if (fclose(fp)) {
|
||||
log_sys_error("fclose", tmp_file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rename(tmp_file, pf->file))
|
||||
log_error("%s: rename to %s failed: %s", tmp_file, pf->file,
|
||||
|
||||
@@ -54,7 +54,9 @@ static int _locate_sysfs_blocks(const char *proc, char *path, size_t len)
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", proc_mounts);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -156,7 +158,9 @@ static int _read_dev(const char *file, dev_t *result)
|
||||
}
|
||||
|
||||
r = _parse_dev(file, fp, result);
|
||||
fclose(fp);
|
||||
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", file);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "lvm-string.h"
|
||||
#include "config.h"
|
||||
#include "metadata.h"
|
||||
#include "activate.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
@@ -37,6 +38,7 @@ typedef struct {
|
||||
} device_info_t;
|
||||
|
||||
static int _md_major = -1;
|
||||
static int _device_mapper_major = -1;
|
||||
|
||||
int md_major(void)
|
||||
{
|
||||
@@ -90,6 +92,13 @@ static int _passes_lvm_type_device_filter(struct dev_filter *f,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Skip suspended devices */
|
||||
if (MAJOR(dev->dev) == _device_mapper_major &&
|
||||
ignore_suspended_devices() && !device_is_usable(dev->dev)) {
|
||||
log_debug("%s: Skipping: Suspended dm device", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check it's accessible */
|
||||
if (!dev_open_flags(dev, O_RDONLY, 0, 1)) {
|
||||
log_debug("%s: Skipping: open failed", name);
|
||||
@@ -182,10 +191,14 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
|
||||
if (!strncmp("md", line + i, 2) && isspace(*(line + i + 2)))
|
||||
_md_major = line_maj;
|
||||
|
||||
/* Look for device-mapper device */
|
||||
/* FIXME Cope with multiple majors */
|
||||
if (!strncmp("device-mapper", line + i, 13) && isspace(*(line + i + 13)))
|
||||
_device_mapper_major = line_maj;
|
||||
|
||||
/* Go through the valid device names and if there is a
|
||||
match store max number of partitions */
|
||||
for (j = 0; device_info[j].name != NULL; j++) {
|
||||
|
||||
dev_len = strlen(device_info[j].name);
|
||||
if (dev_len <= strlen(line + i) &&
|
||||
!strncmp(device_info[j].name, line + i, dev_len) &&
|
||||
@@ -204,7 +217,8 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
|
||||
if (cv->type != CFG_STRING) {
|
||||
log_error("Expecting string in devices/types "
|
||||
"in config file");
|
||||
fclose(pd);
|
||||
if (fclose(pd))
|
||||
log_sys_error("fclose", proc_devices);
|
||||
return 0;
|
||||
}
|
||||
dev_len = strlen(cv->v.str);
|
||||
@@ -214,14 +228,16 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
|
||||
log_error("Max partition count missing for %s "
|
||||
"in devices/types in config file",
|
||||
name);
|
||||
fclose(pd);
|
||||
if (fclose(pd))
|
||||
log_sys_error("fclose", proc_devices);
|
||||
return 0;
|
||||
}
|
||||
if (!cv->v.i) {
|
||||
log_error("Zero partition count invalid for "
|
||||
"%s in devices/types in config file",
|
||||
name);
|
||||
fclose(pd);
|
||||
if (fclose(pd))
|
||||
log_sys_error("fclose", proc_devices);
|
||||
return 0;
|
||||
}
|
||||
if (dev_len <= strlen(line + i) &&
|
||||
@@ -232,7 +248,10 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(pd);
|
||||
|
||||
if (fclose(pd))
|
||||
log_sys_error("fclose", proc_devices);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@ static int _read_uuids(struct disk_list *data)
|
||||
{
|
||||
unsigned num_read = 0;
|
||||
struct uuid_list *ul;
|
||||
char buffer[NAME_LEN];
|
||||
char buffer[NAME_LEN] __attribute((aligned(8)));
|
||||
uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
|
||||
uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ struct pe_disk {
|
||||
|
||||
struct uuid_list {
|
||||
struct list list;
|
||||
char uuid[NAME_LEN];
|
||||
char uuid[NAME_LEN] __attribute((aligned(8)));
|
||||
};
|
||||
|
||||
struct lvd_list {
|
||||
@@ -161,11 +161,11 @@ struct disk_list {
|
||||
struct dm_pool *mem;
|
||||
struct device *dev;
|
||||
|
||||
struct pv_disk pvd;
|
||||
struct vg_disk vgd;
|
||||
struct list uuids;
|
||||
struct list lvds;
|
||||
struct pe_disk *extents;
|
||||
struct pv_disk pvd __attribute((aligned(8)));
|
||||
struct vg_disk vgd __attribute((aligned(8)));
|
||||
struct list uuids __attribute((aligned(8)));
|
||||
struct list lvds __attribute((aligned(8)));
|
||||
struct pe_disk *extents __attribute((aligned(8)));
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -30,7 +30,7 @@ static void _not_supported(const char *op)
|
||||
op);
|
||||
}
|
||||
|
||||
static int _lvm1_can_handle(struct labeller *l, char *buf, uint64_t sector)
|
||||
static int _lvm1_can_handle(struct labeller *l, void *buf, uint64_t sector)
|
||||
{
|
||||
struct pv_disk *pvd = (struct pv_disk *) buf;
|
||||
uint32_t version;
|
||||
@@ -48,13 +48,13 @@ static int _lvm1_can_handle(struct labeller *l, char *buf, uint64_t sector)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _lvm1_write(struct label *label, char *buf)
|
||||
static int _lvm1_write(struct label *label, void *buf)
|
||||
{
|
||||
_not_supported("write");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _lvm1_read(struct labeller *l, struct device *dev, char *buf,
|
||||
static int _lvm1_read(struct labeller *l, struct device *dev, void *buf,
|
||||
struct label **label)
|
||||
{
|
||||
struct pv_disk *pvd = (struct pv_disk *) buf;
|
||||
|
||||
@@ -36,7 +36,7 @@ static int __read_pool_disk(const struct format_type *fmt, struct device *dev,
|
||||
struct dm_pool *mem, struct pool_list *pl,
|
||||
const char *vg_name)
|
||||
{
|
||||
char buf[512];
|
||||
char buf[512] __attribute((aligned(8)));
|
||||
|
||||
/* FIXME: Need to check the cache here first */
|
||||
if (!dev_read(dev, UINT64_C(0), 512, buf)) {
|
||||
@@ -59,7 +59,7 @@ static void _add_pl_to_list(struct list *head, struct pool_list *data)
|
||||
|
||||
list_iterate_items(pl, head) {
|
||||
if (id_equal(&data->pv_uuid, &pl->pv_uuid)) {
|
||||
char uuid[ID_LEN + 7];
|
||||
char uuid[ID_LEN + 7] __attribute((aligned(8)));
|
||||
|
||||
id_write_format(&pl->pv_uuid, uuid, ID_LEN + 7);
|
||||
|
||||
@@ -84,7 +84,7 @@ int read_pool_label(struct pool_list *pl, struct labeller *l,
|
||||
struct lvmcache_info *info;
|
||||
struct id pvid;
|
||||
struct id vgid;
|
||||
char uuid[ID_LEN + 7];
|
||||
char uuid[ID_LEN + 7] __attribute((aligned(8)));
|
||||
struct pool_disk *pd = &pl->pd;
|
||||
|
||||
pool_label_in(pd, buf);
|
||||
@@ -128,7 +128,7 @@ int read_pool_label(struct pool_list *pl, struct labeller *l,
|
||||
* be able to interpret ondisk labels correctly. Always use
|
||||
* this function before writing to disk.
|
||||
*/
|
||||
void pool_label_out(struct pool_disk *pl, char *buf)
|
||||
void pool_label_out(struct pool_disk *pl, void *buf)
|
||||
{
|
||||
struct pool_disk *bufpl = (struct pool_disk *) buf;
|
||||
|
||||
@@ -163,7 +163,7 @@ void pool_label_out(struct pool_disk *pl, char *buf)
|
||||
* correctly. Always use this function before using labels that
|
||||
* were read from disk.
|
||||
*/
|
||||
void pool_label_in(struct pool_disk *pl, char *buf)
|
||||
void pool_label_in(struct pool_disk *pl, void *buf)
|
||||
{
|
||||
struct pool_disk *bufpl = (struct pool_disk *) buf;
|
||||
|
||||
|
||||
@@ -134,8 +134,8 @@ struct user_device {
|
||||
|
||||
int read_pool_label(struct pool_list *pl, struct labeller *l,
|
||||
struct device *dev, char *buf, struct label **label);
|
||||
void pool_label_out(struct pool_disk *pl, char *buf);
|
||||
void pool_label_in(struct pool_disk *pl, char *buf);
|
||||
void pool_label_out(struct pool_disk *pl, void *buf);
|
||||
void pool_label_in(struct pool_disk *pl, void *buf);
|
||||
void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid);
|
||||
int import_pool_vg(struct volume_group *vg, struct dm_pool *mem, struct list *pls);
|
||||
int import_pool_lvs(struct volume_group *vg, struct dm_pool *mem,
|
||||
|
||||
@@ -29,7 +29,7 @@ static void _pool_not_supported(const char *op)
|
||||
op);
|
||||
}
|
||||
|
||||
static int _pool_can_handle(struct labeller *l, char *buf, uint64_t sector)
|
||||
static int _pool_can_handle(struct labeller *l, void *buf, uint64_t sector)
|
||||
{
|
||||
|
||||
struct pool_disk pd;
|
||||
@@ -50,13 +50,13 @@ static int _pool_can_handle(struct labeller *l, char *buf, uint64_t sector)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _pool_write(struct label *label, char *buf)
|
||||
static int _pool_write(struct label *label, void *buf)
|
||||
{
|
||||
_pool_not_supported("write");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _pool_read(struct labeller *l, struct device *dev, char *buf,
|
||||
static int _pool_read(struct labeller *l, struct device *dev, void *buf,
|
||||
struct label **label)
|
||||
{
|
||||
struct pool_list pl;
|
||||
|
||||
@@ -249,17 +249,23 @@ int archive_vg(struct volume_group *vg,
|
||||
|
||||
if (!(fp = fdopen(fd, "w"))) {
|
||||
log_err("Couldn't create FILE object for archive.");
|
||||
close(fd);
|
||||
if (close(fd))
|
||||
log_sys_error("close", temp_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!text_vg_export_file(vg, desc, fp)) {
|
||||
stack;
|
||||
fclose(fp);
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", temp_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
if (fclose(fp)) {
|
||||
log_sys_error("fclose", temp_file);
|
||||
/* Leave file behind as evidence of failure */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we want to rename this file to <vg>_index.vg.
|
||||
|
||||
@@ -132,37 +132,40 @@ static struct mda_header *_raw_read_mda_header(const struct format_type *fmt,
|
||||
|
||||
if (!dev_read(dev_area->dev, dev_area->start, MDA_HEADER_SIZE, mdah)) {
|
||||
stack;
|
||||
dm_pool_free(fmt->cmd->mem, mdah);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (mdah->checksum_xl != xlate32(calc_crc(INITIAL_CRC, mdah->magic,
|
||||
MDA_HEADER_SIZE -
|
||||
sizeof(mdah->checksum_xl)))) {
|
||||
log_error("Incorrect metadata area header checksum");
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
_xlate_mdah(mdah);
|
||||
|
||||
if (strncmp((char *)mdah->magic, FMTT_MAGIC, sizeof(mdah->magic))) {
|
||||
log_error("Wrong magic number in metadata area header");
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (mdah->version != FMTT_VERSION) {
|
||||
log_error("Incompatible metadata area header version: %d",
|
||||
mdah->version);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (mdah->start != dev_area->start) {
|
||||
log_error("Incorrect start sector in metadata area header: %"
|
||||
PRIu64, mdah->start);
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
return mdah;
|
||||
|
||||
error:
|
||||
dm_pool_free(fmt->cmd->mem, mdah);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _raw_write_mda_header(const struct format_type *fmt,
|
||||
@@ -193,7 +196,7 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
|
||||
int *precommitted)
|
||||
{
|
||||
size_t len;
|
||||
char vgnamebuf[NAME_LEN + 2];
|
||||
char vgnamebuf[NAME_LEN + 2] __attribute((aligned(8)));
|
||||
struct raw_locn *rlocn, *rlocn_precommitted;
|
||||
struct lvmcache_info *info;
|
||||
|
||||
@@ -707,7 +710,8 @@ static int _vg_write_file(struct format_instance *fid, struct volume_group *vg,
|
||||
|
||||
if (!(fp = fdopen(fd, "w"))) {
|
||||
log_sys_error("fdopen", temp_file);
|
||||
close(fd);
|
||||
if (close(fd))
|
||||
log_sys_error("fclose", temp_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -715,13 +719,15 @@ static int _vg_write_file(struct format_instance *fid, struct volume_group *vg,
|
||||
|
||||
if (!text_vg_export_file(vg, tc->desc, fp)) {
|
||||
log_error("Failed to write metadata to %s.", temp_file);
|
||||
fclose(fp);
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", temp_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fsync(fd) && (errno != EROFS) && (errno != EINVAL)) {
|
||||
log_sys_error("fsync", tc->path_edit);
|
||||
fclose(fp);
|
||||
if (fclose(fp))
|
||||
log_sys_error("fclose", tc->path_edit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -885,8 +891,8 @@ const char *vgname_from_mda(const struct format_type *fmt,
|
||||
uint32_t wrap = 0;
|
||||
const char *vgname = NULL;
|
||||
unsigned int len = 0;
|
||||
char buf[NAME_LEN + 1];
|
||||
char uuid[64];
|
||||
char buf[NAME_LEN + 1] __attribute((aligned(8)));
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
if (!dev_open(dev_area->dev)) {
|
||||
stack;
|
||||
@@ -1131,7 +1137,7 @@ static int _text_pv_write(const struct format_type *fmt, struct physical_volume
|
||||
struct lvmcache_info *info;
|
||||
struct mda_context *mdac;
|
||||
struct metadata_area *mda;
|
||||
char buf[MDA_HEADER_SIZE];
|
||||
char buf[MDA_HEADER_SIZE] __attribute((aligned(8)));
|
||||
struct mda_header *mdah = (struct mda_header *) buf;
|
||||
uint64_t adjustment;
|
||||
|
||||
@@ -1742,7 +1748,7 @@ static int _get_config_disk_area(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
if (!(dev_area.dev = device_from_pvid(cmd, &id))) {
|
||||
char buffer[64];
|
||||
char buffer[64] __attribute((aligned(8)));
|
||||
|
||||
if (!id_write_format(&id, buffer, sizeof(buffer)))
|
||||
log_err("Couldn't find device.");
|
||||
|
||||
@@ -149,7 +149,7 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
|
||||
* Convert the uuid into a device.
|
||||
*/
|
||||
if (!(pv->dev = device_from_pvid(fid->fmt->cmd, &pv->id))) {
|
||||
char buffer[64];
|
||||
char buffer[64] __attribute((aligned(8)));
|
||||
|
||||
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
|
||||
log_error("Couldn't find device.");
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <fcntl.h>
|
||||
|
||||
static int _text_can_handle(struct labeller *l __attribute((unused)),
|
||||
char *buf,
|
||||
void *buf,
|
||||
uint64_t sector __attribute((unused)))
|
||||
{
|
||||
struct label_header *lh = (struct label_header *) buf;
|
||||
@@ -35,7 +35,7 @@ static int _text_can_handle(struct labeller *l __attribute((unused)),
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _text_write(struct label *label, char *buf)
|
||||
static int _text_write(struct label *label, void *buf)
|
||||
{
|
||||
struct label_header *lh = (struct label_header *) buf;
|
||||
struct pv_header *pvhdr;
|
||||
@@ -189,7 +189,7 @@ static int _text_initialise_label(struct labeller *l __attribute((unused)),
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _text_read(struct labeller *l, struct device *dev, char *buf,
|
||||
static int _text_read(struct labeller *l, struct device *dev, void *buf,
|
||||
struct label **label)
|
||||
{
|
||||
struct label_header *lh = (struct label_header *) buf;
|
||||
|
||||
@@ -115,7 +115,7 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
struct lvmcache_info *info;
|
||||
uint64_t sector;
|
||||
int found = 0;
|
||||
char readbuf[LABEL_SCAN_SIZE];
|
||||
char readbuf[LABEL_SCAN_SIZE] __attribute((aligned(8)));
|
||||
|
||||
if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) {
|
||||
log_debug("%s: Failed to read label area", dev_name(dev));
|
||||
@@ -186,8 +186,8 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
/* FIXME Also wipe associated metadata area headers? */
|
||||
int label_remove(struct device *dev)
|
||||
{
|
||||
char buf[LABEL_SIZE];
|
||||
char readbuf[LABEL_SCAN_SIZE];
|
||||
char buf[LABEL_SIZE] __attribute((aligned(8)));
|
||||
char readbuf[LABEL_SCAN_SIZE] __attribute((aligned(8)));
|
||||
int r = 1;
|
||||
uint64_t sector;
|
||||
int wipe;
|
||||
@@ -258,7 +258,7 @@ int label_remove(struct device *dev)
|
||||
/* FIXME Avoid repeated re-reading if cache lock held */
|
||||
int label_read(struct device *dev, struct label **result)
|
||||
{
|
||||
char buf[LABEL_SIZE];
|
||||
char buf[LABEL_SIZE] __attribute((aligned(8)));
|
||||
struct labeller *l;
|
||||
uint64_t sector;
|
||||
struct lvmcache_info *info;
|
||||
@@ -290,7 +290,7 @@ int label_read(struct device *dev, struct label **result)
|
||||
/* Caller may need to use label_get_handler to create label struct! */
|
||||
int label_write(struct device *dev, struct label *label)
|
||||
{
|
||||
char buf[LABEL_SIZE];
|
||||
char buf[LABEL_SIZE] __attribute((aligned(8)));
|
||||
struct label_header *lh = (struct label_header *) buf;
|
||||
int r = 1;
|
||||
|
||||
@@ -341,7 +341,7 @@ int label_write(struct device *dev, struct label *label)
|
||||
int label_verify(struct device *dev)
|
||||
{
|
||||
struct labeller *l;
|
||||
char buf[LABEL_SIZE];
|
||||
char buf[LABEL_SIZE] __attribute((aligned(8)));
|
||||
uint64_t sector;
|
||||
struct lvmcache_info *info;
|
||||
int r = 0;
|
||||
|
||||
@@ -49,23 +49,23 @@ struct label_ops {
|
||||
/*
|
||||
* Is the device labelled with this format ?
|
||||
*/
|
||||
int (*can_handle) (struct labeller * l, char *buf, uint64_t sector);
|
||||
int (*can_handle) (struct labeller * l, void *buf, uint64_t sector);
|
||||
|
||||
/*
|
||||
* Write a label to a volume.
|
||||
*/
|
||||
int (*write) (struct label * label, char *buf);
|
||||
int (*write) (struct label * label, void *buf);
|
||||
|
||||
/*
|
||||
* Read a label from a volume.
|
||||
*/
|
||||
int (*read) (struct labeller * l, struct device * dev,
|
||||
char *buf, struct label ** label);
|
||||
void *buf, struct label ** label);
|
||||
|
||||
/*
|
||||
* Additional consistency checks for the paranoid.
|
||||
*/
|
||||
int (*verify) (struct labeller * l, char *buf, uint64_t sector);
|
||||
int (*verify) (struct labeller * l, void *buf, uint64_t sector);
|
||||
|
||||
/*
|
||||
* Populate label_type etc.
|
||||
|
||||
@@ -94,7 +94,7 @@ static int _open_local_sock(void)
|
||||
/* Send a request and return the status */
|
||||
static int _send_request(char *inbuf, int inlen, char **retbuf)
|
||||
{
|
||||
char outbuf[PIPE_BUF];
|
||||
char outbuf[PIPE_BUF] __attribute((aligned(8)));
|
||||
struct clvm_header *outheader = (struct clvm_header *) outbuf;
|
||||
int len;
|
||||
int off;
|
||||
@@ -195,8 +195,7 @@ static void _build_header(struct clvm_header *head, int cmd, const char *node,
|
||||
static int _cluster_request(char cmd, const char *node, void *data, int len,
|
||||
lvm_response_t ** response, int *num)
|
||||
{
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
|
||||
int *outptr;
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1] __attribute((aligned(8)));
|
||||
char *inptr;
|
||||
char *retbuf = NULL;
|
||||
int status;
|
||||
@@ -236,17 +235,13 @@ static int _cluster_request(char cmd, const char *node, void *data, int len,
|
||||
* With an extra pair of INTs on the front to sanity
|
||||
* check the pointer when we are given it back to free
|
||||
*/
|
||||
outptr = dm_malloc(sizeof(lvm_response_t) * num_responses +
|
||||
sizeof(int) * 2);
|
||||
if (!outptr) {
|
||||
*response = dm_malloc(sizeof(lvm_response_t) * num_responses);
|
||||
if (!*response) {
|
||||
errno = ENOMEM;
|
||||
status = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*response = (lvm_response_t *) (outptr + 2);
|
||||
outptr[0] = LVM_SIGNATURE;
|
||||
outptr[1] = num_responses;
|
||||
rarray = *response;
|
||||
|
||||
/* Unpack the response into an lvm_response_t array */
|
||||
@@ -265,7 +260,7 @@ static int _cluster_request(char cmd, const char *node, void *data, int len,
|
||||
int j;
|
||||
for (j = 0; j < i; j++)
|
||||
dm_free(rarray[i].response);
|
||||
free(outptr);
|
||||
free(*response);
|
||||
errno = ENOMEM;
|
||||
status = -1;
|
||||
goto out;
|
||||
@@ -287,25 +282,15 @@ static int _cluster_request(char cmd, const char *node, void *data, int len,
|
||||
}
|
||||
|
||||
/* Free reply array */
|
||||
static int _cluster_free_request(lvm_response_t * response)
|
||||
static int _cluster_free_request(lvm_response_t * response, int num)
|
||||
{
|
||||
int *ptr = (int *) response - 2;
|
||||
int i;
|
||||
int num;
|
||||
|
||||
/* Check it's ours to free */
|
||||
if (response == NULL || *ptr != LVM_SIGNATURE) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
num = ptr[1];
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
dm_free(response[i].response);
|
||||
}
|
||||
|
||||
dm_free(ptr);
|
||||
dm_free(response);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -336,8 +321,8 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
|
||||
if (mirror_in_sync())
|
||||
args[1] |= LCK_MIRROR_NOSYNC_MODE;
|
||||
|
||||
if (dmeventd_register_mode())
|
||||
args[1] |= LCK_DMEVENTD_REGISTER_MODE;
|
||||
if (dmeventd_monitor_mode())
|
||||
args[1] |= LCK_DMEVENTD_MONITOR_MODE;
|
||||
|
||||
/*
|
||||
* VG locks are just that: locks, and have no side effects
|
||||
@@ -374,7 +359,7 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
_cluster_free_request(response);
|
||||
_cluster_free_request(response, num_responses);
|
||||
errno = saved_errno;
|
||||
|
||||
return status;
|
||||
|
||||
@@ -163,8 +163,8 @@ static int _lock_file(const char *file, int flags)
|
||||
log_very_verbose("Locking %s %c%c", ll->res, state,
|
||||
flags & LCK_NONBLOCK ? ' ' : 'B');
|
||||
do {
|
||||
if (ll->lf > -1)
|
||||
close(ll->lf);
|
||||
if ((ll->lf > -1) && close(ll->lf))
|
||||
log_sys_error("close", file);
|
||||
|
||||
if ((ll->lf = open(file, O_CREAT | O_APPEND | O_RDWR, 0777))
|
||||
< 0) {
|
||||
|
||||
@@ -249,7 +249,7 @@ static int _lock_vol(struct cmd_context *cmd, const char *resource, int flags)
|
||||
|
||||
int lock_vol(struct cmd_context *cmd, const char *vol, int flags)
|
||||
{
|
||||
char resource[258];
|
||||
char resource[258] __attribute((aligned(8)));
|
||||
|
||||
switch (flags & LCK_SCOPE_MASK) {
|
||||
case LCK_VG:
|
||||
|
||||
@@ -50,7 +50,7 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
|
||||
#define LCK_NULL 0x00000000 /* LCK$_NLMODE */
|
||||
#define LCK_READ 0x00000001 /* LCK$_CRMODE */
|
||||
/* LCK$_CWMODE */
|
||||
/* LCK$_PRMODE */
|
||||
#define LCK_PREAD 0x00000003 /* LCK$_PRMODE */
|
||||
#define LCK_WRITE 0x00000004 /* LCK$_PWMODE */
|
||||
#define LCK_EXCL 0x00000005 /* LCK$_EXMODE */
|
||||
#define LCK_UNLOCK 0x00000006 /* This is ours */
|
||||
@@ -75,7 +75,7 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
|
||||
*/
|
||||
#define LCK_PARTIAL_MODE 0x00000001 /* Running in partial mode */
|
||||
#define LCK_MIRROR_NOSYNC_MODE 0x00000002 /* Mirrors don't require sync */
|
||||
#define LCK_DMEVENTD_REGISTER_MODE 0x00000004 /* Register with dmeventd */
|
||||
#define LCK_DMEVENTD_MONITOR_MODE 0x00000004 /* Register with dmeventd */
|
||||
|
||||
|
||||
/*
|
||||
|
||||
@@ -48,7 +48,8 @@ static char _cmd_name[30] = "";
|
||||
static char _msg_prefix[30] = " ";
|
||||
static int _already_logging = 0;
|
||||
static int _mirror_in_sync = 0;
|
||||
static int _dmeventd_register = DEFAULT_DMEVENTD_MONITOR;
|
||||
static int _dmeventd_monitor = DEFAULT_DMEVENTD_MONITOR;
|
||||
static int _ignore_suspended_devices = 0;
|
||||
|
||||
static lvm2_log_fn_t _lvm2_log_fn = NULL;
|
||||
|
||||
@@ -120,7 +121,8 @@ void fin_log(void)
|
||||
}
|
||||
|
||||
if (_log_to_file) {
|
||||
fclose(_log_file);
|
||||
if (fclose(_log_file))
|
||||
fprintf(stderr, "fclose() on log file failed: %s", strerror(errno));
|
||||
_log_to_file = 0;
|
||||
}
|
||||
}
|
||||
@@ -189,9 +191,14 @@ void init_mirror_in_sync(int in_sync)
|
||||
_mirror_in_sync = in_sync;
|
||||
}
|
||||
|
||||
void init_dmeventd_register(int reg)
|
||||
void init_dmeventd_monitor(int reg)
|
||||
{
|
||||
_dmeventd_register = reg;
|
||||
_dmeventd_monitor = reg;
|
||||
}
|
||||
|
||||
void init_ignore_suspended_devices(int ignore)
|
||||
{
|
||||
_ignore_suspended_devices = ignore;
|
||||
}
|
||||
|
||||
void init_cmd_name(int status)
|
||||
@@ -268,9 +275,14 @@ int mirror_in_sync(void)
|
||||
return _mirror_in_sync;
|
||||
}
|
||||
|
||||
int dmeventd_register_mode(void)
|
||||
int dmeventd_monitor_mode(void)
|
||||
{
|
||||
return _dmeventd_register;
|
||||
return _dmeventd_monitor;
|
||||
}
|
||||
|
||||
int ignore_suspended_devices(void)
|
||||
{
|
||||
return _ignore_suspended_devices;
|
||||
}
|
||||
|
||||
void init_debug(int level)
|
||||
|
||||
@@ -75,7 +75,8 @@ void init_ignorelockingfailure(int level);
|
||||
void init_lockingfailed(int level);
|
||||
void init_security_level(int level);
|
||||
void init_mirror_in_sync(int in_sync);
|
||||
void init_dmeventd_register(int reg);
|
||||
void init_dmeventd_monitor(int reg);
|
||||
void init_ignore_suspended_devices(int ignore);
|
||||
|
||||
void set_cmd_name(const char *cmd_name);
|
||||
|
||||
@@ -90,7 +91,10 @@ int ignorelockingfailure(void);
|
||||
int lockingfailed(void);
|
||||
int security_level(void);
|
||||
int mirror_in_sync(void);
|
||||
int dmeventd_register_mode(void);
|
||||
int ignore_suspended_devices(void);
|
||||
|
||||
#define DMEVENTD_MONITOR_IGNORE -1
|
||||
int dmeventd_monitor_mode(void);
|
||||
|
||||
/* Suppress messages to stdout/stderr (1) or everywhere (2) */
|
||||
/* Returns previous setting */
|
||||
|
||||
@@ -415,6 +415,15 @@ struct alloc_handle {
|
||||
struct list alloced_areas[0]; /* Lists of areas in each stripe */
|
||||
};
|
||||
|
||||
static uint32_t calc_area_multiple(const struct segment_type *segtype,
|
||||
const uint32_t area_count)
|
||||
{
|
||||
if (!segtype_is_striped(segtype) || !area_count)
|
||||
return 1;
|
||||
|
||||
return area_count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Preparation for a specific allocation attempt
|
||||
*/
|
||||
@@ -476,7 +485,7 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
|
||||
ah->area_count = area_count;
|
||||
ah->log_count = log_count;
|
||||
ah->alloc = alloc;
|
||||
ah->area_multiple = segtype_is_striped(segtype) ? ah->area_count : 1;
|
||||
ah->area_multiple = calc_area_multiple(segtype, area_count);
|
||||
|
||||
for (s = 0; s < ah->area_count; s++)
|
||||
list_init(&ah->alloced_areas[s]);
|
||||
@@ -553,7 +562,7 @@ static int _setup_alloced_segment(struct logical_volume *lv, uint32_t status,
|
||||
if (mirrored_pv)
|
||||
extra_areas = 1;
|
||||
|
||||
area_multiple = segtype_is_striped(segtype) ? area_count : 1;
|
||||
area_multiple = calc_area_multiple(segtype, area_count);
|
||||
|
||||
/* log_lv gets set up elsehere */
|
||||
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv,
|
||||
@@ -628,17 +637,17 @@ static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t needed,
|
||||
struct pv_area **areas,
|
||||
uint32_t *ix, struct pv_area *log_area)
|
||||
{
|
||||
uint32_t area_len, smallest, remaining;
|
||||
uint32_t area_len, remaining;
|
||||
uint32_t s;
|
||||
struct alloced_area *aa;
|
||||
|
||||
remaining = needed - *ix;
|
||||
area_len = remaining / ah->area_multiple;
|
||||
|
||||
smallest = areas[ah->area_count - 1]->count;
|
||||
|
||||
if (area_len > smallest)
|
||||
area_len = smallest;
|
||||
/* Reduce area_len to the smallest of the areas */
|
||||
for (s = 0; s < ah->area_count; s++)
|
||||
if (area_len > areas[s]->count)
|
||||
area_len = areas[s]->count;
|
||||
|
||||
if (!(aa = dm_pool_alloc(ah->mem, sizeof(*aa) *
|
||||
(ah->area_count + (log_area ? 1 : 0))))) {
|
||||
@@ -707,7 +716,7 @@ static int _for_each_pv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
if (max_seg_len && *max_seg_len > remaining_seg_len)
|
||||
*max_seg_len = remaining_seg_len;
|
||||
|
||||
area_multiple = segtype_is_striped(seg->segtype) ? seg->area_count : 1;
|
||||
area_multiple = calc_area_multiple(seg->segtype, seg->area_count);
|
||||
area_len = remaining_seg_len / area_multiple ? : 1;
|
||||
|
||||
for (s = first_area;
|
||||
@@ -1066,6 +1075,7 @@ static int _allocate(struct alloc_handle *ah,
|
||||
int r = 0;
|
||||
struct list *pvms;
|
||||
uint32_t areas_size;
|
||||
alloc_policy_t alloc;
|
||||
|
||||
if (allocated >= new_extents && !ah->log_count) {
|
||||
log_error("_allocate called with no work to do!");
|
||||
@@ -1111,50 +1121,18 @@ static int _allocate(struct alloc_handle *ah,
|
||||
return 0;
|
||||
}
|
||||
|
||||
old_allocated = allocated;
|
||||
if (!_find_parallel_space(ah, ALLOC_CONTIGUOUS, pvms, areas,
|
||||
areas_size, can_split,
|
||||
prev_lvseg, &allocated, new_extents)) {
|
||||
stack;
|
||||
goto out;
|
||||
/* Attempt each defined allocation policy in turn */
|
||||
for (alloc = ALLOC_CONTIGUOUS; alloc < ALLOC_INHERIT; alloc++) {
|
||||
old_allocated = allocated;
|
||||
if (!_find_parallel_space(ah, alloc, pvms, areas,
|
||||
areas_size, can_split,
|
||||
prev_lvseg, &allocated, new_extents))
|
||||
goto_out;
|
||||
if ((allocated == new_extents) || (ah->alloc == alloc) ||
|
||||
(!can_split && (allocated != old_allocated)))
|
||||
break;
|
||||
}
|
||||
|
||||
if ((allocated == new_extents) || (ah->alloc == ALLOC_CONTIGUOUS) ||
|
||||
(!can_split && (allocated != old_allocated)))
|
||||
goto finished;
|
||||
|
||||
old_allocated = allocated;
|
||||
if (!_find_parallel_space(ah, ALLOC_CLING, pvms, areas,
|
||||
areas_size, can_split,
|
||||
prev_lvseg, &allocated, new_extents)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((allocated == new_extents) || (ah->alloc == ALLOC_CLING) ||
|
||||
(!can_split && (allocated != old_allocated)))
|
||||
goto finished;
|
||||
|
||||
old_allocated = allocated;
|
||||
if (!_find_parallel_space(ah, ALLOC_NORMAL, pvms, areas,
|
||||
areas_size, can_split,
|
||||
prev_lvseg, &allocated, new_extents)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((allocated == new_extents) || (ah->alloc == ALLOC_NORMAL) ||
|
||||
(!can_split && (allocated != old_allocated)))
|
||||
goto finished;
|
||||
|
||||
if (!_find_parallel_space(ah, ALLOC_ANYWHERE, pvms, areas,
|
||||
areas_size, can_split,
|
||||
prev_lvseg, &allocated, new_extents)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
finished:
|
||||
if (allocated != new_extents) {
|
||||
log_error("Insufficient suitable %sallocatable extents "
|
||||
"for logical volume %s: %u more required",
|
||||
@@ -1165,6 +1143,13 @@ static int _allocate(struct alloc_handle *ah,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ah->log_count && !ah->log_area.len) {
|
||||
log_error("Insufficient extents for log allocation "
|
||||
"for logical volume %s.",
|
||||
lv ? lv->name : "");
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
@@ -1508,7 +1493,7 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
|
||||
struct cmd_context *cmd = vg->cmd;
|
||||
struct lv_list *ll = NULL;
|
||||
struct logical_volume *lv;
|
||||
char dname[32];
|
||||
char dname[NAME_LEN];
|
||||
|
||||
if (vg->max_lv && (vg->max_lv == vg->lv_count)) {
|
||||
log_error("Maximum number of logical volumes (%u) reached "
|
||||
|
||||
@@ -738,7 +738,7 @@ int vg_validate(struct volume_group *vg)
|
||||
{
|
||||
struct pv_list *pvl, *pvl2;
|
||||
struct lv_list *lvl, *lvl2;
|
||||
char uuid[64];
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
int r = 1;
|
||||
|
||||
/* FIXME Also check there's no data/metadata overlap */
|
||||
|
||||
@@ -78,17 +78,18 @@
|
||||
#define FMT_RESIZE_PV 0x00000080U /* Supports pvresize? */
|
||||
#define FMT_UNLIMITED_STRIPESIZE 0x00000100U /* Unlimited stripe size? */
|
||||
|
||||
/* Ordered list - see lv_manip.c */
|
||||
typedef enum {
|
||||
ALLOC_INVALID = 0,
|
||||
ALLOC_INHERIT,
|
||||
ALLOC_INVALID,
|
||||
ALLOC_CONTIGUOUS,
|
||||
ALLOC_CLING,
|
||||
ALLOC_NORMAL,
|
||||
ALLOC_ANYWHERE
|
||||
ALLOC_ANYWHERE,
|
||||
ALLOC_INHERIT
|
||||
} alloc_policy_t;
|
||||
|
||||
typedef enum {
|
||||
AREA_UNASSIGNED = 0,
|
||||
AREA_UNASSIGNED,
|
||||
AREA_PV,
|
||||
AREA_LV
|
||||
} area_type_t;
|
||||
|
||||
@@ -84,6 +84,7 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
|
||||
struct list *removable_pvs, int remove_log)
|
||||
{
|
||||
uint32_t m;
|
||||
uint32_t extents;
|
||||
uint32_t s, s1;
|
||||
struct logical_volume *sub_lv;
|
||||
struct logical_volume *log_lv = NULL;
|
||||
@@ -95,6 +96,7 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
|
||||
struct pv_list *pvl;
|
||||
uint32_t old_area_count = mirrored_seg->area_count;
|
||||
uint32_t new_area_count = mirrored_seg->area_count;
|
||||
struct segment_type *segtype;
|
||||
|
||||
log_very_verbose("Reducing mirror set from %" PRIu32 " to %"
|
||||
PRIu32 " image(s)%s.",
|
||||
@@ -156,9 +158,14 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
|
||||
/* If no more mirrors, remove mirror layer */
|
||||
if (num_mirrors == 1) {
|
||||
lv1 = seg_lv(mirrored_seg, 0);
|
||||
extents = lv1->le_count;
|
||||
_move_lv_segments(mirrored_seg->lv, lv1);
|
||||
mirrored_seg->lv->status &= ~MIRRORED;
|
||||
remove_log = 1;
|
||||
/* Replace mirror with error segment */
|
||||
segtype = get_segtype_from_string(mirrored_seg->lv->vg->cmd, "error");
|
||||
if (!lv_add_virtual_segment(lv1, 0, extents, segtype))
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (remove_log && mirrored_seg->log_lv) {
|
||||
@@ -174,8 +181,6 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
|
||||
* then deactivate and remove them fully.
|
||||
*/
|
||||
|
||||
/* FIXME lv1 has no segments here so shouldn't be written to disk! */
|
||||
|
||||
if (!vg_write(mirrored_seg->lv->vg)) {
|
||||
log_error("intermediate VG write failed.");
|
||||
return 0;
|
||||
|
||||
@@ -32,6 +32,7 @@ struct dev_manager;
|
||||
#define SEG_FORMAT1_SUPPORT 0x00000010U
|
||||
#define SEG_VIRTUAL 0x00000020U
|
||||
#define SEG_CANNOT_BE_ZEROED 0x00000040U
|
||||
#define SEG_MONITORED 0x00000080U
|
||||
|
||||
#define seg_is_mirrored(seg) ((seg)->segtype->flags & SEG_AREAS_MIRRORED ? 1 : 0)
|
||||
#define seg_is_striped(seg) ((seg)->segtype->flags & SEG_AREAS_STRIPED ? 1 : 0)
|
||||
@@ -39,6 +40,7 @@ struct dev_manager;
|
||||
#define seg_is_virtual(seg) ((seg)->segtype->flags & SEG_VIRTUAL ? 1 : 0)
|
||||
#define seg_can_split(seg) ((seg)->segtype->flags & SEG_CAN_SPLIT ? 1 : 0)
|
||||
#define seg_cannot_be_zeroed(seg) ((seg)->segtype->flags & SEG_CANNOT_BE_ZEROED ? 1 : 0)
|
||||
#define seg_monitored(seg) ((seg)->segtype->flags & SEG_MONITORED ? 1 : 0)
|
||||
|
||||
#define segtype_is_striped(segtype) ((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0)
|
||||
#define segtype_is_mirrored(segtype) ((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0)
|
||||
@@ -81,8 +83,9 @@ struct segtype_handler {
|
||||
const struct lv_segment *seg,
|
||||
struct list *modules);
|
||||
void (*destroy) (const struct segment_type * segtype);
|
||||
int (*target_register_events) (struct lv_segment *seg, int events);
|
||||
int (*target_unregister_events) (struct lv_segment *seg, int events);
|
||||
int (*target_monitored) (struct lv_segment *seg, int *pending);
|
||||
int (*target_monitor_events) (struct lv_segment *seg, int events);
|
||||
int (*target_unmonitor_events) (struct lv_segment *seg, int events);
|
||||
};
|
||||
|
||||
struct segment_type *get_segtype_from_string(struct cmd_context *cmd,
|
||||
|
||||
@@ -368,13 +368,12 @@ static int _mirrored_target_present(const struct lv_segment *seg __attribute((un
|
||||
}
|
||||
|
||||
#ifdef DMEVENTD
|
||||
static int _setup_registration(struct dm_pool *mem, struct cmd_context *cmd,
|
||||
char **dso)
|
||||
static int _get_mirror_dso_path(struct cmd_context *cmd, char **dso)
|
||||
{
|
||||
char *path;
|
||||
const char *libpath;
|
||||
|
||||
if (!(path = dm_pool_alloc(mem, PATH_MAX))) {
|
||||
if (!(path = dm_pool_alloc(cmd->mem, PATH_MAX))) {
|
||||
log_error("Failed to allocate dmeventd library path.");
|
||||
return 0;
|
||||
}
|
||||
@@ -389,60 +388,105 @@ static int _setup_registration(struct dm_pool *mem, struct cmd_context *cmd,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME This gets run while suspended and performs banned operations. */
|
||||
/* FIXME Merge these two functions */
|
||||
static int _target_register_events(struct lv_segment *seg,
|
||||
int events)
|
||||
static struct dm_event_handler *_create_dm_event_handler(const char *dmname,
|
||||
const char *dso,
|
||||
enum dm_event_mask mask)
|
||||
{
|
||||
struct dm_event_handler *dmevh;
|
||||
|
||||
if (!(dmevh = dm_event_handler_create()))
|
||||
return_0;
|
||||
|
||||
if (dm_event_handler_set_dso(dmevh, dso))
|
||||
goto fail;
|
||||
|
||||
if (dm_event_handler_set_dev_name(dmevh, dmname))
|
||||
goto fail;
|
||||
|
||||
dm_event_handler_set_event_mask(dmevh, mask);
|
||||
return dmevh;
|
||||
|
||||
fail:
|
||||
dm_event_handler_destroy(dmevh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _target_monitored(struct lv_segment *seg, int *pending)
|
||||
{
|
||||
char *dso, *name;
|
||||
struct logical_volume *lv;
|
||||
struct volume_group *vg;
|
||||
enum dm_event_mask evmask = 0;
|
||||
struct dm_event_handler *dmevh;
|
||||
|
||||
lv = seg->lv;
|
||||
vg = lv->vg;
|
||||
|
||||
if (!_setup_registration(vg->cmd->mem, vg->cmd, &dso)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
*pending = 0;
|
||||
if (!_get_mirror_dso_path(vg->cmd, &dso))
|
||||
return_0;
|
||||
|
||||
if (!(name = build_dm_name(vg->cmd->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))
|
||||
if (!(dmevh = _create_dm_event_handler(name, dso, DM_EVENT_ALL_ERRORS)))
|
||||
return_0;
|
||||
|
||||
log_info("Registered %s for events", name);
|
||||
if (dm_event_get_registered_device(dmevh, 0)) {
|
||||
dm_event_handler_destroy(dmevh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
evmask = dm_event_handler_get_event_mask(dmevh);
|
||||
if (evmask & DM_EVENT_REGISTRATION_PENDING) {
|
||||
*pending = 1;
|
||||
evmask &= ~DM_EVENT_REGISTRATION_PENDING;
|
||||
}
|
||||
|
||||
dm_event_handler_destroy(dmevh);
|
||||
|
||||
return evmask;
|
||||
}
|
||||
|
||||
/* FIXME This gets run while suspended and performs banned operations. */
|
||||
static int _target_set_events(struct lv_segment *seg, int evmask, int set)
|
||||
{
|
||||
char *dso, *name;
|
||||
struct logical_volume *lv;
|
||||
struct volume_group *vg;
|
||||
struct dm_event_handler *dmevh;
|
||||
int r;
|
||||
|
||||
lv = seg->lv;
|
||||
vg = lv->vg;
|
||||
|
||||
if (!_get_mirror_dso_path(vg->cmd, &dso))
|
||||
return_0;
|
||||
|
||||
if (!(name = build_dm_name(vg->cmd->mem, vg->name, lv->name, NULL)))
|
||||
return_0;
|
||||
|
||||
if (!(dmevh = _create_dm_event_handler(name, dso, DM_EVENT_ALL_ERRORS)))
|
||||
return_0;
|
||||
|
||||
r = set ? dm_event_register_handler(dmevh) : dm_event_unregister_handler(dmevh);
|
||||
dm_event_handler_destroy(dmevh);
|
||||
if (!r)
|
||||
return_0;
|
||||
|
||||
log_info("%s %s for events", set ? "Monitored" : "Unmonitored", name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _target_unregister_events(struct lv_segment *seg,
|
||||
int events)
|
||||
static int _target_monitor_events(struct lv_segment *seg, int events)
|
||||
{
|
||||
char *dso;
|
||||
char *name;
|
||||
struct logical_volume *lv;
|
||||
struct volume_group *vg;
|
||||
return _target_set_events(seg, events, 1);
|
||||
}
|
||||
|
||||
lv = seg->lv;
|
||||
vg = lv->vg;
|
||||
|
||||
/* FIXME Remove this and use handle to avoid config file race */
|
||||
if (!_setup_registration(vg->cmd->mem, vg->cmd, &dso))
|
||||
return_0;
|
||||
|
||||
if (!(name = build_dm_name(vg->cmd->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;
|
||||
static int _target_unmonitor_events(struct lv_segment *seg, int events)
|
||||
{
|
||||
return _target_set_events(seg, events, 0);
|
||||
}
|
||||
|
||||
#endif /* DMEVENTD */
|
||||
@@ -486,8 +530,9 @@ static struct segtype_handler _mirrored_ops = {
|
||||
.target_percent = _mirrored_target_percent,
|
||||
.target_present = _mirrored_target_present,
|
||||
#ifdef DMEVENTD
|
||||
.target_register_events = _target_register_events,
|
||||
.target_unregister_events = _target_unregister_events,
|
||||
.target_monitored = _target_monitored,
|
||||
.target_monitor_events = _target_monitor_events,
|
||||
.target_unmonitor_events = _target_unmonitor_events,
|
||||
#endif
|
||||
#endif
|
||||
.modules_needed = _mirrored_modules_needed,
|
||||
@@ -512,7 +557,7 @@ struct segment_type *init_segtype(struct cmd_context *cmd)
|
||||
segtype->ops = &_mirrored_ops;
|
||||
segtype->name = "mirror";
|
||||
segtype->private = NULL;
|
||||
segtype->flags = SEG_AREAS_MIRRORED;
|
||||
segtype->flags = SEG_AREAS_MIRRORED | SEG_MONITORED;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
|
||||
@@ -66,7 +66,8 @@ int create_temp_name(const char *dir, char *buffer, size_t len, int *fd)
|
||||
if (!fcntl(*fd, F_SETLK, &lock))
|
||||
return 1;
|
||||
|
||||
close(*fd);
|
||||
if (close(*fd))
|
||||
log_sys_error("close", buffer);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -239,7 +240,8 @@ void sync_dir(const char *file)
|
||||
if (fsync(fd) && (errno != EROFS) && (errno != EINVAL))
|
||||
log_sys_error("fsync", dir);
|
||||
|
||||
close(fd);
|
||||
if (close(fd))
|
||||
log_sys_error("close", dir);
|
||||
|
||||
out:
|
||||
dm_free(dir);
|
||||
|
||||
@@ -18,67 +18,67 @@
|
||||
* Display Fn, Unique format identifier */
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, "lv_uuid")
|
||||
FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, "lv_name")
|
||||
FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, "lv_attr")
|
||||
FIELD(LVS, lv, NUM, "Maj", major, 3, int32, "lv_major")
|
||||
FIELD(LVS, lv, NUM, "Min", minor, 3, int32, "lv_minor")
|
||||
FIELD(LVS, lv, STR, "KMaj", lvid, 4, lvkmaj, "lv_kernel_major")
|
||||
FIELD(LVS, lv, STR, "KMin", lvid, 4, lvkmin, "lv_kernel_minor")
|
||||
FIELD(LVS, lv, NUM, "LSize", size, 5, size64, "lv_size")
|
||||
FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, "seg_count")
|
||||
FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, "origin")
|
||||
FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, "snap_percent")
|
||||
FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent")
|
||||
FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv")
|
||||
FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags")
|
||||
FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log")
|
||||
FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, "modules")
|
||||
FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, "lv_uuid", "Unique identifier")
|
||||
FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, "lv_name", "Name. LVs created for internal use are enclosed in brackets.")
|
||||
FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, "lv_attr", "Various attributes - see man page.")
|
||||
FIELD(LVS, lv, NUM, "Maj", major, 3, int32, "lv_major", "Persistent major number or -1 if not persistent.")
|
||||
FIELD(LVS, lv, NUM, "Min", minor, 3, int32, "lv_minor", "Persistent minor number or -1 if not persistent.")
|
||||
FIELD(LVS, lv, STR, "KMaj", lvid, 4, lvkmaj, "lv_kernel_major", "Currently assigned major number or -1 if LV is not active.")
|
||||
FIELD(LVS, lv, STR, "KMin", lvid, 4, lvkmin, "lv_kernel_minor", "Currently assigned minor number or -1 if LV is not active.")
|
||||
FIELD(LVS, lv, NUM, "LSize", size, 5, size64, "lv_size", "Size of LV in current units.")
|
||||
FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, "seg_count", "Number of segments in LV.")
|
||||
FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, "origin", "For snapshots, the origin device of this LV")
|
||||
FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, "snap_percent", "For snapshots, the percentage full if LV is active.")
|
||||
FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent", "For mirrors and pvmove, current percentage in-sync.")
|
||||
FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv", "For pvmove, Source PV of temporary LV created by pvmove")
|
||||
FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags", "Tags, if any.")
|
||||
FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log", "For mirrors, the LV holding the synchronisation log.")
|
||||
FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, "modules", "Kernel device-mapper modules required for this LV.")
|
||||
|
||||
FIELD(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt")
|
||||
FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid")
|
||||
FIELD(PVS, pv, NUM, "PSize", id, 5, pvsize, "pv_size")
|
||||
FIELD(PVS, pv, NUM, "DevSize", dev, 7, devsize, "dev_size")
|
||||
FIELD(PVS, pv, NUM, "1st PE", pe_start, 7, size64, "pe_start")
|
||||
FIELD(PVS, pv, NUM, "PFree", id, 5, pvfree, "pv_free")
|
||||
FIELD(PVS, pv, NUM, "Used", id, 4, pvused, "pv_used")
|
||||
FIELD(PVS, pv, STR, "PV", dev, 10, dev_name, "pv_name")
|
||||
FIELD(PVS, pv, STR, "Attr", status, 4, pvstatus, "pv_attr")
|
||||
FIELD(PVS, pv, NUM, "PE", pe_count, 3, uint32, "pv_pe_count")
|
||||
FIELD(PVS, pv, NUM, "Alloc", pe_alloc_count, 5, uint32, "pv_pe_alloc_count")
|
||||
FIELD(PVS, pv, STR, "PV Tags", tags, 7, tags, "pv_tags")
|
||||
FIELD(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt", "Type of metadata.")
|
||||
FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid", "Unique identifier.")
|
||||
FIELD(PVS, pv, NUM, "PSize", id, 5, pvsize, "pv_size", "Size of PV in current units.")
|
||||
FIELD(PVS, pv, NUM, "DevSize", dev, 7, devsize, "dev_size", "Size of underlying device in current units.")
|
||||
FIELD(PVS, pv, NUM, "1st PE", pe_start, 7, size64, "pe_start", "Offset to the start of data on the underlying device.")
|
||||
FIELD(PVS, pv, NUM, "PFree", id, 5, pvfree, "pv_free", "Total amount of unallocated space in current units.")
|
||||
FIELD(PVS, pv, NUM, "Used", id, 4, pvused, "pv_used", "Total amount of allocated space in current units.")
|
||||
FIELD(PVS, pv, STR, "PV", dev, 10, dev_name, "pv_name", "Name.")
|
||||
FIELD(PVS, pv, STR, "Attr", status, 4, pvstatus, "pv_attr", "Various attributes - see man page.")
|
||||
FIELD(PVS, pv, NUM, "PE", pe_count, 3, uint32, "pv_pe_count", "Total number of Physical Extents.")
|
||||
FIELD(PVS, pv, NUM, "Alloc", pe_alloc_count, 5, uint32, "pv_pe_alloc_count", "Total number of allocated Physical Extents.")
|
||||
FIELD(PVS, pv, STR, "PV Tags", tags, 7, tags, "pv_tags", "Tags, if any.")
|
||||
|
||||
FIELD(VGS, vg, STR, "Fmt", cmd, 3, vgfmt, "vg_fmt")
|
||||
FIELD(VGS, vg, STR, "VG UUID", id, 38, uuid, "vg_uuid")
|
||||
FIELD(VGS, vg, STR, "VG", name, 4, string, "vg_name")
|
||||
FIELD(VGS, vg, STR, "Attr", cmd, 5, vgstatus, "vg_attr")
|
||||
FIELD(VGS, vg, NUM, "VSize", cmd, 5, vgsize, "vg_size")
|
||||
FIELD(VGS, vg, NUM, "VFree", cmd, 5, vgfree, "vg_free")
|
||||
FIELD(VGS, vg, STR, "SYS ID", system_id, 6, string, "vg_sysid")
|
||||
FIELD(VGS, vg, NUM, "Ext", extent_size, 3, size32, "vg_extent_size")
|
||||
FIELD(VGS, vg, NUM, "#Ext", extent_count, 4, uint32, "vg_extent_count")
|
||||
FIELD(VGS, vg, NUM, "Free", free_count, 4, uint32, "vg_free_count")
|
||||
FIELD(VGS, vg, NUM, "MaxLV", max_lv, 5, uint32, "max_lv")
|
||||
FIELD(VGS, vg, NUM, "MaxPV", max_pv, 5, uint32, "max_pv")
|
||||
FIELD(VGS, vg, NUM, "#PV", pv_count, 3, uint32, "pv_count")
|
||||
FIELD(VGS, vg, NUM, "#LV", lv_count, 3, uint32, "lv_count")
|
||||
FIELD(VGS, vg, NUM, "#SN", snapshot_count, 3, uint32, "snap_count")
|
||||
FIELD(VGS, vg, NUM, "Seq", seqno, 3, uint32, "vg_seqno")
|
||||
FIELD(VGS, vg, STR, "VG Tags", tags, 7, tags, "vg_tags")
|
||||
FIELD(VGS, vg, STR, "Fmt", cmd, 3, vgfmt, "vg_fmt", "Type of metadata.")
|
||||
FIELD(VGS, vg, STR, "VG UUID", id, 38, uuid, "vg_uuid", "Unique identifier.")
|
||||
FIELD(VGS, vg, STR, "VG", name, 4, string, "vg_name", "Name.")
|
||||
FIELD(VGS, vg, STR, "Attr", cmd, 5, vgstatus, "vg_attr", "Various attributes - see man page.")
|
||||
FIELD(VGS, vg, NUM, "VSize", cmd, 5, vgsize, "vg_size", "Total size of VG in current units.")
|
||||
FIELD(VGS, vg, NUM, "VFree", cmd, 5, vgfree, "vg_free", "Total amount of free space in current units.")
|
||||
FIELD(VGS, vg, STR, "SYS ID", system_id, 6, string, "vg_sysid", "System ID indicating when and where it was created.")
|
||||
FIELD(VGS, vg, NUM, "Ext", extent_size, 3, size32, "vg_extent_size", "Size of Physical Extents in current units.")
|
||||
FIELD(VGS, vg, NUM, "#Ext", extent_count, 4, uint32, "vg_extent_count", "Total number of Physical Extents.")
|
||||
FIELD(VGS, vg, NUM, "Free", free_count, 4, uint32, "vg_free_count", "Total number of unallocated Physical Extents.")
|
||||
FIELD(VGS, vg, NUM, "MaxLV", max_lv, 5, uint32, "max_lv", "Maximum number of LVs allowed in VG or 0 if unlimited.")
|
||||
FIELD(VGS, vg, NUM, "MaxPV", max_pv, 5, uint32, "max_pv", "Maximum number of PVs allowed in VG or 0 if unlimited.")
|
||||
FIELD(VGS, vg, NUM, "#PV", pv_count, 3, uint32, "pv_count", "Number of PVs.")
|
||||
FIELD(VGS, vg, NUM, "#LV", lv_count, 3, uint32, "lv_count", "Number of LVs.")
|
||||
FIELD(VGS, vg, NUM, "#SN", snapshot_count, 3, uint32, "snap_count", "Number of snapshots.")
|
||||
FIELD(VGS, vg, NUM, "Seq", seqno, 3, uint32, "vg_seqno", "Revision number of internal metadata. Incremented whenever it changes.")
|
||||
FIELD(VGS, vg, STR, "VG Tags", tags, 7, tags, "vg_tags", "Tags, if any.")
|
||||
|
||||
FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype")
|
||||
FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes")
|
||||
FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize")
|
||||
FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripe_size")
|
||||
FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunksize")
|
||||
FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunk_size")
|
||||
FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "regionsize")
|
||||
FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "region_size")
|
||||
FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start")
|
||||
FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size")
|
||||
FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags")
|
||||
FIELD(SEGS, seg, STR, "Devices", list, 5, devices, "devices")
|
||||
FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype", "Type of LV segment")
|
||||
FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes", "Number of stripes or mirror legs.")
|
||||
FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize", "For stripes, amount of data placed on one device before switching to the next.")
|
||||
FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripe_size", "For stripes, amount of data placed on one device before switching to the next.")
|
||||
FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "regionsize", "For mirrors, the unit of data copied when synchronising devices.")
|
||||
FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "region_size", "For mirrors, the unit of data copied when synchronising devices.")
|
||||
FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunksize", "For snapshots, the unit of data used when tracking changes.")
|
||||
FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunk_size", "For snapshots, the unit of data used when tracking changes.")
|
||||
FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start", "Offset within the LV to the start of the segment in current units.")
|
||||
FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size", "Size of segment in current units.")
|
||||
FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags", "Tags, if any.")
|
||||
FIELD(SEGS, seg, STR, "Devices", list, 5, devices, "devices", "Underlying devices used with starting extent numbers.")
|
||||
|
||||
FIELD(PVSEGS, pvseg, NUM, "Start", pe, 5, uint32, "pvseg_start")
|
||||
FIELD(PVSEGS, pvseg, NUM, "SSize", len, 5, uint32, "pvseg_size")
|
||||
FIELD(PVSEGS, pvseg, NUM, "Start", pe, 5, uint32, "pvseg_start", "Physical Extent number of start of segment.")
|
||||
FIELD(PVSEGS, pvseg, NUM, "SSize", len, 5, uint32, "pvseg_size", "Number of extents in segment.")
|
||||
/* *INDENT-ON* */
|
||||
|
||||
1185
lib/report/report.c
1185
lib/report/report.c
File diff suppressed because it is too large
Load Diff
@@ -66,6 +66,7 @@ dm_tree_node_add_mirror_target
|
||||
dm_tree_node_add_mirror_target_log
|
||||
dm_tree_node_add_target_area
|
||||
dm_tree_skip_lockfs
|
||||
dm_tree_use_no_flush_suspend
|
||||
dm_is_dm_major
|
||||
dm_mknodes
|
||||
dm_malloc_aux
|
||||
@@ -113,3 +114,16 @@ dm_task_set_geometry
|
||||
dm_split_lvm_name
|
||||
dm_split_words
|
||||
dm_snprintf
|
||||
dm_basename
|
||||
dm_asprintf
|
||||
dm_report_init
|
||||
dm_report_object
|
||||
dm_report_output
|
||||
dm_report_free
|
||||
dm_report_get_private
|
||||
dm_report_field_string
|
||||
dm_report_field_int
|
||||
dm_report_field_int32
|
||||
dm_report_field_uint32
|
||||
dm_report_field_uint64
|
||||
dm_report_field_set_value
|
||||
|
||||
@@ -24,6 +24,7 @@ SOURCES =\
|
||||
libdm-file.c \
|
||||
libdm-deptree.c \
|
||||
libdm-string.c \
|
||||
libdm-report.c \
|
||||
mm/dbg_malloc.c \
|
||||
mm/pool.c \
|
||||
$(interface)/libdm-iface.c
|
||||
@@ -38,8 +39,8 @@ else
|
||||
LIB_SHARED = $(interface)/libdevmapper.so
|
||||
endif
|
||||
|
||||
CFLAGS += -DDEVICE_UID=@DEVICE_UID@ -DDEVICE_GID=@DEVICE_GID@ \
|
||||
-DDEVICE_MODE=@DEVICE_MODE@
|
||||
DEFS += -DDEVICE_UID=@DEVICE_UID@ -DDEVICE_GID=@DEVICE_GID@ \
|
||||
-DDEVICE_MODE=@DEVICE_MODE@
|
||||
|
||||
include ../make.tmpl
|
||||
|
||||
@@ -89,7 +90,7 @@ install_ioctl_static: ioctl/libdevmapper.a
|
||||
.PHONY: distclean_lib distclean
|
||||
|
||||
distclean_lib:
|
||||
$(RM) libdm-common.h libdevmapper.pc
|
||||
$(RM) libdevmapper.pc
|
||||
|
||||
distclean: distclean_lib
|
||||
|
||||
|
||||
@@ -230,12 +230,14 @@ void dm_hash_wipe(struct dm_hash_table *t)
|
||||
t->num_nodes = 0u;
|
||||
}
|
||||
|
||||
char *dm_hash_get_key(struct dm_hash_table *t, struct dm_hash_node *n)
|
||||
char *dm_hash_get_key(struct dm_hash_table *t __attribute((unused)),
|
||||
struct dm_hash_node *n)
|
||||
{
|
||||
return n->key;
|
||||
}
|
||||
|
||||
void *dm_hash_get_data(struct dm_hash_table *t, struct dm_hash_node *n)
|
||||
void *dm_hash_get_data(struct dm_hash_table *t __attribute((unused)),
|
||||
struct dm_hash_node *n)
|
||||
{
|
||||
return n->data;
|
||||
}
|
||||
|
||||
@@ -149,7 +149,8 @@ static int _get_proc_number(const char *file, const char *name,
|
||||
if (!strcmp(name, nm)) {
|
||||
if (number) {
|
||||
*number = num;
|
||||
fclose(fl);
|
||||
if (fclose(fl))
|
||||
log_error("%s: fclose failed: %s", file, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
dm_bit_set(_dm_bitset, num);
|
||||
@@ -158,7 +159,8 @@ static int _get_proc_number(const char *file, const char *name,
|
||||
c = fgetc(fl);
|
||||
} while (c != EOF && c != '\n');
|
||||
}
|
||||
fclose(fl);
|
||||
if (fclose(fl))
|
||||
log_error("%s: fclose failed: %s", file, strerror(errno));
|
||||
|
||||
if (number) {
|
||||
log_error("%s: No entry for %s found", file, name);
|
||||
@@ -1322,7 +1324,7 @@ static int _process_mapper_dir(struct dm_task *dmt)
|
||||
|
||||
dir = dm_dir();
|
||||
if (!(d = opendir(dir))) {
|
||||
fprintf(stderr, "opendir %s: %s", dir, strerror(errno));
|
||||
log_error("opendir %s: %s", dir, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1335,9 +1337,8 @@ static int _process_mapper_dir(struct dm_task *dmt)
|
||||
dm_task_run(dmt);
|
||||
}
|
||||
|
||||
if (closedir(d)) {
|
||||
fprintf(stderr, "closedir %s: %s", dir, strerror(errno));
|
||||
}
|
||||
if (closedir(d))
|
||||
log_error("closedir %s: %s", dir, strerror(errno));
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -1506,6 +1507,8 @@ static int _reload_with_suppression_v4(struct dm_task *dmt)
|
||||
t2 = task->head;
|
||||
|
||||
while (t1 && t2) {
|
||||
while (t2->params[strlen(t2->params) - 1] == ' ')
|
||||
t2->params[strlen(t2->params) - 1] = '\0';
|
||||
if ((t1->start != t2->start) ||
|
||||
(t1->length != t2->length) ||
|
||||
(strcmp(t1->type, t2->type)) ||
|
||||
|
||||
@@ -124,10 +124,10 @@ struct dm_names {
|
||||
};
|
||||
|
||||
struct dm_versions {
|
||||
uint32_t next; /* Offset to next struct from start of this struct */
|
||||
uint32_t version[3];
|
||||
uint32_t next; /* Offset to next struct from start of this struct */
|
||||
uint32_t version[3];
|
||||
|
||||
char name[0];
|
||||
char name[0];
|
||||
};
|
||||
|
||||
int dm_get_library_version(char *version, size_t size);
|
||||
@@ -236,12 +236,12 @@ int dm_tree_add_dev(struct dm_tree *tree, uint32_t major, uint32_t minor);
|
||||
* Add a new node to the tree if it doesn't already exist.
|
||||
*/
|
||||
struct dm_tree_node *dm_tree_add_new_dev(struct dm_tree *tree,
|
||||
const char *name,
|
||||
const char *uuid,
|
||||
uint32_t major, uint32_t minor,
|
||||
int read_only,
|
||||
int clear_inactive,
|
||||
void *context);
|
||||
const char *name,
|
||||
const char *uuid,
|
||||
uint32_t major, uint32_t minor,
|
||||
int read_only,
|
||||
int clear_inactive,
|
||||
void *context);
|
||||
|
||||
/*
|
||||
* Search for a node in the tree.
|
||||
@@ -289,16 +289,16 @@ int dm_tree_deactivate_children(struct dm_tree_node *dnode,
|
||||
* Ignores devices that don't have a uuid starting with uuid_prefix.
|
||||
*/
|
||||
int dm_tree_preload_children(struct dm_tree_node *dnode,
|
||||
const char *uuid_prefix,
|
||||
size_t uuid_prefix_len);
|
||||
const char *uuid_prefix,
|
||||
size_t uuid_prefix_len);
|
||||
|
||||
/*
|
||||
* Resume a device plus all dependencies.
|
||||
* Ignores devices that don't have a uuid starting with uuid_prefix.
|
||||
*/
|
||||
int dm_tree_activate_children(struct dm_tree_node *dnode,
|
||||
const char *uuid_prefix,
|
||||
size_t uuid_prefix_len);
|
||||
const char *uuid_prefix,
|
||||
size_t uuid_prefix_len);
|
||||
|
||||
/*
|
||||
* Suspend a device plus all dependencies.
|
||||
@@ -315,6 +315,16 @@ int dm_tree_suspend_children(struct dm_tree_node *dnode,
|
||||
*/
|
||||
void dm_tree_skip_lockfs(struct dm_tree_node *dnode);
|
||||
|
||||
/*
|
||||
* Set the 'noflush' flag when suspending devices.
|
||||
* If the kernel supports it, instead of erroring outstanding I/O that
|
||||
* cannot be completed, the I/O is queued and resubmitted when the
|
||||
* device is resumed. This affects multipath devices when all paths
|
||||
* have failed and queue_if_no_path is set, and mirror devices when
|
||||
* block_on_error is set and the mirror log has failed.
|
||||
*/
|
||||
void dm_tree_use_no_flush_suspend(struct dm_tree_node *dnode);
|
||||
|
||||
/*
|
||||
* Is the uuid prefix present in the tree?
|
||||
* Only returns 0 if every node was checked successfully.
|
||||
@@ -608,4 +618,97 @@ int dm_split_words(char *buffer, unsigned max,
|
||||
*/
|
||||
int dm_snprintf(char *buf, size_t bufsize, const char *format, ...);
|
||||
|
||||
/*
|
||||
* Returns pointer to the last component of the path.
|
||||
*/
|
||||
char *dm_basename(const char *path);
|
||||
|
||||
/*
|
||||
* Returns size of a buffer which is allocated with dm_malloc.
|
||||
* Pointer to the buffer is stored in *buf.
|
||||
* Returns -1 on failure leaving buf undefined.
|
||||
*/
|
||||
int dm_asprintf(char **buf, const char *format, ...);
|
||||
|
||||
/*********************
|
||||
* reporting functions
|
||||
*********************/
|
||||
|
||||
struct dm_report_object_type {
|
||||
uint32_t id; /* Powers of 2 */
|
||||
const char *desc;
|
||||
const char *prefix; /* field id string prefix (optional) */
|
||||
void *(*data_fn)(void *object); /* callback from report_object() */
|
||||
};
|
||||
|
||||
struct dm_report_field;
|
||||
|
||||
/*
|
||||
* dm_report_field_type flags
|
||||
*/
|
||||
#define DM_REPORT_FIELD_MASK 0x000000FF
|
||||
#define DM_REPORT_FIELD_ALIGN_MASK 0x0000000F
|
||||
#define DM_REPORT_FIELD_ALIGN_LEFT 0x00000001
|
||||
#define DM_REPORT_FIELD_ALIGN_RIGHT 0x00000002
|
||||
#define DM_REPORT_FIELD_TYPE_MASK 0x000000F0
|
||||
#define DM_REPORT_FIELD_TYPE_STRING 0x00000010
|
||||
#define DM_REPORT_FIELD_TYPE_NUMBER 0x00000020
|
||||
|
||||
struct dm_report;
|
||||
struct dm_report_field_type {
|
||||
uint32_t type; /* object type id */
|
||||
const char id[32]; /* string used to specify the field */
|
||||
unsigned int offset; /* byte offset in the object */
|
||||
const char heading[32]; /* string printed in header */
|
||||
int width; /* default width */
|
||||
uint32_t flags; /* DM_REPORT_FIELD_* */
|
||||
int (*report_fn)(struct dm_report *rh, struct dm_pool *mem,
|
||||
struct dm_report_field *field, const void *data,
|
||||
void *private);
|
||||
const char *desc; /* description of the field */
|
||||
};
|
||||
|
||||
/*
|
||||
* dm_report_init output_flags
|
||||
*/
|
||||
#define DM_REPORT_OUTPUT_MASK 0x000000FF
|
||||
#define DM_REPORT_OUTPUT_ALIGNED 0x00000001
|
||||
#define DM_REPORT_OUTPUT_BUFFERED 0x00000002
|
||||
#define DM_REPORT_OUTPUT_HEADINGS 0x00000004
|
||||
|
||||
struct dm_report *dm_report_init(uint32_t *report_types,
|
||||
const struct dm_report_object_type *types,
|
||||
const struct dm_report_field_type *fields,
|
||||
const char *output_fields,
|
||||
const char *output_separator,
|
||||
uint32_t output_flags,
|
||||
const char *sort_keys,
|
||||
void *private);
|
||||
int dm_report_object(struct dm_report *rh, void *object);
|
||||
int dm_report_output(struct dm_report *rh);
|
||||
void dm_report_free(struct dm_report *rh);
|
||||
|
||||
/*
|
||||
* Report functions are provided for simple data types.
|
||||
* They take care of allocating copies of the data.
|
||||
*/
|
||||
int dm_report_field_string(struct dm_report *rh, struct dm_report_field *field,
|
||||
const char **data);
|
||||
int dm_report_field_int32(struct dm_report *rh, struct dm_report_field *field,
|
||||
const int32_t *data);
|
||||
int dm_report_field_uint32(struct dm_report *rh, struct dm_report_field *field,
|
||||
const uint32_t *data);
|
||||
int dm_report_field_int(struct dm_report *rh, struct dm_report_field *field,
|
||||
const int *data);
|
||||
int dm_report_field_uint64(struct dm_report *rh, struct dm_report_field *field,
|
||||
const uint64_t *data);
|
||||
|
||||
/*
|
||||
* For custom fields, allocate the data in 'mem' and use
|
||||
* dm_report_field_set_value().
|
||||
* 'sortvalue' may be NULL if it matches 'value'
|
||||
*/
|
||||
void dm_report_field_set_value(struct dm_report_field *field, const void *value,
|
||||
const void *sortvalue);
|
||||
|
||||
#endif /* LIB_DEVICE_MAPPER_H */
|
||||
|
||||
@@ -38,8 +38,8 @@ static int _verbose = 0;
|
||||
* Library users can provide their own logging
|
||||
* function.
|
||||
*/
|
||||
static void _default_log(int level, const char *file, int line,
|
||||
const char *f, ...)
|
||||
static void _default_log(int level, const char *file __attribute((unused)),
|
||||
int line __attribute((unused)), const char *f, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
|
||||
@@ -28,6 +28,4 @@ int rm_dev_node(const char *dev_name);
|
||||
int rename_dev_node(const char *old_name, const char *new_name);
|
||||
void update_devs(void);
|
||||
|
||||
#define DM_LIB_VERSION @DM_LIB_VERSION@
|
||||
|
||||
#endif
|
||||
@@ -130,6 +130,7 @@ struct dm_tree {
|
||||
struct dm_hash_table *uuids;
|
||||
struct dm_tree_node root;
|
||||
int skip_lockfs; /* 1 skips lockfs (for non-snapshots) */
|
||||
int no_flush; /* 1 sets noflush (mirrors/multipath) */
|
||||
};
|
||||
|
||||
/* FIXME Consider exporting this */
|
||||
@@ -162,6 +163,7 @@ struct dm_tree *dm_tree_create(void)
|
||||
list_init(&dtree->root.uses);
|
||||
list_init(&dtree->root.used_by);
|
||||
dtree->skip_lockfs = 0;
|
||||
dtree->no_flush = 0;
|
||||
|
||||
if (!(dtree->mem = dm_pool_create("dtree", 1024))) {
|
||||
log_error("dtree pool creation failed");
|
||||
@@ -903,13 +905,15 @@ 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,
|
||||
int skip_lockfs, struct dm_info *newinfo)
|
||||
int skip_lockfs, int no_flush, struct dm_info *newinfo)
|
||||
{
|
||||
struct dm_task *dmt;
|
||||
int r;
|
||||
|
||||
log_verbose("Suspending %s (%" PRIu32 ":%" PRIu32 ")%s", name, major,
|
||||
minor, skip_lockfs ? "" : " with filesystem sync.");
|
||||
log_verbose("Suspending %s (%" PRIu32 ":%" PRIu32 ")%s%s",
|
||||
name, major, minor,
|
||||
skip_lockfs ? "" : " with filesystem sync",
|
||||
no_flush ? "" : " without device flush");
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_SUSPEND))) {
|
||||
log_error("Suspend dm_task creation failed for %s", name);
|
||||
@@ -928,6 +932,9 @@ static int _suspend_node(const char *name, uint32_t major, uint32_t minor,
|
||||
if (skip_lockfs && !dm_task_skip_lockfs(dmt))
|
||||
log_error("Failed to set skip_lockfs flag.");
|
||||
|
||||
if (no_flush && !dm_task_no_flush(dmt))
|
||||
log_error("Failed to set no_flush flag.");
|
||||
|
||||
if ((r = dm_task_run(dmt)))
|
||||
r = dm_task_get_info(dmt, newinfo);
|
||||
|
||||
@@ -991,6 +998,11 @@ void dm_tree_skip_lockfs(struct dm_tree_node *dnode)
|
||||
dnode->dtree->skip_lockfs = 1;
|
||||
}
|
||||
|
||||
void dm_tree_use_no_flush_suspend(struct dm_tree_node *dnode)
|
||||
{
|
||||
dnode->dtree->no_flush = 1;
|
||||
}
|
||||
|
||||
int dm_tree_suspend_children(struct dm_tree_node *dnode,
|
||||
const char *uuid_prefix,
|
||||
size_t uuid_prefix_len)
|
||||
@@ -1032,7 +1044,8 @@ int dm_tree_suspend_children(struct dm_tree_node *dnode,
|
||||
continue;
|
||||
|
||||
if (!_suspend_node(name, info.major, info.minor,
|
||||
child->dtree->skip_lockfs, &newinfo)) {
|
||||
child->dtree->skip_lockfs,
|
||||
child->dtree->no_flush, &newinfo)) {
|
||||
log_error("Unable to suspend %s (%" PRIu32
|
||||
":%" PRIu32 ")", name, info.major,
|
||||
info.minor);
|
||||
@@ -1199,7 +1212,9 @@ static int _build_dev_string(char *devbuf, size_t bufsize, struct dm_tree_node *
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _emit_areas_line(struct dm_task *dmt, struct load_segment *seg, char *params, size_t paramsize, int *pos)
|
||||
static int _emit_areas_line(struct dm_task *dmt __attribute((unused)),
|
||||
struct load_segment *seg, char *params,
|
||||
size_t paramsize, int *pos)
|
||||
{
|
||||
struct seg_area *area;
|
||||
char devbuf[10];
|
||||
|
||||
838
libdm/libdm-report.c
Normal file
838
libdm/libdm-report.c
Normal file
@@ -0,0 +1,838 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of device-mapper userspace tools.
|
||||
* The code is based on LVM2 report function.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
|
||||
/*
|
||||
* Internal flags
|
||||
*/
|
||||
#define RH_SORT_REQUIRED 0x00000100
|
||||
#define RH_HEADINGS_PRINTED 0x00000200
|
||||
|
||||
struct dm_report {
|
||||
struct dm_pool *mem;
|
||||
|
||||
uint32_t report_types;
|
||||
const char *field_prefix;
|
||||
uint32_t flags;
|
||||
const char *separator;
|
||||
|
||||
uint32_t keys_count;
|
||||
|
||||
/* Ordered list of fields needed for this report */
|
||||
struct list field_props;
|
||||
|
||||
/* Rows of report data */
|
||||
struct list rows;
|
||||
|
||||
/* Array of field definitions */
|
||||
const struct dm_report_field_type *fields;
|
||||
const struct dm_report_object_type *types;
|
||||
|
||||
/* To store caller private data */
|
||||
void *private;
|
||||
};
|
||||
|
||||
/*
|
||||
* Internal per-field flags
|
||||
*/
|
||||
#define FLD_HIDDEN 0x00000100
|
||||
#define FLD_SORT_KEY 0x00000200
|
||||
#define FLD_ASCENDING 0x00000400
|
||||
#define FLD_DESCENDING 0x00000800
|
||||
|
||||
struct field_properties {
|
||||
struct list list;
|
||||
uint32_t field_num;
|
||||
uint32_t sort_posn;
|
||||
unsigned width;
|
||||
const struct dm_report_object_type *type;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* Report data field
|
||||
*/
|
||||
struct dm_report_field {
|
||||
struct list list;
|
||||
struct field_properties *props;
|
||||
|
||||
const char *report_string; /* Formatted ready for display */
|
||||
const void *sort_value; /* Raw value for sorting */
|
||||
};
|
||||
|
||||
struct row {
|
||||
struct list list;
|
||||
struct dm_report *rh;
|
||||
struct list fields; /* Fields in display order */
|
||||
struct dm_report_field *(*sort_fields)[]; /* Fields in sort order */
|
||||
};
|
||||
|
||||
static const struct dm_report_object_type *_find_type(struct dm_report *rh,
|
||||
uint32_t report_type)
|
||||
{
|
||||
const struct dm_report_object_type *t;
|
||||
|
||||
for (t = rh->types; t->data_fn; t++)
|
||||
if (t->id == report_type)
|
||||
return t;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Data-munging functions to prepare each data type for display and sorting
|
||||
*/
|
||||
|
||||
int dm_report_field_string(struct dm_report *rh,
|
||||
struct dm_report_field *field, const char **data)
|
||||
{
|
||||
char *repstr;
|
||||
|
||||
if (!(repstr = dm_pool_strdup(rh->mem, *data))) {
|
||||
log_error("dm_report_field_string: dm_pool_strdup failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
field->report_string = repstr;
|
||||
field->sort_value = (const void *) field->report_string;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_report_field_int(struct dm_report *rh,
|
||||
struct dm_report_field *field, const int *data)
|
||||
{
|
||||
const int value = *data;
|
||||
uint64_t *sortval;
|
||||
char *repstr;
|
||||
|
||||
if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
|
||||
log_error("dm_report_field_int: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
|
||||
log_error("dm_report_field_int: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(repstr, 12, "%d", value) < 0) {
|
||||
log_error("dm_report_field_int: int too big: %d", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sortval = (const uint64_t) value;
|
||||
field->sort_value = sortval;
|
||||
field->report_string = repstr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_report_field_uint32(struct dm_report *rh,
|
||||
struct dm_report_field *field, const uint32_t *data)
|
||||
{
|
||||
const uint32_t value = *data;
|
||||
uint64_t *sortval;
|
||||
char *repstr;
|
||||
|
||||
if (!(repstr = dm_pool_zalloc(rh->mem, 12))) {
|
||||
log_error("dm_report_field_uint32: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
|
||||
log_error("dm_report_field_uint32: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(repstr, 11, "%u", value) < 0) {
|
||||
log_error("dm_report_field_uint32: uint32 too big: %u", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sortval = (const uint64_t) value;
|
||||
field->sort_value = sortval;
|
||||
field->report_string = repstr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_report_field_int32(struct dm_report *rh,
|
||||
struct dm_report_field *field, const int32_t *data)
|
||||
{
|
||||
const int32_t value = *data;
|
||||
uint64_t *sortval;
|
||||
char *repstr;
|
||||
|
||||
if (!(repstr = dm_pool_zalloc(rh->mem, 13))) {
|
||||
log_error("dm_report_field_int32: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(int64_t)))) {
|
||||
log_error("dm_report_field_int32: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(repstr, 12, "%d", value) < 0) {
|
||||
log_error("dm_report_field_int32: int32 too big: %d", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sortval = (const uint64_t) value;
|
||||
field->sort_value = sortval;
|
||||
field->report_string = repstr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_report_field_uint64(struct dm_report *rh,
|
||||
struct dm_report_field *field, const uint64_t *data)
|
||||
{
|
||||
const int value = *data;
|
||||
uint64_t *sortval;
|
||||
char *repstr;
|
||||
|
||||
if (!(repstr = dm_pool_zalloc(rh->mem, 22))) {
|
||||
log_error("dm_report_field_uint64: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(sortval = dm_pool_alloc(rh->mem, sizeof(uint64_t)))) {
|
||||
log_error("dm_report_field_uint64: dm_pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dm_snprintf(repstr, 21, "%d", value) < 0) {
|
||||
log_error("dm_report_field_uint64: uint64 too big: %d", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sortval = (const uint64_t) value;
|
||||
field->sort_value = sortval;
|
||||
field->report_string = repstr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper functions for custom report functions
|
||||
*/
|
||||
void dm_report_field_set_value(struct dm_report_field *field, const void *value, const void *sortvalue)
|
||||
{
|
||||
field->report_string = (const char *) value;
|
||||
field->sort_value = sortvalue ? : value;
|
||||
}
|
||||
|
||||
/*
|
||||
* show help message
|
||||
*/
|
||||
static void _display_fields(struct dm_report *rh)
|
||||
{
|
||||
uint32_t f;
|
||||
const struct dm_report_object_type *type;
|
||||
const char *desc, *last_desc = "";
|
||||
size_t id_len = 0;
|
||||
|
||||
for (f = 0; rh->fields[f].report_fn; f++)
|
||||
if (strlen(rh->fields[f].id) > id_len)
|
||||
id_len = strlen(rh->fields[f].id);
|
||||
|
||||
for (f = 0; rh->fields[f].report_fn; f++) {
|
||||
if ((type = _find_type(rh, rh->fields[f].type)) && type->desc)
|
||||
desc = type->desc;
|
||||
else
|
||||
desc = " ";
|
||||
if (desc != last_desc) {
|
||||
if (*last_desc)
|
||||
log_print(" ");
|
||||
log_print("%s Fields", desc);
|
||||
log_print("%*.*s", (int) strlen(desc) + 7,
|
||||
(int) strlen(desc) + 7,
|
||||
"------------------------------------------");
|
||||
|
||||
}
|
||||
|
||||
/* FIXME Add line-wrapping at terminal width (or 80 cols) */
|
||||
log_print(" %-*s - %s", (int) id_len, rh->fields[f].id, rh->fields[f].desc);
|
||||
last_desc = desc;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise report handle
|
||||
*/
|
||||
static int _copy_field(struct dm_report *rh, struct field_properties *dest,
|
||||
uint32_t field_num)
|
||||
{
|
||||
dest->field_num = field_num;
|
||||
dest->width = rh->fields[field_num].width;
|
||||
dest->flags = rh->fields[field_num].flags & DM_REPORT_FIELD_MASK;
|
||||
|
||||
/* set object type method */
|
||||
dest->type = _find_type(rh, rh->fields[field_num].type);
|
||||
if (!dest->type) {
|
||||
log_error("dm_report: field not match: %s",
|
||||
rh->fields[field_num].id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _field_match(struct dm_report *rh, const char *field, size_t flen)
|
||||
{
|
||||
uint32_t f, l;
|
||||
struct field_properties *fp;
|
||||
|
||||
if (!flen)
|
||||
return 0;
|
||||
|
||||
for (f = 0; rh->fields[f].report_fn; f++) {
|
||||
if ((!strncasecmp(rh->fields[f].id, field, flen) &&
|
||||
strlen(rh->fields[f].id) == flen) ||
|
||||
(l = strlen(rh->field_prefix),
|
||||
!strncasecmp(rh->field_prefix, rh->fields[f].id, l) &&
|
||||
!strncasecmp(rh->fields[f].id + l, field, flen) &&
|
||||
strlen(rh->fields[f].id) == l + flen)) {
|
||||
rh->report_types |= rh->fields[f].type;
|
||||
if (!(fp = dm_pool_zalloc(rh->mem, sizeof(*fp)))) {
|
||||
log_error("dm_report: "
|
||||
"struct field_properties allocation "
|
||||
"failed");
|
||||
return 0;
|
||||
}
|
||||
if (!_copy_field(rh, fp, f))
|
||||
return 0;
|
||||
|
||||
list_add(&rh->field_props, &fp->list);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _add_sort_key(struct dm_report *rh, uint32_t field_num,
|
||||
uint32_t flags)
|
||||
{
|
||||
struct field_properties *fp, *found = NULL;
|
||||
|
||||
list_iterate_items(fp, &rh->field_props) {
|
||||
if (fp->field_num == field_num) {
|
||||
found = fp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
rh->report_types |= rh->fields[field_num].type;
|
||||
if (!(found = dm_pool_zalloc(rh->mem, sizeof(*found)))) {
|
||||
log_error("dm_report: "
|
||||
"struct field_properties allocation failed");
|
||||
return 0;
|
||||
}
|
||||
if (!_copy_field(rh, found, field_num))
|
||||
return 0;
|
||||
|
||||
/* Add as a non-display field */
|
||||
found->flags |= FLD_HIDDEN;
|
||||
|
||||
list_add(&rh->field_props, &found->list);
|
||||
}
|
||||
|
||||
if (found->flags & FLD_SORT_KEY) {
|
||||
log_error("dm_report: Ignoring duplicate sort field: %s",
|
||||
rh->fields[field_num].id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
found->flags |= FLD_SORT_KEY;
|
||||
found->sort_posn = rh->keys_count++;
|
||||
found->flags |= flags;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _key_match(struct dm_report *rh, const char *key, size_t len)
|
||||
{
|
||||
uint32_t f, l;
|
||||
uint32_t flags;
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
if (*key == '+') {
|
||||
key++;
|
||||
len--;
|
||||
flags = FLD_ASCENDING;
|
||||
} else if (*key == '-') {
|
||||
key++;
|
||||
len--;
|
||||
flags = FLD_DESCENDING;
|
||||
} else
|
||||
flags = FLD_ASCENDING;
|
||||
|
||||
if (!len) {
|
||||
log_error("dm_report: Missing sort field name");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (f = 0; rh->fields[f].report_fn; f++) {
|
||||
if ((!strncasecmp(rh->fields[f].id, key, len) &&
|
||||
strlen(rh->fields[f].id) == len) ||
|
||||
(l = strlen(rh->field_prefix),
|
||||
!strncasecmp(rh->field_prefix, rh->fields[f].id, l) &&
|
||||
!strncasecmp(rh->fields[f].id + l, key, len) &&
|
||||
strlen(rh->fields[f].id) == l + len)) {
|
||||
return _add_sort_key(rh, f, flags);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _parse_options(struct dm_report *rh, const char *format)
|
||||
{
|
||||
const char *ws; /* Word start */
|
||||
const char *we = format; /* Word end */
|
||||
|
||||
while (*we) {
|
||||
/* Allow consecutive commas */
|
||||
while (*we && *we == ',')
|
||||
we++;
|
||||
|
||||
/* start of the field name */
|
||||
ws = we;
|
||||
while (*we && *we != ',')
|
||||
we++;
|
||||
|
||||
if (!_field_match(rh, ws, (size_t) (we - ws))) {
|
||||
_display_fields(rh);
|
||||
log_print(" ");
|
||||
if (strcasecmp(ws, "help") && strcmp(ws, "?"))
|
||||
log_error("Unrecognised field: %.*s",
|
||||
(int) (we - ws), ws);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _parse_keys(struct dm_report *rh, const char *keys)
|
||||
{
|
||||
const char *ws; /* Word start */
|
||||
const char *we = keys; /* Word end */
|
||||
|
||||
while (*we) {
|
||||
/* Allow consecutive commas */
|
||||
while (*we && *we == ',')
|
||||
we++;
|
||||
ws = we;
|
||||
while (*we && *we != ',')
|
||||
we++;
|
||||
if (!_key_match(rh, ws, (size_t) (we - ws))) {
|
||||
log_error("dm_report: Unrecognised field: %.*s",
|
||||
(int) (we - ws), ws);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dm_report *dm_report_init(uint32_t *report_types,
|
||||
const struct dm_report_object_type *types,
|
||||
const struct dm_report_field_type *fields,
|
||||
const char *output_fields,
|
||||
const char *output_separator,
|
||||
uint32_t output_flags,
|
||||
const char *sort_keys,
|
||||
void *private)
|
||||
{
|
||||
struct dm_report *rh;
|
||||
const struct dm_report_object_type *type;
|
||||
|
||||
if (!(rh = dm_malloc(sizeof(*rh)))) {
|
||||
log_error("dm_report_init: dm_malloc failed");
|
||||
return 0;
|
||||
}
|
||||
memset(rh, 0, sizeof(*rh));
|
||||
|
||||
/*
|
||||
* rh->report_types is updated in _parse_options() and _parse_keys()
|
||||
* to contain all types corresponding to the fields specified by
|
||||
* options or keys.
|
||||
*/
|
||||
if (report_types)
|
||||
rh->report_types = *report_types;
|
||||
|
||||
rh->separator = output_separator;
|
||||
rh->fields = fields;
|
||||
rh->types = types;
|
||||
rh->private = private;
|
||||
|
||||
rh->flags |= output_flags & DM_REPORT_OUTPUT_MASK;
|
||||
|
||||
if (output_flags & DM_REPORT_OUTPUT_BUFFERED)
|
||||
rh->flags |= RH_SORT_REQUIRED;
|
||||
|
||||
list_init(&rh->field_props);
|
||||
list_init(&rh->rows);
|
||||
|
||||
if ((type = _find_type(rh, rh->report_types)) && type->prefix)
|
||||
rh->field_prefix = type->prefix;
|
||||
else
|
||||
rh->field_prefix = "";
|
||||
|
||||
if (!(rh->mem = dm_pool_create("report", 10 * 1024))) {
|
||||
log_error("dm_report_init: allocation of memory pool failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Generate list of fields for output based on format string & flags */
|
||||
if (!_parse_options(rh, output_fields))
|
||||
return NULL;
|
||||
|
||||
if (!_parse_keys(rh, sort_keys))
|
||||
return NULL;
|
||||
|
||||
/* Return updated types value for further compatility check by caller */
|
||||
if (report_types)
|
||||
*report_types = rh->report_types;
|
||||
|
||||
return rh;
|
||||
}
|
||||
|
||||
void dm_report_free(struct dm_report *rh)
|
||||
{
|
||||
dm_pool_destroy(rh->mem);
|
||||
dm_free(rh);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a row of data for an object
|
||||
*/
|
||||
static void * _report_get_field_data(struct dm_report *rh,
|
||||
struct field_properties *fp, void *object)
|
||||
{
|
||||
void *ret = fp->type->data_fn(object);
|
||||
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
return ret + rh->fields[fp->field_num].offset;
|
||||
}
|
||||
|
||||
int dm_report_object(struct dm_report *rh, void *object)
|
||||
{
|
||||
struct field_properties *fp;
|
||||
struct row *row;
|
||||
struct dm_report_field *field;
|
||||
void *data = NULL;
|
||||
|
||||
if (!(row = dm_pool_zalloc(rh->mem, sizeof(*row)))) {
|
||||
log_error("dm_report_object: struct row allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
row->rh = rh;
|
||||
|
||||
if ((rh->flags & RH_SORT_REQUIRED) &&
|
||||
!(row->sort_fields =
|
||||
dm_pool_zalloc(rh->mem, sizeof(struct dm_report_field *) *
|
||||
rh->keys_count))) {
|
||||
log_error("dm_report_object: "
|
||||
"row sort value structure allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_init(&row->fields);
|
||||
list_add(&rh->rows, &row->list);
|
||||
|
||||
/* For each field to be displayed, call its report_fn */
|
||||
list_iterate_items(fp, &rh->field_props) {
|
||||
if (!(field = dm_pool_zalloc(rh->mem, sizeof(*field)))) {
|
||||
log_error("dm_report_object: "
|
||||
"struct dm_report_field allocation failed");
|
||||
return 0;
|
||||
}
|
||||
field->props = fp;
|
||||
|
||||
data = _report_get_field_data(rh, fp, object);
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
if (!rh->fields[fp->field_num].report_fn(rh, rh->mem,
|
||||
field, data,
|
||||
rh->private)) {
|
||||
log_error("dm_report_object: "
|
||||
"report function failed for field %s",
|
||||
rh->fields[fp->field_num].id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((strlen(field->report_string) > field->props->width))
|
||||
field->props->width = strlen(field->report_string);
|
||||
|
||||
if ((rh->flags & RH_SORT_REQUIRED) &&
|
||||
(field->props->flags & FLD_SORT_KEY)) {
|
||||
(*row->sort_fields)[field->props->sort_posn] = field;
|
||||
}
|
||||
list_add(&row->fields, &field->list);
|
||||
}
|
||||
|
||||
if (!(rh->flags & DM_REPORT_OUTPUT_BUFFERED))
|
||||
return dm_report_output(rh);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print row of headings
|
||||
*/
|
||||
static int _report_headings(struct dm_report *rh)
|
||||
{
|
||||
struct field_properties *fp;
|
||||
const char *heading;
|
||||
char buf[1024];
|
||||
|
||||
if (rh->flags & RH_HEADINGS_PRINTED)
|
||||
return 1;
|
||||
|
||||
rh->flags |= RH_HEADINGS_PRINTED;
|
||||
|
||||
if (!(rh->flags & DM_REPORT_OUTPUT_HEADINGS))
|
||||
return 1;
|
||||
|
||||
if (!dm_pool_begin_object(rh->mem, 128)) {
|
||||
log_error("dm_report: "
|
||||
"dm_pool_begin_object failed for headings");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* First heading line */
|
||||
list_iterate_items(fp, &rh->field_props) {
|
||||
if (fp->flags & FLD_HIDDEN)
|
||||
continue;
|
||||
|
||||
heading = rh->fields[fp->field_num].heading;
|
||||
if (rh->flags & DM_REPORT_OUTPUT_ALIGNED) {
|
||||
if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
|
||||
fp->width, fp->width, heading) < 0) {
|
||||
log_error("dm_report: snprintf heading failed");
|
||||
goto bad;
|
||||
}
|
||||
if (!dm_pool_grow_object(rh->mem, buf, fp->width)) {
|
||||
log_error("dm_report: Failed to generate report headings for printing");
|
||||
goto bad;
|
||||
}
|
||||
} else if (!dm_pool_grow_object(rh->mem, heading,
|
||||
strlen(heading))) {
|
||||
log_error("dm_report: Failed to generate report headings for printing");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!list_end(&rh->field_props, &fp->list))
|
||||
if (!dm_pool_grow_object(rh->mem, rh->separator,
|
||||
strlen(rh->separator))) {
|
||||
log_error("dm_report: Failed to generate report headings for printing");
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
|
||||
log_error("dm_report: Failed to generate report headings for printing");
|
||||
goto bad;
|
||||
}
|
||||
log_print("%s", (char *) dm_pool_end_object(rh->mem));
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
dm_pool_abandon_object(rh->mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort rows of data
|
||||
*/
|
||||
static int _row_compare(const void *a, const void *b)
|
||||
{
|
||||
const struct row *rowa = *(const struct row **) a;
|
||||
const struct row *rowb = *(const struct row **) b;
|
||||
const struct dm_report_field *sfa, *sfb;
|
||||
uint32_t cnt;
|
||||
|
||||
for (cnt = 0; cnt < rowa->rh->keys_count; cnt++) {
|
||||
sfa = (*rowa->sort_fields)[cnt];
|
||||
sfb = (*rowb->sort_fields)[cnt];
|
||||
if (sfa->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) {
|
||||
const uint64_t numa =
|
||||
*(const uint64_t *) sfa->sort_value;
|
||||
const uint64_t numb =
|
||||
*(const uint64_t *) sfb->sort_value;
|
||||
|
||||
if (numa == numb)
|
||||
continue;
|
||||
|
||||
if (sfa->props->flags & FLD_ASCENDING) {
|
||||
return (numa > numb) ? 1 : -1;
|
||||
} else { /* FLD_DESCENDING */
|
||||
return (numa < numb) ? 1 : -1;
|
||||
}
|
||||
} else { /* DM_REPORT_FIELD_TYPE_STRING */
|
||||
const char *stra = (const char *) sfa->sort_value;
|
||||
const char *strb = (const char *) sfb->sort_value;
|
||||
int cmp = strcmp(stra, strb);
|
||||
|
||||
if (!cmp)
|
||||
continue;
|
||||
|
||||
if (sfa->props->flags & FLD_ASCENDING) {
|
||||
return (cmp > 0) ? 1 : -1;
|
||||
} else { /* FLD_DESCENDING */
|
||||
return (cmp < 0) ? 1 : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0; /* Identical */
|
||||
}
|
||||
|
||||
static int _sort_rows(struct dm_report *rh)
|
||||
{
|
||||
struct row *(*rows)[];
|
||||
uint32_t count = 0;
|
||||
struct row *row;
|
||||
|
||||
if (!(rows = dm_pool_alloc(rh->mem, sizeof(**rows) *
|
||||
list_size(&rh->rows)))) {
|
||||
log_error("dm_report: sort array allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate_items(row, &rh->rows)
|
||||
(*rows)[count++] = row;
|
||||
|
||||
qsort(rows, count, sizeof(**rows), _row_compare);
|
||||
|
||||
list_init(&rh->rows);
|
||||
while (count--)
|
||||
list_add_h(&rh->rows, &(*rows)[count]->list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Produce report output
|
||||
*/
|
||||
int dm_report_output(struct dm_report *rh)
|
||||
{
|
||||
struct list *fh, *rowh, *ftmp, *rtmp;
|
||||
struct row *row = NULL;
|
||||
struct dm_report_field *field;
|
||||
const char *repstr;
|
||||
char buf[4096];
|
||||
unsigned width;
|
||||
uint32_t align;
|
||||
|
||||
if (list_empty(&rh->rows))
|
||||
return 1;
|
||||
|
||||
/* Sort rows */
|
||||
if ((rh->flags & RH_SORT_REQUIRED))
|
||||
_sort_rows(rh);
|
||||
|
||||
/* If headings not printed yet, calculate field widths and print them */
|
||||
if (!(rh->flags & RH_HEADINGS_PRINTED))
|
||||
_report_headings(rh);
|
||||
|
||||
/* Print and clear buffer */
|
||||
list_iterate_safe(rowh, rtmp, &rh->rows) {
|
||||
if (!dm_pool_begin_object(rh->mem, 512)) {
|
||||
log_error("dm_report: Unable to allocate output line");
|
||||
return 0;
|
||||
}
|
||||
row = list_item(rowh, struct row);
|
||||
list_iterate_safe(fh, ftmp, &row->fields) {
|
||||
field = list_item(fh, struct dm_report_field);
|
||||
if (field->props->flags & FLD_HIDDEN)
|
||||
continue;
|
||||
|
||||
repstr = field->report_string;
|
||||
width = field->props->width;
|
||||
if (!(rh->flags & DM_REPORT_OUTPUT_ALIGNED)) {
|
||||
if (!dm_pool_grow_object(rh->mem, repstr,
|
||||
strlen(repstr))) {
|
||||
log_error("dm_report: Unable to extend output line");
|
||||
goto bad;
|
||||
}
|
||||
} else {
|
||||
if (!(align = field->props->flags & DM_REPORT_FIELD_ALIGN_MASK))
|
||||
align = (field->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ?
|
||||
DM_REPORT_FIELD_ALIGN_RIGHT : DM_REPORT_FIELD_ALIGN_LEFT;
|
||||
if (align & DM_REPORT_FIELD_ALIGN_LEFT) {
|
||||
if (dm_snprintf(buf, sizeof(buf), "%-*.*s",
|
||||
width, width, repstr) < 0) {
|
||||
log_error("dm_report: left-aligned snprintf() failed");
|
||||
goto bad;
|
||||
}
|
||||
if (!dm_pool_grow_object(rh->mem, buf, width)) {
|
||||
log_error("dm_report: Unable to extend output line");
|
||||
goto bad;
|
||||
}
|
||||
} else if (align & DM_REPORT_FIELD_ALIGN_RIGHT) {
|
||||
if (dm_snprintf(buf, sizeof(buf), "%*.*s",
|
||||
width, width, repstr) < 0) {
|
||||
log_error("dm_report: right-aligned snprintf() failed");
|
||||
goto bad;
|
||||
}
|
||||
if (!dm_pool_grow_object(rh->mem, buf, width)) {
|
||||
log_error("dm_report: Unable to extend output line");
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!list_end(&row->fields, fh))
|
||||
if (!dm_pool_grow_object(rh->mem, rh->separator,
|
||||
strlen(rh->separator))) {
|
||||
log_error("dm_report: Unable to extend output line");
|
||||
goto bad;
|
||||
}
|
||||
list_del(&field->list);
|
||||
}
|
||||
if (!dm_pool_grow_object(rh->mem, "\0", 1)) {
|
||||
log_error("dm_report: Unable to terminate output line");
|
||||
goto bad;
|
||||
}
|
||||
log_print("%s", (char *) dm_pool_end_object(rh->mem));
|
||||
list_del(&row->list);
|
||||
}
|
||||
|
||||
if (row)
|
||||
dm_pool_free(rh->mem, row);
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
dm_pool_abandon_object(rh->mem);
|
||||
return 0;
|
||||
}
|
||||
@@ -37,7 +37,8 @@ static int _isword(int c)
|
||||
* Split buffer into NULL-separated words in argv.
|
||||
* Returns number of words.
|
||||
*/
|
||||
int dm_split_words(char *buffer, unsigned max, unsigned ignore_comments,
|
||||
int dm_split_words(char *buffer, unsigned max,
|
||||
unsigned ignore_comments __attribute((unused)),
|
||||
char **argv)
|
||||
{
|
||||
unsigned arg;
|
||||
@@ -121,3 +122,41 @@ int dm_snprintf(char *buf, size_t bufsize, const char *format, ...)
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
char *dm_basename(const char *path)
|
||||
{
|
||||
char *p = strrchr(path, '/');
|
||||
|
||||
return p ? p + 1 : (char *) path;
|
||||
}
|
||||
|
||||
int dm_asprintf(char **result, const char *format, ...)
|
||||
{
|
||||
int n, ok = 0, size = 32;
|
||||
va_list ap;
|
||||
char *buf = dm_malloc(size);
|
||||
|
||||
*result = 0;
|
||||
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
while (!ok) {
|
||||
va_start(ap, format);
|
||||
n = vsnprintf(buf, size, format, ap);
|
||||
if (0 <= n && n < size)
|
||||
ok = 1;
|
||||
else {
|
||||
dm_free(buf);
|
||||
size *= 2;
|
||||
buf = dm_malloc(size);
|
||||
if (!buf)
|
||||
return -1;
|
||||
};
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
*result = dm_strdup(buf);
|
||||
dm_free(buf);
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
@@ -20,9 +20,14 @@
|
||||
|
||||
char *dm_strdup_aux(const char *str, const char *file, int line)
|
||||
{
|
||||
char *ret = dm_malloc_aux_debug(strlen(str) + 1, file, line);
|
||||
char *ret;
|
||||
|
||||
if (ret)
|
||||
if (!str) {
|
||||
log_error("Internal error: dm_strdup called with NULL pointer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((ret = dm_malloc_aux_debug(strlen(str) + 1, file, line)))
|
||||
strcpy(ret, str);
|
||||
|
||||
return ret;
|
||||
@@ -226,7 +231,8 @@ void dm_bounds_check_debug(void)
|
||||
}
|
||||
}
|
||||
|
||||
void *dm_malloc_aux(size_t s, const char *file, int line)
|
||||
void *dm_malloc_aux(size_t s, const char *file __attribute((unused)),
|
||||
int line __attribute((unused)))
|
||||
{
|
||||
if (s > 50000000) {
|
||||
log_error("Huge memory allocation (size %" PRIsize_t
|
||||
|
||||
18
make.tmpl.in
18
make.tmpl.in
@@ -73,6 +73,13 @@ ifeq ("@INTL@", "yes")
|
||||
DEFS += -DINTL_PACKAGE=\"@INTL_PACKAGE@\" -DLOCALEDIR=\"@LOCALEDIR@\"
|
||||
endif
|
||||
|
||||
ifneq ("@DMDIR@", "")
|
||||
LDFLAGS += -L@DMDIR@/lib/ioctl
|
||||
ifeq ("@DMEVENTD@", "yes")
|
||||
LDFLAGS += -L@DMDIR@/dmeventd
|
||||
endif
|
||||
endif
|
||||
|
||||
LDFLAGS += -L$(top_srcdir)/lib -L$(libdir)
|
||||
|
||||
#DEFS += -DDEBUG_POOL
|
||||
@@ -89,6 +96,10 @@ LIB_VERSION := $(shell cat $(top_srcdir)/VERSION | \
|
||||
|
||||
INCLUDES += -I. -I$(top_srcdir)/include
|
||||
|
||||
ifneq ("@DMDIR@", "")
|
||||
INCLUDES += -I@DMDIR@/include
|
||||
endif
|
||||
|
||||
ifdef DESTDIR
|
||||
INCLUDES += -I$(DESTDIR)/usr/include
|
||||
endif
|
||||
@@ -162,18 +173,19 @@ $(TARGETS): $(OBJECTS)
|
||||
ifeq ("@LIB_SUFFIX@","so")
|
||||
$(LIB_SHARED): $(OBJECTS) $(LDDEPS)
|
||||
$(CC) -shared -Wl,-soname,$(notdir $@).$(LIB_VERSION) \
|
||||
$(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
|
||||
$(CFLAGS) $(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
|
||||
endif
|
||||
|
||||
ifeq ("@LIB_SUFFIX@","dylib")
|
||||
$(LIB_SHARED): $(OBJECTS) $(LDDEPS)
|
||||
$(CC) -dynamiclib -dylib_current_version,$(LIB_VERSION) \
|
||||
$(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
|
||||
$(CFLAGS) $(CLDFLAGS) $(OBJECTS) $(LIBS) -o $@
|
||||
endif
|
||||
|
||||
%.so: %.a
|
||||
$(CC) -shared -Wl,-soname,$(notdir $@).$(LIB_VERSION) \
|
||||
$(CLDFLAGS) $(LIBS) -o $@ @CLDWHOLEARCHIVE@ $< @CLDNOWHOLEARCHIVE@
|
||||
$(CFLAGS) $(CLDFLAGS) $(LIBS) -o $@ \
|
||||
@CLDWHOLEARCHIVE@ $< @CLDNOWHOLEARCHIVE@
|
||||
|
||||
$(LIB_STATIC): $(OBJECTS)
|
||||
$(RM) $@
|
||||
|
||||
18
man/clvmd.8
18
man/clvmd.8
@@ -6,6 +6,7 @@ clvmd \- cluster LVM daemon
|
||||
[\-d] [\-h]
|
||||
[\-R]
|
||||
[\-t <timeout>]
|
||||
[\-T <start timeout>]
|
||||
[\-V]
|
||||
.SH DESCRIPTION
|
||||
clvmd is the daemon that distributes LVM metadata updates around a cluster.
|
||||
@@ -23,6 +24,23 @@ be so small that commands with many disk updates to do will fail, so you
|
||||
may need to increase this on systems with very large disk farms.
|
||||
The default is 30 seconds.
|
||||
.TP
|
||||
.I \-T <start timeout>
|
||||
Specifies the timeout for clvmd daemon startup. If the daemon does not report
|
||||
that it has started up within this time then the parent command will exit with
|
||||
status of 5. This does NOT mean that clvmd has not started! What it means is
|
||||
that the startup of clvmd has been delayed for some reason; the most likely
|
||||
cause of this is an inquorate cluster though it could be due to locking
|
||||
latencies on a cluster with large numbers of logical volumes. If you get the
|
||||
return code of 5 it is usually not necessary to restart clvmd - it will start
|
||||
as soon as that blockage has cleared. This flag is to allow startup scripts
|
||||
to exit in a timely fashion even if the cluster is stalled for some reason.
|
||||
<br>
|
||||
The default is 0 (no timeout) and the value is in seconds. Don't set this too
|
||||
small or you will experience spurious errors. 10 or 20 seconds might be
|
||||
sensible.
|
||||
<br>
|
||||
This timeout will be ignored if you start clvmd with the -d switch.
|
||||
.TP
|
||||
.I \-R
|
||||
Tells all the running clvmd in the cluster to reload their device cache and
|
||||
re-read the lvm configuration file. This command should be run whenever the
|
||||
|
||||
@@ -1,20 +1,35 @@
|
||||
.TH LVCONVERT 8 "LVM TOOLS" "Red Hat, Inc" \" -*- nroff -*-
|
||||
.SH NAME
|
||||
lvconvert \- convert a logical volume between linear and mirror
|
||||
lvconvert \- convert a logical volume from linear to mirror or snapshot
|
||||
.SH SYNOPSIS
|
||||
.B lvconvert
|
||||
[\-m/\-\-mirrors Mirrors [\-\-corelog] [\-R/\-\-regionsize MirrorLogRegionSize]]
|
||||
\-m/\-\-mirrors Mirrors [\-\-corelog] [\-R/\-\-regionsize MirrorLogRegionSize]
|
||||
[\-A/\-\-alloc AllocationPolicy]
|
||||
[\-h/\-?/\-\-help]
|
||||
[\-v/\-\-verbose]
|
||||
[\-\-version]
|
||||
.br
|
||||
LogicalVolume[Path] [PhysicalVolume[Path]...]
|
||||
.br
|
||||
|
||||
.br
|
||||
.B lvconvert
|
||||
\-s/\-\-snapshot [\-c/\-\-chunksize ChunkSize]
|
||||
[\-h/\-?/\-\-help]
|
||||
[\-v/\-\-verbose]
|
||||
[\-Z/\-\-zero y/n]
|
||||
[\-\-version]
|
||||
.br
|
||||
OriginalLogicalVolume[Path] SnapshotLogicalVolume[Path]
|
||||
.SH DESCRIPTION
|
||||
lvconvert will change a linear logical volume to a mirror
|
||||
logical volume or vis versa. It is also used to add and
|
||||
remove disk logs from mirror devices.
|
||||
logical volume or to a snapshot of linear volume and vice versa.
|
||||
It is also used to add and remove disk logs from mirror devices.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.br
|
||||
Exactly one of \-\-mirrors or \-\-snapshot arguments required.
|
||||
.br
|
||||
.TP
|
||||
.I \-m, \-\-mirrors Mirrors
|
||||
Specifies the degree of the mirror you wish to create.
|
||||
@@ -32,6 +47,19 @@ the mirror you are changing.
|
||||
.I \-R, \-\-regionsize MirrorLogRegionSize
|
||||
A mirror is divided into regions of this size (in MB), and the mirror log
|
||||
uses this granularity to track which regions are in sync.
|
||||
.br
|
||||
.TP
|
||||
.I \-s, \-\-snapshot
|
||||
Create a snapshot from existing logical volume using another
|
||||
existing logical volume as its origin.
|
||||
.TP
|
||||
.I \-c, \-\-chunksize ChunkSize
|
||||
Power of 2 chunk size for the snapshot logical volume between 4k and 512k.
|
||||
.TP
|
||||
.I \-Z, \-\-zero y/n
|
||||
Controls zeroing of the first KB of data in the snapshot.
|
||||
If the volume is read-only the snapshot will not be zeroed.
|
||||
.br
|
||||
.SH Examples
|
||||
"lvconvert -m1 vg00/lvol1"
|
||||
.br
|
||||
@@ -49,6 +77,12 @@ two-way mirror with an in-memory log.
|
||||
.br
|
||||
converts a mirror logical volume to a linear logical
|
||||
volume.
|
||||
.br
|
||||
|
||||
.br
|
||||
"lvconvert -s vg00/lvol1 vg00/lvol2"
|
||||
.br
|
||||
converts logical volume "vg00/lvol2" to snapshot of original volume "vg00/lvol1"
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR lvm (8),
|
||||
|
||||
@@ -139,6 +139,10 @@ on the snapshot in order to check how much data is allocated to it.
|
||||
Controls zeroing of the first KB of data in the new logical volume.
|
||||
.br
|
||||
Default is yes.
|
||||
.br
|
||||
Volume will not be zeroed if read only flag is set.
|
||||
.br
|
||||
Snapshot volumes are zeroed always.
|
||||
|
||||
.br
|
||||
Warning: trying to mount an unzeroed logical volume can cause the system to
|
||||
|
||||
@@ -31,7 +31,7 @@ size of the Logical Volume with the suffix %LV or as a percentage of the remaini
|
||||
free space in the Volume Group with the suffix %FREE.
|
||||
.TP
|
||||
.I \-L, \-\-size [+]LogicalVolumeSize[kKmMgGtTpPeE]
|
||||
Extend or set the logical volume size in units in units of megabytes.
|
||||
Extend or set the logical volume size in units of megabytes.
|
||||
A size suffix of M for megabytes,
|
||||
G for gigabytes, T for terabytes, P for petabytes
|
||||
or E for exabytes is optional.
|
||||
|
||||
@@ -35,11 +35,13 @@ lv_uuid, lv_name, lv_attr, lv_major, lv_minor, lv_kernel_major, lv_kernel_minor,
|
||||
lv_size, seg_count, origin, snap_percent,
|
||||
copy_percent, move_pv, lv_tags,
|
||||
segtype, stripes,
|
||||
stripesize, chunksize, seg_start, seg_size, seg_tags, devices.
|
||||
stripesize, chunksize, seg_start, seg_size, seg_tags, devices,
|
||||
regionsize, mirror_log, modules.
|
||||
.IP
|
||||
With \-\-segments, any "seg_" prefixes are optional; otherwise any "lv_"
|
||||
prefixes are optional. Columns mentioned in \fBvgs (8)\fP
|
||||
can also be chosen.
|
||||
Use \fb-o help\fP to view the full list of fields available.
|
||||
.IP
|
||||
The lv_attr bits are:
|
||||
.RS
|
||||
|
||||
11
man/pvs.8
11
man/pvs.8
@@ -31,9 +31,16 @@ if processing the output.
|
||||
Comma-separated ordered list of columns. Precede the list with '+' to append
|
||||
to the default selection of columns. Column names are: pv_fmt, pv_uuid,
|
||||
pv_size, dev_size, pv_free, pv_used, pv_name, pv_attr, pv_pe_count,
|
||||
pv_pe_alloc_count, pv_tags.
|
||||
The "pv_" prefix is optional. Columns mentioned in \fBvgs (8)\fP can also
|
||||
pv_pe_alloc_count, pv_tags, pvseg_start, pvseg_size, pe_start.
|
||||
With --segments, any "pvseg_" prefixes are optional; otherwise any
|
||||
"pv_" prefixes are optional. Columns mentioned in \fBvgs (8)\fP can also
|
||||
be chosen. The pv_attr bits are: (a)llocatable and e(x)ported.
|
||||
Use \fb-o help\fP to view the full list of fields available.
|
||||
.TP
|
||||
.I \-\-segments
|
||||
Produces one line of output for each contiguous allocation of space on each
|
||||
Physical Volume, showing the start (pvseg_start) and length (pvseg_size) in
|
||||
units of physical extents.
|
||||
.TP
|
||||
.I \-O, \-\-sort
|
||||
Comma-separated ordered list of columns to sort by. Replaces the default
|
||||
|
||||
@@ -10,6 +10,7 @@ vgchange \- change attributes of a volume group
|
||||
.RB [ \-A | \-\-autobackup " {" y | n }]
|
||||
.RB [ \-a | \-\-available " [e|l] {" y | n }]
|
||||
.RB [ \-\-monitor " {" y | n }]
|
||||
.RB [ \-c | \-\-clustered " {" y | n }]
|
||||
.RB [ \-d | \-\-debug]
|
||||
.RB [ \-\-deltag
|
||||
.IR Tag ]
|
||||
@@ -44,12 +45,12 @@ snapshots should be removed (see
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.BR \-A ", " \-\-autobackup { y | n }
|
||||
.BR \-A ", " \-\-autobackup " " { y | n }
|
||||
Controls automatic backup of metadata after the change. See
|
||||
.B vgcfgbackup (8).
|
||||
Default is yes.
|
||||
.TP
|
||||
.BR \-a ", " \-\-available [e|l] { y | n }
|
||||
.BR \-a ", " \-\-available " " [e|l] { y | n }
|
||||
Controls the availability of the logical volumes in the volume
|
||||
group for input/output.
|
||||
In other words, makes the logical volumes known/unknown to the kernel.
|
||||
@@ -60,6 +61,14 @@ on the local node.
|
||||
Logical volumes with single-host snapshots are always activated
|
||||
exclusively because they can only be used on one node at once.
|
||||
.TP
|
||||
.BR \-c ", " \-\-clustered " " { y | n }
|
||||
If clustered locking is enabled, this indicates whether this
|
||||
Volume Group is shared with other nodes in the cluster or whether
|
||||
it contains only local disks that are not visible on the other nodes.
|
||||
If the cluster infrastructure is unavailable on a particular node at a
|
||||
particular time, you may still be able to use Volume Groups that
|
||||
are not marked as clustered.
|
||||
.TP
|
||||
.BR \-\-monitor " " { y | n }
|
||||
Controls whether or not a mirrored logical volume is monitored by
|
||||
dmeventd, if it is installed.
|
||||
@@ -108,7 +117,7 @@ impact on I/O performance to the logical volume. The smallest PE is 1KB.
|
||||
|
||||
The 2.4 kernel has a limitation of 2TB per block device.
|
||||
.TP
|
||||
.BR \-x ", " \-\-resizeable { y | n }
|
||||
.BR \-x ", " \-\-resizeable " " { y | n }
|
||||
Enables or disables the extension/reduction of this volume group
|
||||
with/by physical volumes.
|
||||
.SH EXAMPLES
|
||||
|
||||
@@ -8,6 +8,7 @@ vgcreate \- create a volume group
|
||||
.RB [ \-\-alloc
|
||||
.IR AllocationPolicy ]
|
||||
.RB [ \-A | \-\-autobackup " {" y | n }]
|
||||
.RB [ \-c | \-\-clustered " {" y | n }]
|
||||
.RB [ \-d | \-\-debug ]
|
||||
.RB [ \-h | \-\-help ]
|
||||
.RB [ \-l | \-\-maxlogicalvolumes
|
||||
@@ -33,6 +34,14 @@ previously configured for LVM with
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.BR \-c ", " \-\-clustered " " { y | n }
|
||||
If clustered locking is enabled, this indicates whether this
|
||||
Volume Group is shared with other nodes in the cluster or whether
|
||||
it contains only local disks that are not visible on the other nodes.
|
||||
If the cluster infrastructure is unavailable on a particular node at a
|
||||
particular time, you may still be able to use Volume Groups that
|
||||
are not marked as clustered.
|
||||
.TP
|
||||
.BR \-l ", " \-\-maxlogicalvolumes " " \fIMaxLogicalVolumes\fR
|
||||
Sets the maximum number of logical volumes allowed in this
|
||||
volume group.
|
||||
|
||||
@@ -38,6 +38,7 @@ Any "vg_" prefixes are optional. Columns mentioned in either \fBpvs (8)\fP
|
||||
or \fBlvs (8)\fP can also be chosen, but columns cannot be taken from both
|
||||
at the same time. The vg_attr bits are: (w)riteable, (r)eadonly,
|
||||
resi(z)eable, e(x)ported, (p)artial and (c)lustered.
|
||||
Use \fb-o help\fP to view the full list of fields available.
|
||||
.TP
|
||||
.I \-O, \-\-sort
|
||||
Comma-separated ordered list of columns to sort by. Replaces the default
|
||||
|
||||
@@ -15,6 +15,7 @@ VGCHANGE="/usr/sbin/vgchange"
|
||||
VGSCAN="/usr/sbin/vgscan"
|
||||
VGDISPLAY="/usr/sbin/vgdisplay"
|
||||
VGS="/usr/sbin/vgs"
|
||||
CLVMDOPTS="-T20"
|
||||
|
||||
[ -f /etc/sysconfig/cluster ] && . /etc/sysconfig/cluster
|
||||
|
||||
@@ -27,7 +28,7 @@ start()
|
||||
if ! pidof clvmd > /dev/null
|
||||
then
|
||||
echo -n "Starting clvmd: "
|
||||
daemon clvmd
|
||||
daemon clvmd $CLVMDOPTS
|
||||
rtrn=$?
|
||||
echo
|
||||
if [ $rtrn -ne 0 ]
|
||||
|
||||
98
scripts/lvm2_monitoring_init_rhel4
Normal file
98
scripts/lvm2_monitoring_init_rhel4
Normal file
@@ -0,0 +1,98 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2007 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# This file is part of LVM2.
|
||||
# It is required for the proper handling of failures of LVM2 mirror
|
||||
# devices that were created using the -m option of lvcreate.
|
||||
#
|
||||
#
|
||||
# chkconfig: 12345 02 99
|
||||
# description: Starts and stops dmeventd monitoring for lvm2
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides:
|
||||
### END INIT INFO
|
||||
|
||||
. /etc/init.d/functions
|
||||
|
||||
VGCHANGE="/usr/sbin/vgchange"
|
||||
|
||||
start()
|
||||
{
|
||||
for ret in 0
|
||||
do
|
||||
# TODO do we want to separate out already active groups only?
|
||||
VGS=`vgs --noheadings -o name`
|
||||
for vg in $VGS
|
||||
do
|
||||
if ! action "Starting monitoring for VG $vg:" $VGCHANGE --monitor y $vg
|
||||
then
|
||||
ret=$?
|
||||
fi
|
||||
done
|
||||
|
||||
done
|
||||
|
||||
return $ret
|
||||
}
|
||||
|
||||
|
||||
stop()
|
||||
{
|
||||
for ret in 0
|
||||
do
|
||||
# TODO do we want to separate out already active groups only?
|
||||
VGS=`vgs --noheadings -o name`
|
||||
for vg in $VGS
|
||||
do
|
||||
if ! action "Starting monitoring for VG $vg:" $VGCHANGE --monitor n $vg
|
||||
then
|
||||
ret=$?
|
||||
fi
|
||||
done
|
||||
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
ret=1
|
||||
|
||||
# See how we were called.
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
ret=$?
|
||||
;;
|
||||
|
||||
stop)
|
||||
stop
|
||||
ret=$?
|
||||
;;
|
||||
|
||||
restart)
|
||||
if stop
|
||||
then
|
||||
start
|
||||
fi
|
||||
ret=$?
|
||||
;;
|
||||
|
||||
status)
|
||||
# TODO anyone with an idea how to dump monitored volumes?
|
||||
;;
|
||||
|
||||
*)
|
||||
echo $"Usage: $0 {start|stop|restart|status}"
|
||||
;;
|
||||
esac
|
||||
|
||||
exit $ret
|
||||
@@ -101,11 +101,12 @@ DEFS += -DLVM_SHARED_PATH=\"$(exec_prefix)/sbin/lvm\"
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
lvm: $(OBJECTS) lvm.o $(top_srcdir)/lib/liblvm.a
|
||||
$(CC) -o $@ $(OBJECTS) lvm.o $(LDFLAGS) $(LVMLIBS) $(LIBS) -rdynamic
|
||||
$(CC) -o $@ $(CFLAGS) $(OBJECTS) lvm.o \
|
||||
$(LDFLAGS) $(LVMLIBS) $(LIBS) -rdynamic
|
||||
|
||||
lvm.static: $(OBJECTS) lvm-static.o $(top_srcdir)/lib/liblvm.a
|
||||
$(CC) -o $@ $(OBJECTS) lvm-static.o -static $(LDFLAGS) $(LVMLIBS) \
|
||||
$(LIBS) -rdynamic
|
||||
$(CC) -o $@ $(CFLAGS) $(OBJECTS) lvm-static.o -static \
|
||||
$(LDFLAGS) $(LVMLIBS) $(LIBS) -rdynamic
|
||||
|
||||
liblvm2cmd.a: $(top_srcdir)/lib/liblvm.a $(OBJECTS) lvmcmdlib.o lvm2cmd.o
|
||||
cat $(top_srcdir)/lib/liblvm.a > $@
|
||||
|
||||
@@ -30,7 +30,10 @@ xx(e2fsadm,
|
||||
|
||||
xx(dumpconfig,
|
||||
"Dump active configuration",
|
||||
"dumpconfig <filename>\n")
|
||||
"dumpconfig "
|
||||
"\t[-f|--file filename] " "\n"
|
||||
"[ConfigurationVariable...]\n",
|
||||
file_ARG)
|
||||
|
||||
xx(formats,
|
||||
"List available metadata formats",
|
||||
@@ -654,7 +657,7 @@ xx(vgcreate,
|
||||
"\t[-A|--autobackup {y|n}] " "\n"
|
||||
"\t[--addtag Tag] " "\n"
|
||||
"\t[--alloc AllocationPolicy] " "\n"
|
||||
"\t[-c|--clustered] " "\n"
|
||||
"\t[-c|--clustered {y|n}] " "\n"
|
||||
"\t[-d|--debug]" "\n"
|
||||
"\t[-h|--help]" "\n"
|
||||
"\t[-l|--maxlogicalvolumes MaxLogicalVolumes]" "\n"
|
||||
|
||||
378
tools/dmsetup.c
378
tools/dmsetup.c
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2005 NEC Corperation
|
||||
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2005-2007 NEC Corperation
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
@@ -114,7 +114,9 @@ enum {
|
||||
NOOPENCOUNT_ARG,
|
||||
NOTABLE_ARG,
|
||||
OPTIONS_ARG,
|
||||
SEPARATOR_ARG,
|
||||
SHOWKEYS_ARG,
|
||||
SORT_ARG,
|
||||
TABLE_ARG,
|
||||
TARGET_ARG,
|
||||
TREE_ARG,
|
||||
@@ -126,18 +128,30 @@ enum {
|
||||
};
|
||||
|
||||
static int _switches[NUM_SWITCHES];
|
||||
static int _values[NUM_SWITCHES];
|
||||
static int _int_args[NUM_SWITCHES];
|
||||
static char *_string_args[NUM_SWITCHES];
|
||||
static int _num_devices;
|
||||
static char *_uuid;
|
||||
static char *_fields;
|
||||
static char *_table;
|
||||
static char *_target;
|
||||
static char *_command;
|
||||
static struct dm_tree *_dtree;
|
||||
static struct dm_report *_report;
|
||||
|
||||
/*
|
||||
* Commands
|
||||
*/
|
||||
|
||||
typedef int (*command_fn) (int argc, char **argv, void *data);
|
||||
|
||||
struct command {
|
||||
const char *name;
|
||||
const char *help;
|
||||
int min_args;
|
||||
int max_args;
|
||||
command_fn fn;
|
||||
};
|
||||
|
||||
static int _parse_line(struct dm_task *dmt, char *buffer, const char *file,
|
||||
int line)
|
||||
{
|
||||
@@ -217,71 +231,33 @@ static int _parse_file(struct dm_task *dmt, const char *file)
|
||||
#else
|
||||
free(buffer);
|
||||
#endif
|
||||
if (file)
|
||||
fclose(fp);
|
||||
if (file && fclose(fp))
|
||||
fprintf(stderr, "%s: fclose failed: %s", file, strerror(errno));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void _display_info_cols_noheadings(struct dm_task *dmt,
|
||||
struct dm_info *info)
|
||||
struct dmsetup_report_obj {
|
||||
struct dm_task *task;
|
||||
struct dm_info *info;
|
||||
};
|
||||
|
||||
static int _display_info_cols(struct dm_task *dmt, struct dm_info *info)
|
||||
{
|
||||
const char *uuid;
|
||||
|
||||
if (!info->exists)
|
||||
return;
|
||||
|
||||
uuid = dm_task_get_uuid(dmt);
|
||||
|
||||
if (_switches[OPTIONS_ARG])
|
||||
printf("%s\n", dm_task_get_name(dmt));
|
||||
else
|
||||
printf("%s:%d:%d:%s%s%s%s:%d:%d:%" PRIu32 ":%s\n",
|
||||
dm_task_get_name(dmt),
|
||||
info->major, info->minor,
|
||||
info->live_table ? "L" : "-",
|
||||
info->inactive_table ? "I" : "-",
|
||||
info->suspended ? "s" : "-",
|
||||
info->read_only ? "r" : "w",
|
||||
info->open_count, info->target_count, info->event_nr,
|
||||
uuid && *uuid ? uuid : "");
|
||||
}
|
||||
|
||||
static void _display_info_cols(struct dm_task *dmt, struct dm_info *info)
|
||||
{
|
||||
static int _headings = 0;
|
||||
const char *uuid;
|
||||
struct dmsetup_report_obj obj;
|
||||
|
||||
if (!info->exists) {
|
||||
printf("Device does not exist.\n");
|
||||
return;
|
||||
fprintf(stderr, "Device does not exist.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_headings) {
|
||||
if (_switches[OPTIONS_ARG])
|
||||
printf("Name\n");
|
||||
else
|
||||
printf("Name Maj Min Stat Open Targ "
|
||||
"Event UUID\n");
|
||||
_headings = 1;
|
||||
}
|
||||
obj.task = dmt;
|
||||
obj.info = info;
|
||||
|
||||
if (_switches[OPTIONS_ARG])
|
||||
printf("%s\n", dm_task_get_name(dmt));
|
||||
else {
|
||||
printf("%-16s %3d %3d %s%s%s%s %4d %4d %6" PRIu32 " ",
|
||||
dm_task_get_name(dmt),
|
||||
info->major, info->minor,
|
||||
info->live_table ? "L" : "-",
|
||||
info->inactive_table ? "I" : "-",
|
||||
info->suspended ? "s" : "-",
|
||||
info->read_only ? "r" : "w",
|
||||
info->open_count, info->target_count, info->event_nr);
|
||||
if (!dm_report_object(_report, &obj))
|
||||
return 0;
|
||||
|
||||
if ((uuid = dm_task_get_uuid(dmt)) && *uuid)
|
||||
printf("%s", uuid);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _display_info_long(struct dm_task *dmt, struct dm_info *info)
|
||||
@@ -331,9 +307,8 @@ static int _display_info(struct dm_task *dmt)
|
||||
|
||||
if (!_switches[COLS_ARG])
|
||||
_display_info_long(dmt, &info);
|
||||
else if (_switches[NOHEADINGS_ARG])
|
||||
_display_info_cols_noheadings(dmt, &info);
|
||||
else
|
||||
/* FIXME return code */
|
||||
_display_info_cols(dmt, &info);
|
||||
|
||||
return info.exists ? 1 : 0;
|
||||
@@ -348,8 +323,8 @@ static int _set_task_device(struct dm_task *dmt, const char *name, int optional)
|
||||
if (!dm_task_set_uuid(dmt, _uuid))
|
||||
return 0;
|
||||
} else if (_switches[MAJOR_ARG] && _switches[MINOR_ARG]) {
|
||||
if (!dm_task_set_major(dmt, _values[MAJOR_ARG]) ||
|
||||
!dm_task_set_minor(dmt, _values[MINOR_ARG]))
|
||||
if (!dm_task_set_major(dmt, _int_args[MAJOR_ARG]) ||
|
||||
!dm_task_set_minor(dmt, _int_args[MINOR_ARG]))
|
||||
return 0;
|
||||
} else if (!optional) {
|
||||
fprintf(stderr, "No device specified.\n");
|
||||
@@ -440,19 +415,19 @@ static int _create(int argc, char **argv, void *data __attribute((unused)))
|
||||
if (_switches[READ_ONLY] && !dm_task_set_ro(dmt))
|
||||
goto out;
|
||||
|
||||
if (_switches[MAJOR_ARG] && !dm_task_set_major(dmt, _values[MAJOR_ARG]))
|
||||
if (_switches[MAJOR_ARG] && !dm_task_set_major(dmt, _int_args[MAJOR_ARG]))
|
||||
goto out;
|
||||
|
||||
if (_switches[MINOR_ARG] && !dm_task_set_minor(dmt, _values[MINOR_ARG]))
|
||||
if (_switches[MINOR_ARG] && !dm_task_set_minor(dmt, _int_args[MINOR_ARG]))
|
||||
goto out;
|
||||
|
||||
if (_switches[UID_ARG] && !dm_task_set_uid(dmt, _values[UID_ARG]))
|
||||
if (_switches[UID_ARG] && !dm_task_set_uid(dmt, _int_args[UID_ARG]))
|
||||
goto out;
|
||||
|
||||
if (_switches[GID_ARG] && !dm_task_set_gid(dmt, _values[GID_ARG]))
|
||||
if (_switches[GID_ARG] && !dm_task_set_gid(dmt, _int_args[GID_ARG]))
|
||||
goto out;
|
||||
|
||||
if (_switches[MODE_ARG] && !dm_task_set_mode(dmt, _values[MODE_ARG]))
|
||||
if (_switches[MODE_ARG] && !dm_task_set_mode(dmt, _int_args[MODE_ARG]))
|
||||
goto out;
|
||||
|
||||
if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
|
||||
@@ -533,7 +508,11 @@ static int _message(int argc, char **argv, void *data __attribute((unused)))
|
||||
for (i = 0; i < argc; i++)
|
||||
sz += strlen(argv[i]) + 1;
|
||||
|
||||
str = dm_malloc(sz);
|
||||
if (!(str = dm_malloc(sz))) {
|
||||
err("message string allocation failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(str, 0, sz);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
@@ -1492,6 +1471,194 @@ static int _tree(int argc, char **argv, void *data __attribute((unused)))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Report device information
|
||||
*/
|
||||
|
||||
/* dm specific display functions */
|
||||
|
||||
static int _int32_disp(struct dm_report *rh,
|
||||
struct dm_pool *mem __attribute((unused)),
|
||||
struct dm_report_field *field, const void *data,
|
||||
void *private __attribute((unused)))
|
||||
{
|
||||
const int32_t value = *(const int32_t *)data;
|
||||
|
||||
return dm_report_field_int32(rh, field, &value);
|
||||
}
|
||||
|
||||
static int _uint32_disp(struct dm_report *rh,
|
||||
struct dm_pool *mem __attribute((unused)),
|
||||
struct dm_report_field *field, const void *data,
|
||||
void *private __attribute((unused)))
|
||||
{
|
||||
const uint32_t value = *(const int32_t *)data;
|
||||
|
||||
return dm_report_field_uint32(rh, field, &value);
|
||||
}
|
||||
|
||||
static int _dm_name_disp(struct dm_report *rh,
|
||||
struct dm_pool *mem __attribute((unused)),
|
||||
struct dm_report_field *field, const void *data,
|
||||
void *private __attribute((unused)))
|
||||
{
|
||||
const char *name = dm_task_get_name((struct dm_task *) data);
|
||||
|
||||
return dm_report_field_string(rh, field, &name);
|
||||
}
|
||||
|
||||
static int _dm_uuid_disp(struct dm_report *rh,
|
||||
struct dm_pool *mem __attribute((unused)),
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute((unused)))
|
||||
{
|
||||
const char *uuid = dm_task_get_uuid((struct dm_task *) data);
|
||||
|
||||
if (!uuid || !*uuid)
|
||||
uuid = "";
|
||||
|
||||
return dm_report_field_string(rh, field, &uuid);
|
||||
}
|
||||
|
||||
static int _dm_info_status_disp(struct dm_report *rh,
|
||||
struct dm_pool *mem __attribute((unused)),
|
||||
struct dm_report_field *field, const void *data,
|
||||
void *private __attribute((unused)))
|
||||
{
|
||||
char buf[5];
|
||||
const char *s = buf;
|
||||
struct dm_info *info = (struct dm_info *) data;
|
||||
|
||||
buf[0] = info->live_table ? 'L' : '-';
|
||||
buf[1] = info->inactive_table ? 'I' : '-';
|
||||
buf[2] = info->suspended ? 's' : '-';
|
||||
buf[3] = info->read_only ? 'r' : 'w';
|
||||
buf[4] = '\0';
|
||||
|
||||
return dm_report_field_string(rh, field, &s);
|
||||
}
|
||||
|
||||
/* Report types */
|
||||
enum { DR_TASK = 1, DR_INFO = 2 };
|
||||
|
||||
static void *_task_get_obj(void *obj)
|
||||
{
|
||||
return ((struct dmsetup_report_obj *)obj)->task;
|
||||
}
|
||||
|
||||
static void *_info_get_obj(void *obj)
|
||||
{
|
||||
return ((struct dmsetup_report_obj *)obj)->info;
|
||||
}
|
||||
|
||||
static const struct dm_report_object_type _report_types[] = {
|
||||
{ DR_TASK, "Mapped Device Name", "", _task_get_obj },
|
||||
{ DR_INFO, "Mapped Device Information", "", _info_get_obj },
|
||||
{ 0, "", "", NULL },
|
||||
};
|
||||
|
||||
/* Column definitions */
|
||||
#define OFFSET_OF(strct, field) ((unsigned int) &((struct strct *)NULL)->field)
|
||||
#define STR (DM_REPORT_FIELD_TYPE_STRING)
|
||||
#define NUM (DM_REPORT_FIELD_TYPE_NUMBER)
|
||||
#define FIELD_O(type, strct, sorttype, head, field, width, func, id, desc) {DR_ ## type, id, OFFSET_OF(strct, field), head, width, sorttype, &_ ## func ## _disp, desc},
|
||||
#define FIELD_F(type, sorttype, head, width, func, id, desc) {DR_ ## type, id, 0, head, width, sorttype, &_ ## func ## _disp, desc},
|
||||
|
||||
static const struct dm_report_field_type _report_fields[] = {
|
||||
/* *INDENT-OFF* */
|
||||
FIELD_F(TASK, STR, "Name", 16, dm_name, "name", "Name of mapped device.")
|
||||
FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid", "Unique identifier for mapped device (optional).")
|
||||
FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "status", "Attributes.")
|
||||
FIELD_O(INFO, dm_info, NUM, "Maj", major, 3, int32, "major", "Major number.")
|
||||
FIELD_O(INFO, dm_info, NUM, "Min", minor, 3, int32, "minor", "Minor number.")
|
||||
FIELD_O(INFO, dm_info, NUM, "Open", open_count, 4, int32, "open_count", "Number of references to open device, if requested.")
|
||||
FIELD_O(INFO, dm_info, NUM, "Targ", target_count, 4, int32, "target_count", "Number of segments in live table, if present.")
|
||||
FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "event_nr", "Current event number.")
|
||||
{0, "", 0, "", 0, 0, NULL, NULL},
|
||||
/* *INDENT-ON* */
|
||||
};
|
||||
|
||||
#undef STR
|
||||
#undef NUM
|
||||
#undef FIELD_O
|
||||
#undef FIELD_F
|
||||
|
||||
static const char *default_report_options = "name,major,minor,status,open_count,target_count,event_nr,uuid";
|
||||
|
||||
static int _report_init(struct command *c)
|
||||
{
|
||||
char *options = (char *) default_report_options;
|
||||
const char *keys = "";
|
||||
const char *separator = " ";
|
||||
int aligned = 1, headings = 1, buffered = 0;
|
||||
uint32_t report_type = 0;
|
||||
uint32_t flags = 0;
|
||||
size_t len = 0;
|
||||
int r = 0;
|
||||
|
||||
/* emulate old dmsetup behaviour */
|
||||
if (_switches[NOHEADINGS_ARG]) {
|
||||
separator = ":";
|
||||
aligned = 0;
|
||||
headings = 0;
|
||||
}
|
||||
|
||||
if (_switches[OPTIONS_ARG] && _string_args[OPTIONS_ARG]) {
|
||||
if (*_string_args[OPTIONS_ARG] != '+')
|
||||
options = _string_args[OPTIONS_ARG];
|
||||
else {
|
||||
len = strlen(default_report_options) +
|
||||
strlen(_string_args[OPTIONS_ARG]) + 1;
|
||||
if (!(options = dm_malloc(len))) {
|
||||
err("Failed to allocate option string.");
|
||||
return 0;
|
||||
}
|
||||
if (dm_snprintf(options, len, "%s,%s",
|
||||
default_report_options,
|
||||
&_string_args[OPTIONS_ARG][1]) < 0) {
|
||||
err("snprintf failed");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_switches[SORT_ARG] && _string_args[SORT_ARG]) {
|
||||
keys = _string_args[SORT_ARG];
|
||||
buffered = 1;
|
||||
if (!strcmp(c->name, "status") || !strcmp(c->name, "table")) {
|
||||
err("--sort is not yet supported with status and table");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (_switches[SEPARATOR_ARG] && _string_args[SEPARATOR_ARG]) {
|
||||
separator = _string_args[SEPARATOR_ARG];
|
||||
aligned = 0;
|
||||
}
|
||||
|
||||
if (aligned)
|
||||
flags |= DM_REPORT_OUTPUT_ALIGNED;
|
||||
|
||||
if (buffered)
|
||||
flags |= DM_REPORT_OUTPUT_BUFFERED;
|
||||
|
||||
if (headings)
|
||||
flags |= DM_REPORT_OUTPUT_HEADINGS;
|
||||
|
||||
if (!(_report = dm_report_init(&report_type,
|
||||
_report_types, _report_fields,
|
||||
options, separator, flags, keys, NULL)))
|
||||
goto out;
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
if (len)
|
||||
dm_free(options);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* List devices
|
||||
*/
|
||||
@@ -1507,18 +1674,8 @@ static int _ls(int argc, char **argv, void *data)
|
||||
}
|
||||
|
||||
/*
|
||||
* dispatch table
|
||||
* Dispatch table
|
||||
*/
|
||||
typedef int (*command_fn) (int argc, char **argv, void *data);
|
||||
|
||||
struct command {
|
||||
const char *name;
|
||||
const char *help;
|
||||
int min_args;
|
||||
int max_args;
|
||||
command_fn fn;
|
||||
};
|
||||
|
||||
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"
|
||||
@@ -1669,7 +1826,7 @@ static char *parse_loop_device_name(char *dev)
|
||||
char *buf;
|
||||
char *device;
|
||||
|
||||
if (!(buf = dm_malloc(PATH_MAX)));
|
||||
if (!(buf = dm_malloc(PATH_MAX)))
|
||||
return NULL;
|
||||
|
||||
if (dev[0] == '/') {
|
||||
@@ -1699,7 +1856,8 @@ error:
|
||||
/*
|
||||
* create a table for a mapped device using the loop target.
|
||||
*/
|
||||
static int _loop_table(char *table, size_t tlen, char *file, char *dev, off_t off)
|
||||
static int _loop_table(char *table, size_t tlen, char *file,
|
||||
char *dev __attribute((unused)), off_t off)
|
||||
{
|
||||
struct stat fbuf;
|
||||
off_t size, sectors;
|
||||
@@ -1732,7 +1890,7 @@ static int _loop_table(char *table, size_t tlen, char *file, char *dev, off_t of
|
||||
|
||||
#ifdef HAVE_SYS_STATVFS_H
|
||||
if (fstatvfs(fd, &fsbuf))
|
||||
goto error;
|
||||
goto error;
|
||||
|
||||
/* FIXME Fragment size currently unused */
|
||||
blksize = fsbuf.f_frsize;
|
||||
@@ -1740,7 +1898,7 @@ static int _loop_table(char *table, size_t tlen, char *file, char *dev, off_t of
|
||||
|
||||
close(fd);
|
||||
|
||||
if (dm_snprintf(table, tlen, "%llu %llu loop %s %llu\n", 0ULL,
|
||||
if (dm_snprintf(table, tlen, "%llu %llu loop %s %llu\n", 0ULL,
|
||||
(long long unsigned)sectors, file, off) < 0)
|
||||
return 0;
|
||||
|
||||
@@ -1884,7 +2042,9 @@ static int _process_switches(int *argc, char ***argv)
|
||||
{"noopencount", 0, &ind, NOOPENCOUNT_ARG},
|
||||
{"notable", 0, &ind, NOTABLE_ARG},
|
||||
{"options", 1, &ind, OPTIONS_ARG},
|
||||
{"separator", 1, &ind, SEPARATOR_ARG},
|
||||
{"showkeys", 0, &ind, SHOWKEYS_ARG},
|
||||
{"sort", 1, &ind, SORT_ARG},
|
||||
{"table", 1, &ind, TABLE_ARG},
|
||||
{"target", 1, &ind, TARGET_ARG},
|
||||
{"tree", 0, &ind, TREE_ARG},
|
||||
@@ -1902,7 +2062,7 @@ static int _process_switches(int *argc, char ***argv)
|
||||
* Zero all the index counts.
|
||||
*/
|
||||
memset(&_switches, 0, sizeof(_switches));
|
||||
memset(&_values, 0, sizeof(_values));
|
||||
memset(&_int_args, 0, sizeof(_int_args));
|
||||
|
||||
namebase = strdup((*argv)[0]);
|
||||
base = basename(namebase);
|
||||
@@ -1914,17 +2074,17 @@ static int _process_switches(int *argc, char ***argv)
|
||||
_switches[OPTIONS_ARG]++;
|
||||
_switches[MAJOR_ARG]++;
|
||||
_switches[MINOR_ARG]++;
|
||||
_fields = (char *) "name";
|
||||
_string_args[OPTIONS_ARG] = (char *) "name";
|
||||
|
||||
if (*argc == 3) {
|
||||
_values[MAJOR_ARG] = atoi((*argv)[1]);
|
||||
_values[MINOR_ARG] = atoi((*argv)[2]);
|
||||
_int_args[MAJOR_ARG] = atoi((*argv)[1]);
|
||||
_int_args[MINOR_ARG] = atoi((*argv)[2]);
|
||||
*argc -= 2;
|
||||
*argv += 2;
|
||||
} else if ((*argc == 2) &&
|
||||
(2 == sscanf((*argv)[1], "%i:%i",
|
||||
&_values[MAJOR_ARG],
|
||||
&_values[MINOR_ARG]))) {
|
||||
&_int_args[MAJOR_ARG],
|
||||
&_int_args[MINOR_ARG]))) {
|
||||
*argc -= 1;
|
||||
*argv += 1;
|
||||
} else {
|
||||
@@ -1946,7 +2106,7 @@ static int _process_switches(int *argc, char ***argv)
|
||||
|
||||
optarg = 0;
|
||||
optind = OPTIND_INIT;
|
||||
while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfGj:m:Mno:ru:Uv",
|
||||
while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfGj:m:Mno:O:ru:Uv",
|
||||
long_options, NULL)) != -1) {
|
||||
if (c == ':' || c == '?')
|
||||
return 0;
|
||||
@@ -1958,17 +2118,25 @@ static int _process_switches(int *argc, char ***argv)
|
||||
_switches[READ_ONLY]++;
|
||||
if (c == 'j' || ind == MAJOR_ARG) {
|
||||
_switches[MAJOR_ARG]++;
|
||||
_values[MAJOR_ARG] = atoi(optarg);
|
||||
_int_args[MAJOR_ARG] = atoi(optarg);
|
||||
}
|
||||
if (c == 'm' || ind == MINOR_ARG) {
|
||||
_switches[MINOR_ARG]++;
|
||||
_values[MINOR_ARG] = atoi(optarg);
|
||||
_int_args[MINOR_ARG] = atoi(optarg);
|
||||
}
|
||||
if (c == 'n' || ind == NOTABLE_ARG)
|
||||
_switches[NOTABLE_ARG]++;
|
||||
if (c == 'o' || ind == OPTIONS_ARG) {
|
||||
_switches[OPTIONS_ARG]++;
|
||||
_fields = optarg;
|
||||
_string_args[OPTIONS_ARG] = optarg;
|
||||
}
|
||||
if (ind == SEPARATOR_ARG) {
|
||||
_switches[SEPARATOR_ARG]++;
|
||||
_string_args[SEPARATOR_ARG] = optarg;
|
||||
}
|
||||
if (c == 'O' || ind == SORT_ARG) {
|
||||
_switches[SORT_ARG]++;
|
||||
_string_args[SORT_ARG] = optarg;
|
||||
}
|
||||
if (c == 'v' || ind == VERBOSE_ARG)
|
||||
_switches[VERBOSE_ARG]++;
|
||||
@@ -1978,16 +2146,16 @@ static int _process_switches(int *argc, char ***argv)
|
||||
}
|
||||
if (c == 'G' || ind == GID_ARG) {
|
||||
_switches[GID_ARG]++;
|
||||
_values[GID_ARG] = atoi(optarg);
|
||||
_int_args[GID_ARG] = atoi(optarg);
|
||||
}
|
||||
if (c == 'U' || ind == UID_ARG) {
|
||||
_switches[UID_ARG]++;
|
||||
_values[UID_ARG] = atoi(optarg);
|
||||
_int_args[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);
|
||||
_int_args[MODE_ARG] = (int) strtol(optarg, NULL, 8);
|
||||
}
|
||||
if ((ind == EXEC_ARG)) {
|
||||
_switches[EXEC_ARG]++;
|
||||
@@ -2027,13 +2195,7 @@ static int _process_switches(int *argc, char ***argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_switches[COLS_ARG] && _switches[OPTIONS_ARG] &&
|
||||
strcmp(_fields, "name")) {
|
||||
fprintf(stderr, "Only -o name is supported so far.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_switches[TREE_ARG] && !_process_tree_options(_fields))
|
||||
if (_switches[TREE_ARG] && !_process_tree_options(_string_args[OPTIONS_ARG]))
|
||||
return 0;
|
||||
|
||||
if (_switches[TABLE_ARG] && _switches[NOTABLE_ARG]) {
|
||||
@@ -2081,6 +2243,9 @@ int main(int argc, char **argv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (_switches[COLS_ARG] && !_report_init(c))
|
||||
goto out;
|
||||
|
||||
doit:
|
||||
if (!c->fn(argc, argv, NULL)) {
|
||||
fprintf(stderr, "Command failed\n");
|
||||
@@ -2090,5 +2255,10 @@ int main(int argc, char **argv)
|
||||
r = 0;
|
||||
|
||||
out:
|
||||
if (_report) {
|
||||
dm_report_output(_report);
|
||||
dm_report_free(_report);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -19,15 +19,10 @@ int dumpconfig(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
const char *file = NULL;
|
||||
|
||||
if (argc == 1)
|
||||
file = argv[0];
|
||||
if (arg_count(cmd, file_ARG))
|
||||
file = arg_str_value(cmd, file_ARG, "");
|
||||
|
||||
if (argc > 1) {
|
||||
log_error("Please specify one file for output");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!write_config_file(cmd->cft, file))
|
||||
if (!write_config_file(cmd->cft, file, argc, argv))
|
||||
return ECMD_FAILED;
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
|
||||
@@ -23,7 +23,7 @@ TARGETS = fsadm
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
fsadm: $(OBJECTS)
|
||||
$(CC) -o $@ $(OBJECTS) -rdynamic
|
||||
$(CC) -o $@ $(CFLAGS) $(OBJECTS) -rdynamic
|
||||
|
||||
install: fsadm
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) fsadm \
|
||||
|
||||
@@ -19,6 +19,7 @@ static int lvchange_permission(struct cmd_context *cmd,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
uint32_t lv_access;
|
||||
struct lvinfo info;
|
||||
|
||||
lv_access = arg_uint_value(cmd, permission_ARG, 0);
|
||||
|
||||
@@ -34,6 +35,13 @@ static int lvchange_permission(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((lv->status & MIRRORED) && (lv->vg->status & CLUSTERED) &&
|
||||
lv_info(cmd, lv, &info, 0) && info.exists) {
|
||||
log_error("Cannot change permissions of mirror \"%s\" "
|
||||
"while active.", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_access & LVM_WRITE) {
|
||||
lv->status |= LVM_WRITE;
|
||||
log_verbose("Setting logical volume \"%s\" read/write",
|
||||
@@ -72,10 +80,9 @@ static int lvchange_permission(struct cmd_context *cmd,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lvchange_registration(struct cmd_context *cmd,
|
||||
struct logical_volume *lv)
|
||||
static int lvchange_monitoring(struct cmd_context *cmd,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
int r;
|
||||
struct lvinfo info;
|
||||
|
||||
if (!lv_info(cmd, lv, &info, 0) || !info.exists) {
|
||||
@@ -83,25 +90,15 @@ static int lvchange_registration(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* do not register pvmove lv's */
|
||||
/* do not monitor pvmove lv's */
|
||||
if (lv->status & PVMOVE)
|
||||
return 1;
|
||||
|
||||
log_verbose("%smonitoring logical volume \"%s\"",
|
||||
(dmeventd_register_mode()) ? "" : "Not ", lv->name);
|
||||
r = register_dev_for_events(cmd, lv, dmeventd_register_mode());
|
||||
if ((dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) &&
|
||||
!monitor_dev_for_events(cmd, lv, dmeventd_monitor_mode()))
|
||||
stack;
|
||||
|
||||
if (r < 0) {
|
||||
log_error("Unable to %smonitor logical volume, %s",
|
||||
(dmeventd_register_mode()) ? "" : "un", lv->name);
|
||||
r = 0;
|
||||
} else if (!r) {
|
||||
log_verbose("Logical volume %s needs no monitoring.",
|
||||
lv->name);
|
||||
r = 1;
|
||||
}
|
||||
|
||||
return r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lvchange_availability(struct cmd_context *cmd,
|
||||
@@ -595,7 +592,9 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
init_dmeventd_register(arg_int_value(cmd, monitor_ARG, DEFAULT_DMEVENTD_MONITOR));
|
||||
init_dmeventd_monitor(arg_int_value(cmd, monitor_ARG,
|
||||
cmd->is_static ?
|
||||
DMEVENTD_MONITOR_IGNORE : DEFAULT_DMEVENTD_MONITOR));
|
||||
|
||||
/* access permission change */
|
||||
if (arg_count(cmd, permission_ARG)) {
|
||||
@@ -665,7 +664,7 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
if (!arg_count(cmd, available_ARG) &&
|
||||
!arg_count(cmd, refresh_ARG) &&
|
||||
arg_count(cmd, monitor_ARG)) {
|
||||
if (!lvchange_registration(cmd, lv))
|
||||
if (!lvchange_monitoring(cmd, lv))
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
|
||||
@@ -281,15 +281,8 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
if (lp->mirrors == existing_mirrors) {
|
||||
if (!seg->log_lv && !arg_count(cmd, corelog_ARG)) {
|
||||
/* No disk log present, add one. */
|
||||
/* FIXME: Why doesn't this work? Without
|
||||
it, we will probably put the log on the
|
||||
same device as a mirror leg.
|
||||
if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
parallel_areas = NULL;
|
||||
if (!(parallel_areas = build_parallel_areas_from_lv(cmd, lv)))
|
||||
return_0;
|
||||
if (!lv_mirror_percent(cmd, lv, 0, &sync_percent, NULL)) {
|
||||
log_error("Unable to determine mirror sync status.");
|
||||
return 0;
|
||||
@@ -297,7 +290,7 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
|
||||
segtype = get_segtype_from_string(cmd, "striped");
|
||||
|
||||
if (!(ah = allocate_extents(lv->vg, NULL, segtype, 1,
|
||||
if (!(ah = allocate_extents(lv->vg, NULL, segtype, 0,
|
||||
0, 1, 0,
|
||||
NULL, 0, 0, lp->pvh,
|
||||
lp->alloc,
|
||||
@@ -453,8 +446,8 @@ static int lvconvert_snapshot(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lp->zero)
|
||||
log_error("WARNING: \"%s\" not zeroed", lv->name);
|
||||
if (!lp->zero || !(lv->status & LVM_WRITE))
|
||||
log_print("WARNING: \"%s\" not zeroed", lv->name);
|
||||
else if (!set_lv(cmd, lv, 0, 0)) {
|
||||
log_error("Aborting. Failed to wipe snapshot "
|
||||
"exception store.");
|
||||
|
||||
@@ -434,6 +434,10 @@ static int _lvcreate_params(struct lvcreate_params *lp, struct cmd_context *cmd,
|
||||
else
|
||||
lp->permission = LVM_READ | LVM_WRITE;
|
||||
|
||||
/* Must not zero read only volume */
|
||||
if (!(lp->permission & LVM_WRITE))
|
||||
lp->zero = 0;
|
||||
|
||||
lp->minor = arg_int_value(cmd, minor_ARG, -1);
|
||||
lp->major = arg_int_value(cmd, major_ARG, -1);
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "tools.h"
|
||||
#include "lvm2cmdline.h"
|
||||
#include "label.h"
|
||||
#include "memlock.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "lvm2cmd.h"
|
||||
@@ -77,7 +78,13 @@ int lvm2_run(void *handle, const char *cmdline)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = lvm_run_command(cmd, argc, argv);
|
||||
/* FIXME Temporary - move to libdevmapper */
|
||||
if (!strcmp(cmdline, "_memlock_inc"))
|
||||
memlock_inc();
|
||||
if (!strcmp(cmdline, "_memlock_dec"))
|
||||
memlock_dec();
|
||||
else
|
||||
ret = lvm_run_command(cmd, argc, argv);
|
||||
|
||||
out:
|
||||
dm_free(cmdcopy);
|
||||
|
||||
@@ -1030,7 +1030,7 @@ struct cmd_context *init_lvm(unsigned is_static)
|
||||
{
|
||||
struct cmd_context *cmd;
|
||||
|
||||
if (!(cmd = create_toolcontext(&the_args[0], is_static))) {
|
||||
if (!(cmd = create_toolcontext(&the_args[0], is_static, 0))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
@@ -1065,8 +1065,9 @@ static int _run_script(struct cmd_context *cmd, int argc, char **argv)
|
||||
char buffer[CMD_LEN];
|
||||
int ret = 0;
|
||||
int magic_number = 0;
|
||||
char *script_file = argv[0];
|
||||
|
||||
if ((script = fopen(argv[0], "r")) == NULL)
|
||||
if ((script = fopen(script_file, "r")) == NULL)
|
||||
return ENO_SUCH_CMD;
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), script) != NULL) {
|
||||
@@ -1099,7 +1100,9 @@ static int _run_script(struct cmd_context *cmd, int argc, char **argv)
|
||||
lvm_run_command(cmd, argc, argv);
|
||||
}
|
||||
|
||||
fclose(script);
|
||||
if (fclose(script))
|
||||
log_sys_error("fclose", script_file);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -152,6 +152,14 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((lv->status & MIRRORED) ||
|
||||
(lv->status & MIRROR_LOG) ||
|
||||
(lv->status & MIRROR_IMAGE)) {
|
||||
log_error("Mirrored LV, \"%s\" cannot be renamed: %s",
|
||||
lv->name, strerror(ENOSYS));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!archive(lv->vg)) {
|
||||
stack;
|
||||
goto error;
|
||||
|
||||
@@ -29,7 +29,7 @@ static int _pvchange_single(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
const char *pv_name = dev_name(pv->dev);
|
||||
const char *tag = NULL;
|
||||
const char *orig_vg_name;
|
||||
char uuid[64];
|
||||
char uuid[64] __attribute((aligned(8)));
|
||||
|
||||
int consistent = 1;
|
||||
int allocatable = 0;
|
||||
|
||||
@@ -38,8 +38,8 @@ static int pvremove_check(struct cmd_context *cmd, const char *name)
|
||||
if (!(pv = pv_read(cmd, name, NULL, NULL, 1))) {
|
||||
if (arg_count(cmd, force_ARG))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
log_error("Physical Volume %s not found", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* orphan ? */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user