1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-12-24 16:23:50 +03:00

Compare commits

...

94 Commits

Author SHA1 Message Date
Alasdair Kergon
cce3baa275 pre-release 2007-01-11 22:49:43 +00:00
Alasdair Kergon
2b48fad426 updated dmeventd interface 2007-01-11 22:24:32 +00:00
Alasdair Kergon
d554b2bc94 Lots of dmeventd-related changes. 2007-01-11 21:54:53 +00:00
Alasdair Kergon
f66943de43 fail if status args are missing 2007-01-11 20:11:19 +00:00
Alasdair Kergon
9d1e9bc2fb Remove dmeventd mirror status line word limit 2007-01-11 19:52:06 +00:00
Alasdair Kergon
2d6a014920 Use CFLAGS when linking so mixed sparc builds can supply -m64 2007-01-11 17:12:27 +00:00
Alasdair Kergon
c1952bf257 Use CFLAGS when linking so mixed sparc builds can supply -m64. 2007-01-11 16:23:22 +00:00
Alasdair Kergon
a10227eb03 Prevent permission changes on active mirrors. 2007-01-10 19:56:39 +00:00
Milan Broz
475ae29b85 Print warning instead of error message if cannot zero volume
Update lvconvert man page (snapshot option)
2007-01-10 14:13:46 +00:00
Alasdair Kergon
0b9cfc278b dumpconfig accepts a list of configuration variables to display.
Change dumpconfig to use --file to redirect output to a file.
2007-01-09 23:22:31 +00:00
Alasdair Kergon
b57b6b4fba Avoid vgreduce error when mirror code removes the log LV. 2007-01-09 23:14:35 +00:00
Alasdair Kergon
7d948f7bc5 Remove 3 redundant AC_MSG_RESULTs from configure.in. 2007-01-09 22:07:20 +00:00
Alasdair Kergon
459023d171 Free memory in _raw_read_mda_header() error paths.
Fix ambiguous vgsplit error message for split LV.
Fix lvextend man page typo.
2007-01-09 21:12:41 +00:00
Alasdair Kergon
fd6570720a Add configure --with-dmdir to compile against a device-mapper source tree.
Use no flush suspending for mirrors.
2007-01-09 20:31:08 +00:00
Alasdair Kergon
7831665417 Add dm_tree_use_no_flush_suspend(). 2007-01-09 19:44:07 +00:00
Alasdair Kergon
7c9920d982 fix last checkin 2007-01-08 15:35:08 +00:00
Alasdair Kergon
cbdccf0a9c Lots of dmevent changes.
Export dm_basename().
Cope with a trailing space when comparing tables prior to possible reload.
2007-01-08 15:18:52 +00:00
Alasdair Kergon
64fa83ec3f Add dmeventd_mirror register_mutex, tidy initialisation & add memlock. 2007-01-08 14:24:20 +00:00
Milan Broz
faff865cfd Fix create mirror with name longer than 22 chars. 2007-01-05 15:53:40 +00:00
Alasdair Kergon
742ab55a9a Fix some activate.c prototypes when compiled without devmapper. 2006-12-20 16:19:01 +00:00
Alasdair Kergon
66e623fb2a Fix dmeventd mirror to cope if monitored device disappears. 2006-12-20 14:35:02 +00:00
Alasdair Kergon
4ab17ee965 post-release 2006-12-14 22:21:32 +00:00
Alasdair Kergon
7f48ca5132 pre-release 2006-12-14 20:05:08 +00:00
Alasdair Kergon
da983848b4 Add missing pvremove error message when device doesn't exist. 2006-12-13 18:40:23 +00:00
Alasdair Kergon
bc03f7bad3 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.

(See lvm-devel list archives for further details.)
2006-12-13 03:39:58 +00:00
Alasdair Kergon
a1c8bd3846 Fix detection of smallest area in _alloc_parallel_area() for cling policy. 2006-12-12 19:30:10 +00:00
Patrick Caulfield
404bc284e0 Add manpage reference for clvmd -T that got missed out when I
checked the code in (sorry).
2006-12-11 14:06:25 +00:00
Patrick Caulfield
9dee30ff0e Fix gulm operation of clvmd. including a hang when attempting to
exclusively lock an LV that is already locked no another node.
2006-12-11 14:00:26 +00:00
Patrick Caulfield
f91aadbea8 Fix hang in clvmd if a pre-command failed. The pre/post thread was getting
out of sync in this instance and would not quit.
2006-12-11 13:48:41 +00:00
Alasdair Kergon
aa15a10c91 post-release 2006-12-01 23:29:54 +00:00
Alasdair Kergon
5b03e36351 pre release 2006-12-01 23:15:59 +00:00
Alasdair Kergon
b9ba9ffad2 clvmd ia64 alignment fixes etc. (pjc) 2006-12-01 23:10:26 +00:00
Alasdair Kergon
642be5d16c Fix VG clustered read locks to use PR not CR.
VG metadata reads were not being locked out during metadata updates.
2006-12-01 22:48:47 +00:00
Alasdair Kergon
ee68d715bf Adjust some alignments for ia64 and sparc.
(Some of the changes are probably unnecessary.)
2006-11-30 23:11:42 +00:00
Alasdair Kergon
224084f056 Fix mirror segment removal to use temporary error segment. 2006-11-30 17:52:47 +00:00
Patrick Caulfield
1cd8c849b8 Always compile debug logging into clvmd as it's too useful to
restrict to just developers.
-d will switch it on and run the daemon in the foreground
2006-11-30 13:19:42 +00:00
Patrick Caulfield
169f68bfcd Add timeout to RHEL4 clvmd init script.
With the previous clvmd checkin this should address bz#187812
2006-11-30 10:16:48 +00:00
Patrick Caulfield
d2b7cfa2d1 Add -T (startup timeout) switch to clvmd 2006-11-30 09:44:07 +00:00
Alasdair Kergon
a40c7dff5d post-release 2006-11-28 22:51:01 +00:00
Alasdair Kergon
e8e00630d3 pre-release 2006-11-28 22:49:58 +00:00
Alasdair Kergon
e33720c854 Update dmsetup man page (setgeometry & message) 2006-11-23 20:34:16 +00:00
Alasdair Kergon
bd8a4e0d17 mention new env vars on man page 2006-11-23 17:44:15 +00:00
Alasdair Kergon
586a2aef76 Improve lvm_dump.sh robustness. 2006-11-23 17:23:14 +00:00
Alasdair Kergon
ce1d8f6754 Update lvm2create_initrd to support gentoo. 2006-11-21 22:41:56 +00:00
Alasdair Kergon
7b0f401065 . 2006-11-21 17:46:11 +00:00
Alasdair Kergon
8387016eef Fix clvmd_init_rhel4 line truncation (2.02.14). 2006-11-21 17:44:46 +00:00
Alasdair Kergon
4e1342b641 fix _find_config_node: null parameter is permitted 2006-11-21 15:13:36 +00:00
Alasdair Kergon
e45a184d90 post-release 2006-11-20 23:30:45 +00:00
Alasdair Kergon
979e1012d2 Install lvmdump by default. 2006-11-20 20:03:26 +00:00
Alasdair Kergon
fe10a50e23 pre-release 2006-11-20 19:33:03 +00:00
Alasdair Kergon
8ab6d72519 Fix check for snapshot module when activating snapshot. 2006-11-20 16:45:45 +00:00
Alasdair Kergon
3aada6dd1d Fix pvremove error path for case when PV is in use. 2006-11-17 02:45:51 +00:00
Alasdair Kergon
0933036366 Warn if certain duplicate config file entries are seen.
(not thoroughly tested)
2006-11-16 17:36:00 +00:00
Alasdair Kergon
05f5abdc06 Enhance lvm_dump.sh for sysreport integration and add man page. 2006-11-16 16:44:48 +00:00
Alasdair Kergon
fb875e0709 Fix --autobackup argument which could never disable backups. 2006-11-14 15:28:50 +00:00
Alasdair Kergon
9acdc2f6bf Fix a label_verify error path. 2006-11-14 15:03:07 +00:00
Alasdair Kergon
028ce4bff6 post-release 2006-11-10 21:27:51 +00:00
Alasdair Kergon
3f245ad6db pre-release 2006-11-10 21:22:34 +00:00
Alasdair Kergon
23115f4116 fix cast 2006-11-10 20:15:10 +00:00
Alasdair Kergon
cf5f48e6cc Fix adjusted_mirror_region_size() for 64-bit size. 2006-11-10 19:35:03 +00:00
Alasdair Kergon
997fa756ad Add some missing bounds checks on 32 bit extent counters.
Add Petabyte and Exabyte support.
Fix lvcreate error message when 0 extents requested.
2006-11-10 18:24:11 +00:00
Patrick Caulfield
e23f75b1cc Add note to lvremove man page: volumes must be inactive on
all cluster nodes before being removed.
2006-11-06 14:11:40 +00:00
Alasdair Kergon
6531e88761 Protect .cache manipulations with fcntl locking.
Change .cache timestamp comparisons to use ctime.
2006-11-04 03:34:10 +00:00
Alasdair Kergon
e76a9c2618 fix shift 2006-11-03 21:23:06 +00:00
Alasdair Kergon
45be8a836b fix last check-in: lv->size is in sectors 2006-11-03 21:07:15 +00:00
Alasdair Kergon
954b6032e7 Fix mirror log LV writing to set all bits in whole LV. 2006-11-02 23:33:20 +00:00
Alasdair Kergon
bd95416f27 Fix clustered VG detection and default runlevels in clvmd_init_rhel4. 2006-11-01 18:25:26 +00:00
Alasdair Kergon
df2577ace2 Fix high-level free space check for partial allocations. 2006-10-30 16:10:55 +00:00
Alasdair Kergon
720e6558c9 post-release 2006-10-27 15:37:02 +00:00
Alasdair Kergon
c239f15d8a pre-release 2006-10-27 15:21:07 +00:00
Alasdair Kergon
dfa1f80a57 dd couple of missing files to tools/Makefile CLEAN_TARGETS. 2006-10-26 20:37:13 +00:00
Alasdair Kergon
15dfb93b17 When adding snapshot leave cow LV mapped device active after zeroing. 2006-10-26 18:22:10 +00:00
Alasdair Kergon
0ec8488c2b . 2006-10-24 19:07:32 +00:00
Jonathan Earl Brassow
94b2e29cb1 - likely cut and paste error. Fix wrong function name in debug
output.
2006-10-24 18:49:31 +00:00
Alasdair Kergon
fefa8e9b4d Add dev_flush() to set_lv() 2006-10-24 18:25:30 +00:00
Alasdair Kergon
32c4c44812 resync alphabetical order 2006-10-24 17:19:48 +00:00
Alasdair Kergon
05195e2b1d try forcesync -> resync 2006-10-24 17:18:25 +00:00
Alasdair Kergon
4c2ff675b8 reword --resync desc a bit 2006-10-24 17:09:40 +00:00
Alasdair Kergon
e5692a4721 fix forcesync local active detection 2006-10-24 15:30:33 +00:00
Alasdair Kergon
312e6a0d31 Add lvchange --forcesync. 2006-10-23 23:03:55 +00:00
Alasdair Kergon
5bb8efa41f Perform high-level free space check before each allocation attempt. 2006-10-23 15:54:51 +00:00
Patrick Caulfield
949a835f4a Don't allow a node to remove an LV that's exclusively active on anther node. 2006-10-23 11:46:16 +00:00
Alasdair Kergon
85e6042941 Cope if same PV is included more than once in cmdline PE range list. 2006-10-21 23:18:43 +00:00
Alasdair Kergon
3cd2f28975 getline debug free 2006-10-19 16:50:05 +00:00
Alasdair Kergon
2179a72c3a Suppress encryption key in 'dmsetup table' output unless --showkeys supplied. 2006-10-19 15:34:50 +00:00
Alasdair Kergon
a5f282f156 Set PV size to current device size if it is found to be zero. 2006-10-19 12:53:47 +00:00
Alasdair Kergon
40e8631f63 Add segment parameter to target_present functions. 2006-10-18 18:01:53 +00:00
Alasdair Kergon
9ded05bb97 post-release 2006-10-16 17:18:08 +00:00
Alasdair Kergon
ec8efa35a1 revert 2006-10-16 16:47:56 +00:00
Alasdair Kergon
f72bf20482 pre-release 2006-10-16 16:44:28 +00:00
Alasdair Kergon
ebde2002e8 Fix pvdisplay to use vg_read() for non-orphans 2006-10-16 16:29:40 +00:00
Alasdair Kergon
352a66f46f Fall back to internal locking if external locking lib is missing or fails. 2006-10-14 16:37:54 +00:00
Alasdair Kergon
d84c5391f7 Retain activation state after changing LV minor number with --force. 2006-10-13 21:33:31 +00:00
Alasdair Kergon
f4c582472b post-release.
Note that I've dropped the 2.4 kernel files from the release tarballs now.
2006-10-13 19:01:30 +00:00
108 changed files with 3084 additions and 1660 deletions

View File

@@ -16,7 +16,7 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
SUBDIRS = doc include man
SUBDIRS = doc include man scripts
ifeq ("@INTL@", "yes")
SUBDIRS += po

View File

@@ -1 +1 @@
2.02.12-cvs (2006-10-12)
2.02.18-cvs (2007-01-11)

View File

@@ -1,6 +1,92 @@
Version 2.02.12 -
Version 2.02.18 - 11th January 2007
===================================
Propogate clustered flag in vgsplit and require resizeable flag.
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.
Version 2.02.15 - 21st November 2006
====================================
Fix clvmd_init_rhel4 line truncation (2.02.14).
Install lvmdump by default.
Fix check for snapshot module when activating snapshot.
Fix pvremove error path for case when PV is in use.
Warn if certain duplicate config file entries are seen.
Enhance lvm_dump.sh for sysreport integration and add man page.
Fix --autobackup argument which could never disable backups.
Fix a label_verify error path.
Version 2.02.14 - 10th November 2006
====================================
Fix adjusted_mirror_region_size() to handle 64-bit size.
Add some missing bounds checks on 32-bit extent counters.
Add Petabyte and Exabyte support.
Fix lvcreate error message when 0 extents requested.
lvremove man page: volumes must be cluster inactive before being removed.
Protect .cache manipulations with fcntl locking.
Change .cache timestamp comparisons to use ctime.
Fix mirror log LV writing to set all bits in whole LV.
Fix clustered VG detection and default runlevels in clvmd_init_rhel4.
Fix high-level free space check for partial allocations.
Version 2.02.13 - 27th October 2006
===================================
Add couple of missing files to tools/Makefile CLEAN_TARGETS.
When adding snapshot leave cow LV mapped device active after zeroing.
Fix a clvmd debug message.
Add dev_flush() to set_lv().
Add lvchange --resync.
Perform high-level free space check before each allocation attempt.
Don't allow a node to remove an LV that's exclusively active on anther node.
Cope if same PV is included more than once in cmdline PE range list.
Set PV size to current device size if it is found to be zero.
Add segment parameter to target_present functions.
Version 2.02.12 - 16th October 2006
===================================
Fix pvdisplay to use vg_read() for non-orphans.
Fall back to internal locking if external locking lib is missing or fails.
Retain activation state after changing LV minor number with --force.
Propagate clustered flag in vgsplit and require resizeable flag.
Version 2.02.11 - 12th October 2006
===================================

View File

@@ -1,3 +1,19 @@
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).
Fix dmsetup free after getline with debug.
Suppress encryption key in 'dmsetup table' output unless --showkeys supplied.
Version 1.02.12 - 13 Oct 2006
=============================
Avoid deptree attempting to suspend a device that's already suspended.

29
configure vendored
View File

@@ -310,7 +310,7 @@ ac_includes_default="\
#endif"
ac_default_prefix=/usr
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB 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,10 +11198,11 @@ fi
################################################################################
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile dmeventd/Makefile dmeventd/mirror/Makefile doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/snapshot/Makefile man/Makefile po/Makefile tools/Makefile tools/version.h tools/fsadm/Makefile test/mm/Makefile test/device/Makefile test/format1/Makefile test/regex/Makefile test/filters/Makefile"
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile dmeventd/Makefile dmeventd/mirror/Makefile doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/snapshot/Makefile man/Makefile po/Makefile scripts/Makefile tools/Makefile tools/version.h tools/fsadm/Makefile test/mm/Makefile test/device/Makefile test/format1/Makefile test/regex/Makefile test/filters/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
@@ -11745,6 +11744,7 @@ do
"lib/snapshot/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/snapshot/Makefile" ;;
"man/Makefile" ) CONFIG_FILES="$CONFIG_FILES man/Makefile" ;;
"po/Makefile" ) CONFIG_FILES="$CONFIG_FILES po/Makefile" ;;
"scripts/Makefile" ) CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;;
"tools/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
"tools/version.h" ) CONFIG_FILES="$CONFIG_FILES tools/version.h" ;;
"tools/fsadm/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/fsadm/Makefile" ;;
@@ -11899,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

View File

@@ -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)
@@ -637,6 +637,7 @@ lib/mirror/Makefile \
lib/snapshot/Makefile \
man/Makefile \
po/Makefile \
scripts/Makefile \
tools/Makefile \
tools/version.h \
tools/fsadm/Makefile \

View File

@@ -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

View File

@@ -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:

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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);

View File

@@ -243,7 +243,7 @@ static int do_resume_lv(char *resource)
/* Is it open ? */
oldmode = get_current_lock(resource);
if (oldmode == -1) {
DEBUGLOG("do_deactivate_lock, lock not already held\n");
DEBUGLOG("do_resume_lv, lock not already held\n");
return 0; /* We don't need to do anything */
}

View File

@@ -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;

View File

@@ -1,5 +1,16 @@
dm_event_handler_create
dm_event_handler_destroy
dm_event_handler_set_dso
dm_event_handler_set_name
dm_event_handler_set_uuid
dm_event_handler_set_major
dm_event_handler_set_minor
dm_event_handler_set_events
dm_event_handler_get_dso
dm_event_handler_get_name
dm_event_handler_get_uuid
dm_event_handler_get_major
dm_event_handler_get_minor
dm_event_handler_get_events
dm_event_register
dm_event_unregister
dm_event_get_registered_device
dm_event_set_timeout
dm_event_get_timeout

View File

@@ -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

View File

@@ -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__ */

View File

@@ -1,4 +1,4 @@
/*
/*
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
@@ -27,12 +27,490 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <arpa/inet.h> /* for htonl, ntohl */
/* Set by any of the external fxns the first time one of them is called */
/* FIXME Unused */
// static int _logging = 0;
struct dm_event_handler {
const char *dso;
const char *device;
const char *uuid;
int major;
int minor;
enum dm_event_type events;
};
static void dm_event_handler_clear_device(struct dm_event_handler *h)
{
h->device = h->uuid = NULL;
h->major = h->minor = 0;
}
struct dm_event_handler *dm_event_handler_create(void)
{
struct dm_event_handler *ret = 0;
if (!(ret = dm_malloc(sizeof(*ret))))
return NULL;
ret->dso = ret->device = ret->uuid = NULL;
ret->major = ret->minor = 0;
ret->events = 0;
return ret;
}
void dm_event_handler_destroy(struct dm_event_handler *h)
{
dm_free(h);
}
void dm_event_handler_set_dso(struct dm_event_handler *h, const char *path)
{
h->dso = path;
}
void dm_event_handler_set_name(struct dm_event_handler *h, const char *name)
{
dm_event_handler_clear_device(h);
h->device = name;
}
void dm_event_handler_set_uuid(struct dm_event_handler *h, const char *uuid)
{
dm_event_handler_clear_device(h);
h->uuid = uuid;
}
void dm_event_handler_set_major(struct dm_event_handler *h, int major)
{
int minor = h->minor;
dm_event_handler_clear_device(h);
h->major = major;
h->minor = minor;
}
void dm_event_handler_set_minor(struct dm_event_handler *h, int minor)
{
int major = h->major;
dm_event_handler_clear_device(h);
h->major = major;
h->minor = minor;
}
void dm_event_handler_set_events(struct dm_event_handler *h,
enum dm_event_type event)
{
h->events = event;
}
const char *dm_event_handler_get_dso(const struct dm_event_handler *h)
{
return h->dso;
}
const char *dm_event_handler_get_name(const struct dm_event_handler *h)
{
return h->device;
}
const char *dm_event_handler_get_uuid(const struct dm_event_handler *h)
{
return h->uuid;
}
int dm_event_handler_get_major(const struct dm_event_handler *h)
{
return h->major;
}
int dm_event_handler_get_minor(const struct dm_event_handler *h)
{
return h->minor;
}
enum dm_event_type dm_event_handler_get_events(const struct dm_event_handler *h)
{
return h->events;
}
/*
* daemon_read
* @fifos
* @msg
*
* Read message from daemon.
*
* Returns: 0 on failure, 1 on success
*/
static int daemon_read(struct dm_event_fifos *fifos,
struct dm_event_daemon_message *msg)
{
unsigned bytes = 0;
int ret, i;
fd_set fds;
struct timeval tval = { 0, 0 };
size_t size = 2 * sizeof(uint32_t); /* status + size */
char *buf = alloca(size);
int header = 1;
while (bytes < size) {
for (i = 0, ret = 0; (i < 20) && (ret < 1); i++) {
/* Watch daemon read FIFO for input. */
FD_ZERO(&fds);
FD_SET(fifos->server, &fds);
tval.tv_sec = 1;
ret = select(fifos->server + 1, &fds, NULL, NULL,
&tval);
if (ret < 0 && errno != EINTR) {
log_error("Unable to read from event server");
return 0;
}
}
if (ret < 1) {
log_error("Unable to read from event server.");
return 0;
}
ret = read(fifos->server, buf + bytes, size);
if (ret < 0) {
if ((errno == EINTR) || (errno == EAGAIN))
continue;
else {
log_error("Unable to read from event server.");
return 0;
}
}
bytes += ret;
if (bytes == 2 * sizeof(uint32_t) && header) {
msg->cmd = ntohl(*((uint32_t *)buf));
msg->size = ntohl(*((uint32_t *)buf + 1));
buf = msg->data = dm_malloc(msg->size);
size = msg->size;
bytes = 0;
header = 0;
}
}
if (bytes != size) {
if (msg->data)
dm_free(msg->data);
msg->data = NULL;
}
return bytes == size;
}
/* Write message to daemon. */
static int daemon_write(struct dm_event_fifos *fifos,
struct dm_event_daemon_message *msg)
{
unsigned bytes = 0;
int ret = 0;
fd_set fds;
size_t size = 2 * sizeof(uint32_t) + msg->size;
char *buf = alloca(size);
*((uint32_t *)buf) = htonl(msg->cmd);
*((uint32_t *)buf + 1) = htonl(msg->size);
memcpy(buf + 2 * sizeof(uint32_t), msg->data, msg->size);
while (bytes < size) {
do {
/* Watch daemon write FIFO to be ready for output. */
FD_ZERO(&fds);
FD_SET(fifos->client, &fds);
ret = select(fifos->client + 1, NULL, &fds, NULL, NULL);
if ((ret < 0) && (errno != EINTR)) {
log_error("Unable to talk to event daemon");
return 0;
}
} while (ret < 1);
ret = write(fifos->client, ((char *) buf) + bytes,
size - bytes);
if (ret < 0) {
if ((errno == EINTR) || (errno == EAGAIN))
continue;
else {
log_error("Unable to talk to event daemon");
return 0;
}
}
bytes += ret;
}
return bytes == size;
}
static int daemon_talk(struct dm_event_fifos *fifos,
struct dm_event_daemon_message *msg, int cmd,
const char *dso_name, const char *device,
enum dm_event_type events, uint32_t timeout)
{
const char *dso = dso_name ? dso_name : "";
const char *dev = device ? device : "";
const char *fmt = "%s %s %u %" PRIu32;
memset(msg, 0, sizeof(*msg));
/*
* Set command and pack the arguments
* into ASCII message string.
*/
msg->cmd = cmd;
msg->size = dm_saprintf(&(msg->data), fmt, dso, dev, events, timeout);
/*
* Write command and message to and
* read status return code from daemon.
*/
if (!daemon_write(fifos, msg)) {
stack;
return -EIO;
}
if (!daemon_read(fifos, msg)) {
stack;
return -EIO;
}
return (int32_t) msg->cmd;
}
/*
* start_daemon
*
* This function forks off a process (dmeventd) that will handle
* the events. I am currently test opening one of the fifos to
* ensure that the daemon is running and listening... I thought
* this would be less expensive than fork/exec'ing every time.
* Perhaps there is an even quicker/better way (no, checking the
* lock file is _not_ a better way).
*
* Returns: 1 on success, 0 otherwise
*/
static int start_daemon(struct dm_event_fifos *fifos)
{
int pid, ret = 0;
int status;
struct stat statbuf;
if (stat(fifos->client_path, &statbuf))
goto start_server;
if (!S_ISFIFO(statbuf.st_mode)) {
log_error("%s is not a fifo.", fifos->client_path);
return 0;
}
/* Anyone listening? If not, errno will be ENXIO */
fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK);
if (fifos->client >= 0) {
/* server is running and listening */
close(fifos->client);
return 1;
} else if (errno != ENXIO) {
/* problem */
log_error("%s: Can't open client fifo %s: %s",
__func__, fifos->client_path, strerror(errno));
stack;
return 0;
}
start_server:
/* server is not running */
pid = fork();
if (pid < 0)
log_error("Unable to fork.");
else if (!pid) {
/* FIXME configure path (cf. lvm2 modprobe) */
execvp("dmeventd", NULL);
exit(EXIT_FAILURE);
} else {
if (waitpid(pid, &status, 0) < 0)
log_error("Unable to start dmeventd: %s",
strerror(errno));
else if (WEXITSTATUS(status))
log_error("Unable to start dmeventd.");
else
ret = 1;
}
return ret;
}
/* Initialize client. */
static int init_client(struct dm_event_fifos *fifos)
{
/* FIXME? Is fifo the most suitable method? Why not share
comms/daemon code with something else e.g. multipath? */
/* init fifos */
memset(fifos, 0, sizeof(*fifos));
fifos->client_path = DM_EVENT_FIFO_CLIENT;
fifos->server_path = DM_EVENT_FIFO_SERVER;
if (!start_daemon(fifos)) {
stack;
return 0;
}
/* Open the fifo used to read from the daemon. */
if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) {
log_error("%s: open server fifo %s",
__func__, fifos->server_path);
stack;
return 0;
}
/* Lock out anyone else trying to do communication with the daemon. */
if (flock(fifos->server, LOCK_EX) < 0) {
log_error("%s: flock %s", __func__, fifos->server_path);
close(fifos->server);
return 0;
}
/* if ((fifos->client = open(fifos->client_path, O_WRONLY | O_NONBLOCK)) < 0) {*/
if ((fifos->client = open(fifos->client_path, O_RDWR | O_NONBLOCK)) < 0) {
log_error("%s: Can't open client fifo %s: %s",
__func__, fifos->client_path, strerror(errno));
close(fifos->server);
stack;
return 0;
}
return 1;
}
static void dtr_client(struct dm_event_fifos *fifos)
{
if (flock(fifos->server, LOCK_UN))
log_error("flock unlock %s", fifos->server_path);
close(fifos->client);
close(fifos->server);
}
/* Get uuid of a device, if it exists (otherwise NULL). */
static struct dm_task *get_device_info(const struct dm_event_handler *h)
{
struct dm_task *dmt = dm_task_create(DM_DEVICE_INFO);
struct dm_task *ret;
if (!dmt)
return NULL;
if (h->uuid)
dm_task_set_uuid(dmt, h->uuid);
else if (h->device)
dm_task_set_name(dmt, h->device);
else if (h->major && h->minor) {
dm_task_set_major(dmt, h->major);
dm_task_set_minor(dmt, h->minor);
}
if (!dm_task_run(dmt))
ret = NULL;
else
ret = dmt;
return ret;
}
/* Handle the event (de)registration call and return negative error codes. */
static int do_event(int cmd, struct dm_event_daemon_message *msg,
const char *dso_name, const char *device,
enum dm_event_type events, uint32_t timeout)
{
int ret;
struct dm_event_fifos fifos;
if (!init_client(&fifos)) {
stack;
return -ESRCH;
}
ret = daemon_talk(&fifos, msg, cmd, dso_name, device, events, timeout);
/* what is the opposite of init? */
dtr_client(&fifos);
return ret;
}
/* External library interface. */
int dm_event_register(const struct dm_event_handler *h)
{
int ret, err;
const char *uuid;
struct dm_task *dmt;
struct dm_event_daemon_message msg;
if (!(dmt = get_device_info(h))) {
log_error("%s: device not found", h->device);
return 0;
}
uuid = dm_task_get_uuid(dmt);
if ((err = do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg,
h->dso, uuid, h->events, 0)) < 0) {
log_error("%s: event registration failed: %s",
dm_task_get_name(dmt),
msg.data ? msg.data : strerror(-err));
ret = 0;
} else
ret = 1;
if (msg.data)
dm_free(msg.data);
dm_task_destroy(dmt);
return ret;
}
int dm_event_unregister(const struct dm_event_handler *h)
{
int ret, err;
const char *uuid;
struct dm_task *dmt;
struct dm_event_daemon_message msg;
if (!(dmt = get_device_info(h))) {
log_error("%s: device not found", dm_task_get_name(dmt));
return 0;
}
uuid = dm_task_get_uuid(dmt);
if ((err = do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg,
h->dso, uuid, h->events, 0)) < 0) {
log_error("%s: event deregistration failed: %s",
dm_task_get_name(dmt),
msg.data ? msg.data : strerror(-err));
ret = 0;
} else
ret = 1;
if (msg.data)
dm_free(msg.data);
dm_task_destroy(dmt);
return ret;
}
#if 0 /* left out for now */
/* Fetch a string off src and duplicate it into *dest. */
/* FIXME: move to seperate module to share with the daemon. */
@@ -57,10 +535,9 @@ static char *fetch_string(char **src)
static int parse_message(struct dm_event_daemon_message *msg, char **dso_name,
char **device, enum dm_event_type *events)
{
char *p = msg->msg;
char *p = msg->data;
if ((*dso_name = fetch_string(&p)) &&
(*device = fetch_string(&p))) {
if ((*dso_name = fetch_string(&p)) && (*device = fetch_string(&p))) {
*events = atoi(p);
return 0;
@@ -70,397 +547,35 @@ static int parse_message(struct dm_event_daemon_message *msg, char **dso_name,
}
/*
* daemon_read
* @fifos
* @msg
* dm_event_get_registered_device
* @dso_name
* @device_path
* @events
* @next
*
* Read message from daemon.
* FIXME: This function sucks.
*
* Returns: 0 on failure, 1 on success
* Returns: 1 if device found, 0 otherwise (even on error)
*/
static int daemon_read(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
{
unsigned bytes = 0;
int ret = 0;
fd_set fds;
memset(msg, 0, sizeof(*msg));
while (bytes < sizeof(*msg)) {
do {
/* Watch daemon read FIFO for input. */
FD_ZERO(&fds);
FD_SET(fifos->server, &fds);
ret = select(fifos->server+1, &fds, NULL, NULL, NULL);
if (ret < 0 && errno != EINTR) {
/* FIXME Log error */
return 0;
}
} while (ret < 1);
ret = read(fifos->server, msg, sizeof(*msg) - bytes);
if (ret < 0) {
if ((errno == EINTR) || (errno == EAGAIN))
continue;
else {
/* FIXME Log error */
return 0;
}
}
bytes += ret;
}
return bytes == sizeof(*msg);
}
/* Write message to daemon. */
static int daemon_write(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg)
{
unsigned bytes = 0;
int ret = 0;
fd_set fds;
while (bytes < sizeof(*msg)) {
do {
/* Watch daemon write FIFO to be ready for output. */
FD_ZERO(&fds);
FD_SET(fifos->client, &fds);
ret = select(fifos->client +1, NULL, &fds, NULL, NULL);
if ((ret < 0) && (errno != EINTR)) {
/* FIXME Log error */
return 0;
}
} while (ret < 1);
ret = write(fifos->client, msg, sizeof(*msg) - bytes);
if (ret < 0) {
if ((errno == EINTR) || (errno == EAGAIN))
continue;
else {
/* fixme: log error */
return 0;
}
}
bytes += ret;
}
return bytes == sizeof(*msg);
}
static int daemon_talk(struct dm_event_fifos *fifos, struct dm_event_daemon_message *msg,
int cmd, char *dso_name, char *device,
enum dm_event_type events, uint32_t timeout)
{
memset(msg, 0, sizeof(*msg));
/*
* Set command and pack the arguments
* into ASCII message string.
*/
msg->opcode.cmd = cmd;
if (sizeof(msg->msg) <= (unsigned) snprintf(msg->msg, sizeof(msg->msg),
"%s %s %u %"PRIu32,
dso_name ? dso_name : "",
device ? device : "",
events, timeout)) {
stack;
return -ENAMETOOLONG;
}
/*
* Write command and message to and
* read status return code from daemon.
*/
if (!daemon_write(fifos, msg)) {
stack;
return -EIO;
}
if (!daemon_read(fifos, msg)) {
stack;
return -EIO;
}
return msg->opcode.status;
}
static volatile sig_atomic_t daemon_running = 0;
static void daemon_running_signal_handler(int sig)
{
daemon_running = 1;
}
/*
* start_daemon
*
* This function forks off a process (dmeventd) that will handle
* the events. A signal must be returned from the child to
* indicate when it is ready to handle requests. The parent
* (this function) returns 1 if there is a daemon running.
*
* Returns: 1 on success, 0 otherwise
*/
static int start_daemon(void)
{
int pid, ret=0;
void *old_hand;
sigset_t set, oset;
/* Must be able to acquire signal */
old_hand = signal(SIGUSR1, &daemon_running_signal_handler);
if (old_hand == SIG_ERR) {
log_error("Unable to setup signal handler.");
return 0;
}
if (sigemptyset(&set) || sigaddset(&set, SIGUSR1)) {
log_error("Unable to fill signal set.");
} else if (sigprocmask(SIG_UNBLOCK, &set, &oset)) {
log_error("Can't unblock the potentially blocked signal SIGUSR1");
}
pid = fork();
if (pid < 0)
log_error("Unable to fork.\n");
else if (pid) { /* parent waits for child to get ready for requests */
int status;
/* FIXME Better way to do this? */
while (!waitpid(pid, &status, WNOHANG) && !daemon_running)
sleep(1);
if (daemon_running) {
ret = 1;
} else {
switch (WEXITSTATUS(status)) {
case EXIT_LOCKFILE_INUSE:
/*
* Note, this is ok... we still have daemon
* that we can communicate with...
*/
log_print("Starting dmeventd failed: "
"dmeventd already running.\n");
ret = 1;
break;
default:
log_error("Unable to start dmeventd.\n");
break;
}
}
/*
* Sometimes, a single process may perform multiple calls
* that result in a daemon starting and exiting. If we
* don't reset this, the second (or greater) time the daemon
* is started will cause this logic not to work.
*/
daemon_running = 0;
} else {
signal(SIGUSR1, SIG_IGN); /* don't care about error */
/* dmeventd function is responsible for properly setting **
** itself up. It must never return - only exit. This is**
** why it is followed by an EXIT_FAILURE */
dmeventd();
exit(EXIT_FAILURE);
}
/* FIXME What if old_hand is SIG_ERR? */
if (signal(SIGUSR1, old_hand) == SIG_ERR)
log_error("Unable to reset signal handler.");
if (sigprocmask(SIG_SETMASK, &oset, NULL))
log_error("Unable to reset signal mask.");
return ret;
}
/* Initialize client. */
static int init_client(struct dm_event_fifos *fifos)
{
/* FIXME Is fifo the most suitable method? */
/* FIXME Why not share comms/daemon code with something else e.g. multipath? */
/* init fifos */
memset(fifos, 0, sizeof(*fifos));
fifos->client_path = DM_EVENT_FIFO_CLIENT;
fifos->server_path = DM_EVENT_FIFO_SERVER;
/* FIXME The server should be responsible for these, not the client. */
/* Create fifos */
if (((mkfifo(fifos->client_path, 0600) == -1) && errno != EEXIST) ||
((mkfifo(fifos->server_path, 0600) == -1) && errno != EEXIST)) {
log_error("%s: Failed to create a fifo.\n", __func__);
return 0;
}
/* FIXME Warn/abort if perms are wrong - not something to fix silently. */
/* If they were already there, make sure permissions are ok. */
if (chmod(fifos->client_path, 0600)) {
log_error("Unable to set correct file permissions on %s",
fifos->client_path);
return 0;
}
if (chmod(fifos->server_path, 0600)) {
log_error("Unable to set correct file permissions on %s",
fifos->server_path);
return 0;
}
/*
* Open the fifo used to read from the daemon.
* Allows daemon to create its write fifo...
*/
if ((fifos->server = open(fifos->server_path, O_RDWR)) < 0) {
log_error("%s: open server fifo %s\n",
__func__, fifos->server_path);
stack;
return 0;
}
/* Lock out anyone else trying to do communication with the daemon. */
/* FIXME Why failure not retry? How do multiple processes communicate? */
if (flock(fifos->server, LOCK_EX) < 0){
log_error("%s: flock %s\n", __func__, fifos->server_path);
close(fifos->server);
return 0;
}
/* Anyone listening? If not, errno will be ENXIO */
while ((fifos->client = open(fifos->client_path,
O_WRONLY | O_NONBLOCK)) < 0) {
if (errno != ENXIO) {
log_error("%s: Can't open client fifo %s: %s\n",
__func__, fifos->client_path, strerror(errno));
close(fifos->server);
stack;
return 0;
}
/* FIXME Unnecessary if daemon was started before calling this */
if (!start_daemon()) {
stack;
return 0;
}
}
return 1;
}
static void dtr_client(struct dm_event_fifos *fifos)
{
if (flock(fifos->server, LOCK_UN))
log_error("flock unlock %s\n", fifos->server_path);
close(fifos->client);
close(fifos->server);
}
/* Check, if a block device exists. */
static int device_exists(char *device)
{
struct stat st_buf;
char path2[PATH_MAX];
if (!device)
return 0;
if (device[0] == '/') /* absolute path */
return !stat(device, &st_buf) && S_ISBLK(st_buf.st_mode);
if (PATH_MAX <= snprintf(path2, PATH_MAX, "%s/%s", dm_dir(), device))
return 0;
return !stat(path2, &st_buf) && S_ISBLK(st_buf.st_mode);
}
/* Handle the event (de)registration call and return negative error codes. */
static int do_event(int cmd, struct dm_event_daemon_message *msg,
char *dso_name, char *device, enum dm_event_type events,
uint32_t timeout)
{
int ret;
struct dm_event_fifos fifos;
/* FIXME Start the daemon here if it's not running e.g. exclusive lock file */
/* FIXME Move this to separate 'dm_event_register_handler' - if no daemon here, fail */
if (!init_client(&fifos)) {
stack;
return -ESRCH;
}
/* FIXME Use separate 'dm_event_register_handler' function to pass in dso? */
ret = daemon_talk(&fifos, msg, cmd, dso_name, device, events, timeout);
/* what is the opposite of init? */
dtr_client(&fifos);
return ret;
}
/* FIXME remove dso_name - use handle instead */
/* FIXME Use uuid not path! */
/* External library interface. */
int dm_event_register(char *dso_name, char *device_path,
enum dm_event_type events)
{
int ret;
struct dm_event_daemon_message msg;
if (!device_exists(device_path)) {
log_error("%s: device not found", device_path);
return 0;
}
if ((ret = do_event(DM_EVENT_CMD_REGISTER_FOR_EVENT, &msg,
dso_name, device_path, events, 0)) < 0) {
log_error("%s: event registration failed: %s", device_path,
strerror(-ret));
return 0;
}
return 1;
}
int dm_event_unregister(char *dso_name, char *device_path,
enum dm_event_type events)
{
int ret;
struct dm_event_daemon_message msg;
if (!device_exists(device_path)) {
log_error("%s: device not found", device_path);
return 0;
}
if ((ret = do_event(DM_EVENT_CMD_UNREGISTER_FOR_EVENT, &msg,
dso_name, device_path, events, 0)) < 0) {
log_error("%s: event deregistration failed: %s", device_path,
strerror(-ret));
return 0;
}
return 1;
}
int dm_event_get_registered_device(char **dso_name, char **device_path,
enum dm_event_type *events, int next)
enum dm_event_type *events, int next)
{
int ret;
char *dso_name_arg = NULL, *device_path_arg = NULL;
struct dm_event_daemon_message msg;
if (!(ret = do_event(next ? DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE :
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
&msg, *dso_name, *device_path, *events, 0)))
ret = parse_message(&msg, &dso_name_arg, &device_path_arg,
events);
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
&msg, *dso_name, *device_path, *events, 0))) {
ret = !parse_message(&msg, &dso_name_arg, &device_path_arg,
events);
} else /* FIXME: Make sure this is ENOENT */
ret = 0;
if (next){
if (msg.data)
dm_free(msg.data);
if (next) {
if (*dso_name)
dm_free(*dso_name);
if (*device_path)
@@ -477,7 +592,7 @@ int dm_event_get_registered_device(char **dso_name, char **device_path,
return ret;
}
int dm_event_set_timeout(char *device_path, uint32_t timeout)
int dm_event_set_timeout(const char *device_path, uint32_t timeout)
{
struct dm_event_daemon_message msg;
@@ -487,24 +602,18 @@ int dm_event_set_timeout(char *device_path, uint32_t timeout)
NULL, device_path, 0, timeout);
}
int dm_event_get_timeout(char *device_path, uint32_t *timeout)
int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
{
int ret;
struct dm_event_daemon_message msg;
if (!device_exists(device_path))
return -ENODEV;
if (!(ret = do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path, 0, 0)))
*timeout = atoi(msg.msg);
if (!(ret = do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path,
0, 0)))
*timeout = atoi(msg.data);
if (msg.data)
dm_free(msg.data);
return ret;
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/
#endif

View File

@@ -23,86 +23,71 @@
#include <stdint.h>
/* FIXME This stuff must be configurable. */
#define DM_EVENT_DAEMON "/sbin/dmeventd"
#define DM_EVENT_LOCKFILE "/var/lock/dmeventd"
#define DM_EVENT_FIFO_CLIENT "/var/run/dmeventd-client"
#define DM_EVENT_FIFO_SERVER "/var/run/dmeventd-server"
#define DM_EVENT_PIDFILE "/var/run/dmeventd.pid"
#define DM_EVENT_DEFAULT_TIMEOUT 10
/* Commands for the daemon passed in the message below. */
enum dm_event_command {
DM_EVENT_CMD_ACTIVE = 1,
DM_EVENT_CMD_REGISTER_FOR_EVENT,
DM_EVENT_CMD_UNREGISTER_FOR_EVENT,
DM_EVENT_CMD_GET_REGISTERED_DEVICE,
DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE,
DM_EVENT_CMD_SET_TIMEOUT,
DM_EVENT_CMD_GET_TIMEOUT,
};
/* Message passed between client and daemon. */
struct dm_event_daemon_message {
union {
unsigned int cmd; /* FIXME Use fixed size. */
int status; /* FIXME Use fixed size. */
} opcode;
char msg[252]; /* FIXME Why is this 252 ? */
} __attribute__((packed)); /* FIXME Do this properly! */
/* FIXME Is this meant to be exported? I can't see where the interface uses it. */
/* Fifos for client/daemon communication. */
struct dm_event_fifos {
int client;
int server;
const char *client_path;
const char *server_path;
};
/* Event type definitions. */
/* FIXME Use masks to separate the types and provide for extension. */
enum dm_event_type {
DM_EVENT_SINGLE = 0x01, /* Report multiple errors just once. */
DM_EVENT_MULTI = 0x02, /* Report all of them. */
DM_EVENT_SETTINGS_MASK = 0x0000FF,
DM_EVENT_SINGLE = 0x000001, /* Report multiple errors just once. */
DM_EVENT_MULTI = 0x000002, /* Report all of them. */
DM_EVENT_SECTOR_ERROR = 0x04, /* Failure on a particular sector. */
DM_EVENT_DEVICE_ERROR = 0x08, /* Device failure. */
DM_EVENT_PATH_ERROR = 0x10, /* Failure on an io path. */
DM_EVENT_ADAPTOR_ERROR = 0x20, /* Failure off a host adaptor. */
DM_EVENT_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 off a host adaptor. */
DM_EVENT_SYNC_STATUS = 0x40, /* Mirror synchronization completed/failed. */
DM_EVENT_TIMEOUT = 0x80, /* Timeout has occured */
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 */
};
/* 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)
#define DM_EVENT_ALL_ERRORS DM_EVENT_ERROR_MASK
/* Prototypes for event lib interface. */
/* FIXME Replace device with standard name/uuid/devno choice */
/* Interface changes:
First register a handler, passing in a unique ref for the device. */
// int dm_event_register_handler(const char *dso_name, const char *device);
// int dm_event_register(const char *dso_name, const char *name, const char *uuid, uint32_t major, uint32_t minor, enum dm_event_type events);
/* Or (better?) add to task structure and use existing functions - run a task to register/unregister events - we may need to run task withe that with the new event mechanism anyway, then the dso calls just hook in.
*/
/* FIXME Missing consts? */
int dm_event_register(char *dso_name, char *device, enum dm_event_type events);
int dm_event_unregister(char *dso_name, char *device,
enum dm_event_type events);
int dm_event_get_registered_device(char **dso_name, char **device,
enum dm_event_type *events, int next);
int dm_event_set_timeout(char *device, uint32_t timeout);
int dm_event_get_timeout(char *device, uint32_t *timeout);
struct dm_event_handler;
/* 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);
/* Create and destroy dm_event_handler struct, which is passed to
register/unregister functions below */
struct dm_event_handler *dm_event_handler_create(void);
void dm_event_handler_destroy(struct dm_event_handler *h);
/* Set parameters of a handler:
- dso - shared library path to handle the events
(only one of the following three needs to be set)
- name - device name or path
- uuid - device uuid
- major and minor - device major/minor numbers
- events - a bitfield defining which events to handle (see
enum dm_event_type above)
*/
void dm_event_handler_set_dso(struct dm_event_handler *h, const char *path);
void dm_event_handler_set_name(struct dm_event_handler *h, const char *name);
void dm_event_handler_set_uuid(struct dm_event_handler *h, const char *uuid);
void dm_event_handler_set_major(struct dm_event_handler *h, int major);
void dm_event_handler_set_minor(struct dm_event_handler *h, int minor);
void dm_event_handler_set_events(struct dm_event_handler *h,
enum dm_event_type event);
/* Get parameters of a handler, same as above */
const char *dm_event_handler_get_dso(const struct dm_event_handler *h);
const char *dm_event_handler_get_name(const struct dm_event_handler *h);
const char *dm_event_handler_get_uuid(const struct dm_event_handler *h);
int dm_event_handler_get_major(const struct dm_event_handler *h);
int dm_event_handler_get_minor(const struct dm_event_handler *h);
enum dm_event_type dm_event_handler_get_events(const struct dm_event_handler *h);
/* Call out to dmeventd to register or unregister a handler. If
dmeventd is not running, it is spawned first. */
int dm_event_register(const struct dm_event_handler *h);
int dm_event_unregister(const struct dm_event_handler *h);
/* Prototypes for DSO interface, see dmeventd.c, struct dso_data for
detailed descriptions. */
void process_event(struct dm_task *dmt, enum dm_event_type event);
int register_device(const char *device, const char *uuid, int major, int minor);
int unregister_device(const char *device, const char *uuid, int major,
int minor);
#endif

View File

@@ -26,79 +26,100 @@
#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];
*/
/* 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 + max log parameters */
args = dm_malloc((num_devs + 8) * sizeof(char *));
if (!args || dm_split_words(p, num_devs + 8, 0, args) < num_devs + 8)
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 +134,54 @@ 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 --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_type event)
{
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, &params);
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 +198,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 +210,66 @@ 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)
{
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)
{
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;
}

View File

@@ -26,79 +26,100 @@
#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];
*/
/* 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 + max log parameters */
args = dm_malloc((num_devs + 8) * sizeof(char *));
if (!args || dm_split_words(p, num_devs + 8, 0, args) < num_devs + 8)
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 +134,54 @@ 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 --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_type event)
{
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, &params);
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 +198,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 +210,66 @@ 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)
{
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)
{
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;
}

View File

@@ -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;

View File

@@ -782,12 +782,19 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
{
uint32_t s;
struct list *snh;
struct lv_segment *seg_present;
/* Ensure required device-mapper targets are loaded */
if (seg->segtype->ops->target_present &&
!seg->segtype->ops->target_present()) {
seg_present = find_cow(seg->lv) ? : seg;
log_debug("Checking kernel supports %s segment type for %s%s%s",
seg_present->segtype->name, seg->lv->name,
layer ? "-" : "", layer ? : "");
if (seg_present->segtype->ops->target_present &&
!seg_present->segtype->ops->target_present(seg_present)) {
log_error("Can't expand LV %s: %s target support missing "
"from kernel?", seg->lv->name, seg->segtype->name);
"from kernel?", seg->lv->name, seg_present->segtype->name);
return 0;
}
@@ -986,6 +993,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;
@@ -1065,7 +1074,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
View File

@@ -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");

View File

@@ -330,7 +330,7 @@ static int _load_config_file(struct cmd_context *cmd, const char *tag)
return 0;
}
if (!(cfl->cft = create_config_tree(config_file))) {
if (!(cfl->cft = create_config_tree(config_file, 0))) {
log_error("config_tree allocation failed");
return 0;
}
@@ -370,7 +370,7 @@ static int _init_lvm_conf(struct cmd_context *cmd)
{
/* No config file if LVM_SYSTEM_DIR is empty */
if (!*cmd->sys_dir) {
if (!(cmd->cft = create_config_tree(NULL))) {
if (!(cmd->cft = create_config_tree(NULL, 0))) {
log_error("Failed to create config tree");
return 0;
}
@@ -408,7 +408,7 @@ static int _merge_config_files(struct cmd_context *cmd)
/* Replace temporary duplicate copy of lvm.conf */
if (cmd->cft->root) {
if (!(cmd->cft = create_config_tree(NULL))) {
if (!(cmd->cft = create_config_tree(NULL, 0))) {
log_error("Failed to create config tree");
return 0;
}
@@ -609,8 +609,8 @@ static int _init_filters(struct cmd_context *cmd)
cmd->dump_filter = 0;
if (!stat(dev_cache, &st) &&
(st.st_mtime > config_file_timestamp(cmd->cft)) &&
!persistent_filter_load(f4))
(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);

View File

@@ -58,6 +58,8 @@ struct cs {
time_t timestamp;
char *filename;
int exists;
int keep_open;
struct device *dev;
};
static void _get_token(struct parser *p, int tok_prev);
@@ -95,7 +97,7 @@ static int _tok_match(const char *str, const char *b, const char *e)
/*
* public interface
*/
struct config_tree *create_config_tree(const char *filename)
struct config_tree *create_config_tree(const char *filename, int keep_open)
{
struct cs *c;
struct dm_pool *mem = dm_pool_create("config", 10 * 1024);
@@ -115,6 +117,8 @@ struct config_tree *create_config_tree(const char *filename)
c->cft.root = (struct config_node *) NULL;
c->timestamp = 0;
c->exists = 0;
c->keep_open = keep_open;
c->dev = 0;
if (filename)
c->filename = dm_pool_strdup(c->mem, filename);
return &c->cft;
@@ -122,7 +126,12 @@ struct config_tree *create_config_tree(const char *filename)
void destroy_config_tree(struct config_tree *cft)
{
dm_pool_destroy(((struct cs *) cft)->mem);
struct cs *c = (struct cs *) cft;
if (c->dev)
dev_close(c->dev);
dm_pool_destroy(c->mem);
}
static int _parse_config_file(struct parser *p, struct config_tree *cft)
@@ -143,7 +152,7 @@ struct config_tree *create_config_tree_from_string(struct cmd_context *cmd,
struct config_tree *cft;
struct parser *p;
if (!(cft = create_config_tree(NULL)))
if (!(cft = create_config_tree(NULL, 0)))
return_NULL;
c = (struct cs *) cft;
@@ -250,7 +259,6 @@ int read_config_file(struct config_tree *cft)
{
struct cs *c = (struct cs *) cft;
struct stat info;
struct device *dev;
int r = 1;
if (stat(c->filename, &info)) {
@@ -272,22 +280,23 @@ int read_config_file(struct config_tree *cft)
return 1;
}
if (!(dev = dev_create_file(c->filename, NULL, NULL, 1))) {
stack;
return 0;
if (!c->dev) {
if (!(c->dev = dev_create_file(c->filename, NULL, NULL, 1)))
return_0;
if (!dev_open_flags(c->dev, O_RDONLY, 0, 0))
return_0;
}
if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
stack;
return 0;
}
r = read_config_fd(cft, dev, 0, (size_t) info.st_size, 0, 0,
r = read_config_fd(cft, c->dev, 0, (size_t) info.st_size, 0, 0,
(checksum_fn_t) NULL, 0);
dev_close(dev);
if (!c->keep_open) {
dev_close(c->dev);
c->dev = 0;
}
c->timestamp = info.st_mtime;
c->timestamp = info.st_ctime;
return r;
}
@@ -331,7 +340,7 @@ int config_file_changed(struct config_tree *cft)
}
/* Unchanged? */
if (c->timestamp == info.st_mtime)
if (c->timestamp == info.st_ctime)
return 0;
reload:
@@ -364,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;
@@ -377,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 */
@@ -402,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;
@@ -421,9 +433,22 @@ 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 configuration");
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 configuration");
r = 0;
}
} else {
log_error("Configuration node %s not found", *argv);
r = 0;
}
argv++;
}
if (fp != stdout)
@@ -763,6 +788,7 @@ static struct config_node *_find_config_node(const struct config_node *cn,
const char *path)
{
const char *e;
const struct config_node *cn_found = NULL;
while (cn) {
/* trim any leading slashes */
@@ -773,22 +799,30 @@ static struct config_node *_find_config_node(const struct config_node *cn,
for (e = path; *e && (*e != sep); e++) ;
/* hunt for the node */
cn_found = NULL;
while (cn) {
if (_tok_match(cn->key, path, e))
break;
if (_tok_match(cn->key, path, e)) {
/* Inefficient */
if (!cn_found)
cn_found = cn;
else
log_error("WARNING: Ignoring duplicate"
" config node: %s ("
"seeking %s)", cn->key, path);
}
cn = cn->sib;
}
if (cn && *e)
cn = cn->child;
if (cn_found && *e)
cn = cn_found->child;
else
break; /* don't move into the last node */
path = e;
}
return (struct config_node *) cn;
return (struct config_node *) cn_found;
}
static struct config_node *_find_first_config_node(const struct config_node *cn1,

View File

@@ -53,7 +53,7 @@ struct config_tree_list {
struct config_tree *cft;
};
struct config_tree *create_config_tree(const char *filename);
struct config_tree *create_config_tree(const char *filename, int keep_open);
struct config_tree *create_config_tree_from_string(struct cmd_context *cmd,
const char *config_settings);
void destroy_config_tree(struct config_tree *cft);
@@ -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,

View File

@@ -605,7 +605,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;

View File

@@ -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,7 +70,7 @@ 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);
for (p = 0; p < 4; p++, part++) {

View File

@@ -82,6 +82,12 @@ uint64_t units_to_bytes(const char *units, char *unit_type)
case 't':
v *= KILO * KILO * KILO * KILO;
break;
case 'p':
v *= KILO * KILO * KILO * KILO * KILO;
break;
case 'e':
v *= KILO * KILO * KILO * KILO * KILO * KILO;
break;
#undef KILO
#define KILO UINT64_C(1000)
case 'K':
@@ -96,6 +102,12 @@ uint64_t units_to_bytes(const char *units, char *unit_type)
case 'T':
v *= KILO * KILO * KILO * KILO;
break;
case 'P':
v *= KILO * KILO * KILO * KILO * KILO;
break;
case 'E':
v *= KILO * KILO * KILO * KILO * KILO * KILO;
break;
#undef KILO
default:
return 0;
@@ -143,6 +155,8 @@ static const char *_display_size(struct cmd_context *cmd, uint64_t size, size_le
uint64_t units = UINT64_C(1024);
char *size_buf = NULL;
const char *size_str[][3] = {
{" Exabyte", " EB", "E"},
{" Petabyte", " PB", "P"},
{" Terabyte", " TB", "T"},
{" Gigabyte", " GB", "G"},
{" Megabyte", " MB", "M"},
@@ -161,7 +175,7 @@ static const char *_display_size(struct cmd_context *cmd, uint64_t size, size_le
suffix = cmd->current_settings.suffix;
for (s = 0; s < 8; s++)
for (s = 0; s < 10; s++)
if (toupper((int) cmd->current_settings.unit_type) ==
*size_str[s][2])
break;
@@ -171,7 +185,7 @@ static const char *_display_size(struct cmd_context *cmd, uint64_t size, size_le
return size_buf;
}
if (s < 8) {
if (s < 10) {
byte = cmd->current_settings.unit_factor;
size *= UINT64_C(512);
} else {
@@ -181,7 +195,7 @@ static const char *_display_size(struct cmd_context *cmd, uint64_t size, size_le
units = UINT64_C(1000);
else
units = UINT64_C(1024);
byte = units * units * units;
byte = units * units * units * units * units;
s = 0;
while (size_str[s] && size < byte)
s++, byte /= units;
@@ -220,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;
@@ -248,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;
@@ -310,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;
@@ -357,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; */
@@ -523,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);
@@ -602,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);

View File

@@ -50,7 +50,7 @@ static int _errseg_add_target_line(struct dev_manager *dm __attribute((unused)),
return dm_tree_node_add_error_target(node, len);
}
static int _errseg_target_present(void)
static int _errseg_target_present(const struct lv_segment *seg __attribute((unused)))
{
static int _errseg_checked = 0;
static int _errseg_present = 0;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -17,6 +17,7 @@
#include "config.h"
#include "dev-cache.h"
#include "filter-persistent.h"
#include "lvm-file.h"
#include <sys/stat.h>
#include <fcntl.h>
@@ -26,11 +27,12 @@ struct pfilter {
char *file;
struct dm_hash_table *devices;
struct dev_filter *real;
time_t ctime;
};
/*
* entries in the table can be in one of these
* states.
* The hash table holds one of these two states
* against each entry.
*/
#define PF_BAD_DEVICE ((void *) 1)
#define PF_GOOD_DEVICE ((void *) 2)
@@ -93,22 +95,26 @@ static int _read_array(struct pfilter *pf, struct config_tree *cft,
return 1;
}
int persistent_filter_load(struct dev_filter *f)
int persistent_filter_load(struct dev_filter *f, struct config_tree **cft_out)
{
struct pfilter *pf = (struct pfilter *) f->private;
int r = 0;
struct config_tree *cft;
struct stat info;
int r = 0;
if (!(cft = create_config_tree(pf->file))) {
stack;
return 0;
if (!stat(pf->file, &info))
pf->ctime = info.st_ctime;
else {
log_very_verbose("%s: stat failed: %s", pf->file,
strerror(errno));
return_0;
}
if (!read_config_file(cft)) {
stack;
goto out;
}
if (!(cft = create_config_tree(pf->file, 1)))
return_0;
if (!read_config_file(cft))
goto_out;
_read_array(pf, cft, "persistent_filter_cache/valid_devices",
PF_GOOD_DEVICE);
@@ -126,7 +132,10 @@ int persistent_filter_load(struct dev_filter *f)
log_very_verbose("Loaded persistent filter cache from %s", pf->file);
out:
destroy_config_tree(cft);
if (r && cft_out)
*cft_out = cft;
else
destroy_config_tree(cft);
return r;
}
@@ -163,8 +172,12 @@ static void _write_array(struct pfilter *pf, FILE *fp, const char *path,
int persistent_filter_dump(struct dev_filter *f)
{
struct pfilter *pf = (struct pfilter *) f->private;
char *tmp_file;
struct stat info, info2;
struct config_tree *cft = NULL;
FILE *fp;
int lockfd;
int r = 0;
if (!dm_hash_get_num_entries(pf->devices)) {
log_very_verbose("Internal persistent device cache empty "
@@ -179,11 +192,43 @@ int persistent_filter_dump(struct dev_filter *f)
log_very_verbose("Dumping persistent device cache to %s", pf->file);
fp = fopen(pf->file, "w");
if (!fp) {
if (errno != EROFS)
log_sys_error("fopen", pf->file);
return 0;
while (1) {
if ((lockfd = fcntl_lock_file(pf->file, F_WRLCK, 0)) < 0)
return_0;
/*
* Ensure we locked the file we expected
*/
if (fstat(lockfd, &info)) {
log_sys_error("fstat", pf->file);
goto out;
}
if (stat(pf->file, &info2)) {
log_sys_error("stat", pf->file);
goto out;
}
if (!memcmp(&info.st_ino, &info2.st_ino, sizeof(ino_t)))
break;
fcntl_unlock_file(lockfd);
}
/*
* If file contents changed since we loaded it, merge new contents
*/
if (info.st_ctime != pf->ctime)
/* Keep cft open to avoid losing lock */
persistent_filter_load(f, &cft);
tmp_file = alloca(strlen(pf->file) + 5);
sprintf(tmp_file, "%s.tmp", pf->file);
if (!(fp = fopen(tmp_file, "w"))) {
/* EACCES has been reported over NFS */
if (errno != EROFS && errno != EACCES)
log_sys_error("fopen", tmp_file);
goto out;
}
fprintf(fp, "# This file is automatically maintained by lvm.\n\n");
@@ -195,7 +240,20 @@ int persistent_filter_dump(struct dev_filter *f)
fprintf(fp, "}\n");
fclose(fp);
return 1;
if (rename(tmp_file, pf->file))
log_error("%s: rename to %s failed: %s", tmp_file, pf->file,
strerror(errno));
r = 1;
out:
fcntl_unlock_file(lockfd);
if (cft)
destroy_config_tree(cft);
return r;
}
static int _lookup_p(struct dev_filter *f, struct device *dev)

View File

@@ -22,7 +22,7 @@ struct dev_filter *persistent_filter_create(struct dev_filter *f,
const char *file);
int persistent_filter_wipe(struct dev_filter *f);
int persistent_filter_load(struct dev_filter *f);
int persistent_filter_load(struct dev_filter *f, struct config_tree **cft_out);
int persistent_filter_dump(struct dev_filter *f);
#endif

View File

@@ -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;

View File

@@ -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)));
};
/*
@@ -203,8 +203,8 @@ int write_disks(const struct format_type *fmt, struct list *pvds);
* Functions to translate to between disk and in
* core structures.
*/
int import_pv(struct dm_pool *mem, struct device *dev,
struct volume_group *vg,
int import_pv(const struct format_type *fmt, struct dm_pool *mem,
struct device *dev, struct volume_group *vg,
struct physical_volume *pv, struct pv_disk *pvd,
struct vg_disk *vgd);
int export_pv(struct cmd_context *cmd, struct dm_pool *mem,

View File

@@ -312,7 +312,7 @@ static int _format1_pv_read(const struct format_type *fmt, const char *pv_name,
goto out;
}
if (!import_pv(fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd, &dl->vgd)) {
if (!import_pv(fmt, fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd, &dl->vgd)) {
stack;
goto out;
}

View File

@@ -24,6 +24,7 @@
#include "toolcontext.h"
#include "segtype.h"
#include "pv_alloc.h"
#include "display.h"
#include <time.h>
@@ -47,11 +48,13 @@ static char *_create_lv_name(struct dm_pool *mem, const char *full_name)
return dm_pool_strdup(mem, ptr);
}
int import_pv(struct dm_pool *mem, struct device *dev,
struct volume_group *vg,
int import_pv(const struct format_type *fmt, struct dm_pool *mem,
struct device *dev, struct volume_group *vg,
struct physical_volume *pv, struct pv_disk *pvd,
struct vg_disk *vgd)
{
uint64_t size;
memset(pv, 0, sizeof(*pv));
memcpy(&pv->id, pvd->pv_uuid, ID_LEN);
@@ -89,6 +92,25 @@ int import_pv(struct dm_pool *mem, struct device *dev,
pv->pe_count = pvd->pe_total;
pv->pe_alloc_count = 0;
/* Fix up pv size if missing */
if (!pv->size) {
if (!dev_get_size(dev, &pv->size)) {
log_error("%s: Couldn't get size.", dev_name(pv->dev));
return 0;
}
log_verbose("Fixing up missing format1 size (%s) "
"for PV %s", display_size(fmt->cmd, pv->size),
dev_name(pv->dev));
if (vg) {
size = pv->pe_count * (uint64_t) vg->extent_size +
pv->pe_start;
if (size > pv->size)
log_error("WARNING: Physical Volume %s is too "
"large for underlying device",
dev_name(pv->dev));
}
}
list_init(&pv->tags);
list_init(&pv->segments);
@@ -427,7 +449,7 @@ int import_pvs(const struct format_type *fmt, struct dm_pool *mem,
return 0;
}
if (!import_pv(mem, dl->dev, vg, pvl->pv, &dl->pvd, &dl->vgd)) {
if (!import_pv(fmt, mem, dl->dev, vg, pvl->pv, &dl->pvd, &dl->vgd)) {
stack;
return 0;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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,

View File

@@ -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;

View File

@@ -221,6 +221,8 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
"Megabytes",
"Gigabytes",
"Terabytes",
"Petabytes",
"Exabytes",
NULL
};

View File

@@ -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;
@@ -885,8 +888,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 +1134,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;
@@ -1408,6 +1411,7 @@ static int _text_pv_setup(const struct format_type *fmt,
uint64_t pe_end = 0;
unsigned mda_count = 0;
uint64_t mda_size2 = 0;
uint64_t pe_count;
/* FIXME Cope with pvchange */
/* FIXME Merge code with _text_create_text_instance */
@@ -1473,8 +1477,17 @@ static int _text_pv_setup(const struct format_type *fmt,
pv->pe_start + mda_size2;
/* Recalculate number of extents that will fit */
if (!pv->pe_count)
pv->pe_count = (pv->size - pv->pe_start - mda_size2) / vg->extent_size;
if (!pv->pe_count) {
pe_count = (pv->size - pv->pe_start - mda_size2) /
vg->extent_size;
if (pe_count > UINT32_MAX) {
log_error("PV %s too large for extent size %s.",
dev_name(pv->dev),
display_size(vg->cmd, (uint64_t) vg->extent_size));
return 0;
}
pv->pe_count = (uint32_t) pe_count;
}
/* Unlike LVM1, we don't store this outside a VG */
/* FIXME Default from config file? vgextend cmdline flag? */
@@ -1732,7 +1745,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.");

View File

@@ -43,7 +43,7 @@ const char *text_vgname_import(const struct format_type *fmt,
_text_import_initialised = 1;
}
if (!(cft = create_config_tree(NULL)))
if (!(cft = create_config_tree(NULL, 0)))
return_NULL;
if ((!dev && !read_config_file(cft)) ||
@@ -94,7 +94,7 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
*desc = NULL;
*when = 0;
if (!(cft = create_config_tree(file)))
if (!(cft = create_config_tree(file, 0)))
return_NULL;
if ((!dev && !read_config_file(cft)) ||

View File

@@ -116,6 +116,7 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
struct physical_volume *pv;
struct pv_list *pvl;
struct config_node *cn;
uint64_t size;
if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl))) ||
!(pvl->pv = dm_pool_zalloc(mem, sizeof(*pvl->pv)))) {
@@ -148,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.");
@@ -213,6 +214,25 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
pv->pe_alloc_count = 0;
pv->fmt = fid->fmt;
/* Fix up pv size if missing */
if (!pv->size && pv->dev) {
if (!dev_get_size(pv->dev, &pv->size)) {
log_error("%s: Couldn't get size.", dev_name(pv->dev));
return 0;
}
log_verbose("Fixing up missing format1 size (%s) "
"for PV %s", display_size(fid->fmt->cmd, pv->size),
dev_name(pv->dev));
if (vg) {
size = pv->pe_count * (uint64_t) vg->extent_size +
pv->pe_start;
if (size > pv->size)
log_error("WARNING: Physical Volume %s is too "
"large for underlying device",
dev_name(pv->dev));
}
}
if (!alloc_pv_segment_whole_pv(mem, pv)) {
stack;
return 0;

View File

@@ -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;

View File

@@ -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,19 +341,17 @@ 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;
if (!dev_open(dev)) {
stack;
if ((info = info_from_pvid(dev->pvid)))
lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN,
0, NULL);
goto out;
return_0;
}
if (!(l = _find_labeller(dev, buf, &sector)))

View File

@@ -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.

View File

@@ -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;
}
@@ -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;

View File

@@ -144,18 +144,18 @@ int init_locking(int type, struct cmd_context *cmd)
case 2:
if (!cmd->is_static) {
log_very_verbose("External locking selected.");
if (!init_external_locking(&_locking, cmd))
break;
return 1;
if (init_external_locking(&_locking, cmd))
return 1;
}
if (!find_config_tree_int(cmd, "locking/fallback_to_clustered_locking",
DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING))
break;
log_very_verbose("Falling back to clustered locking.");
/* Fall through */
#endif
#ifdef CLUSTER_LOCKING_INTERNAL
log_very_verbose("Falling back to internal clustered locking.");
/* Fall through */
case 3:
log_very_verbose("Cluster locking selected.");
if (!init_cluster_locking(&_locking, cmd))
@@ -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:

View File

@@ -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 */

View File

@@ -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;
@@ -890,8 +899,17 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
uint32_t next_le;
struct seg_pvs *spvs;
struct list *parallel_pvs;
uint32_t free_pes;
/* Is there enough total space? */
free_pes = pv_maps_size(pvms);
if (needed - *allocated > free_pes) {
log_error("Insufficient free space: %" PRIu32 " extents needed,"
" but only %" PRIu32 " available",
needed - *allocated, free_pes);
return 0;
}
/* FIXME Do calculations on free extent counts before selecting space */
/* FIXME Select log PV appropriately if there isn't one yet */
/* Are there any preceding segments we must follow on from? */
@@ -1057,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!");
@@ -1102,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",
@@ -1156,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:
@@ -1499,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 "

View File

@@ -23,6 +23,7 @@
#include "str_list.h"
#include "pv_alloc.h"
#include "activate.h"
#include "display.h"
#include <sys/param.h>
@@ -122,6 +123,15 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
pvl->pv = pv;
list_add(&vg->pvs, &pvl->list);
if ((uint64_t) vg->extent_count + pv->pe_count > UINT32_MAX) {
log_error("Unable to add %s to %s: new extent count (%"
PRIu64 ") exceeds limit (%" PRIu32 ").",
pv_name, vg->name,
(uint64_t) vg->extent_count + pv->pe_count,
UINT32_MAX);
return 0;
}
vg->pv_count++;
vg->extent_count += pv->pe_count;
vg->free_count += pv->pe_count;
@@ -728,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 */

View File

@@ -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;
@@ -285,7 +286,7 @@ struct logical_volume {
int32_t major;
int32_t minor;
uint64_t size;
uint64_t size; /* Sectors */
uint32_t le_count;
uint32_t origin_count;

View File

@@ -36,20 +36,20 @@ struct lv_segment *find_mirror_seg(struct lv_segment *seg)
}
/*
* Ensure region size is compatible with volume size.
* Reduce the region size if necessary to ensure
* the volume size is a multiple of the region size.
*/
uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
uint32_t region_size)
{
uint32_t region_max;
uint64_t region_max;
region_max = (1 << (ffs((int)extents) - 1)) * extent_size;
region_max = (1 << (ffs((int)extents) - 1)) * (uint64_t) extent_size;
if (region_max < region_size) {
region_size = region_max;
if (region_max < UINT32_MAX && region_size > region_max) {
region_size = (uint32_t) region_max;
log_print("Using reduced mirror region size of %" PRIu32
" sectors", region_max);
return region_max;
" sectors", region_size);
}
return region_size;
@@ -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;
@@ -562,7 +567,7 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
}
if (activation() && segtype->ops->target_present &&
!segtype->ops->target_present()) {
!segtype->ops->target_present(NULL)) {
log_error("%s: Required device-mapper target(s) not "
"detected in your kernel", segtype->name);
return 0;

View File

@@ -19,6 +19,8 @@
/*
* Areas are maintained in size order, largest first.
*
* FIXME Cope with overlap.
*/
static void _insert_area(struct list *head, struct pv_area *a)
{
@@ -30,6 +32,7 @@ static void _insert_area(struct list *head, struct pv_area *a)
}
list_add(&pva->list, &a->list);
a->map->pe_count += a->count;
}
static int _create_single_area(struct dm_pool *mem, struct pv_map *pvm,
@@ -126,23 +129,32 @@ static int _create_all_areas_for_pv(struct dm_pool *mem, struct pv_map *pvm,
static int _create_maps(struct dm_pool *mem, struct list *pvs, struct list *pvms)
{
struct pv_map *pvm;
struct pv_map *pvm, *pvm2;
struct pv_list *pvl;
list_iterate_items(pvl, pvs) {
if (!(pvl->pv->status & ALLOCATABLE_PV))
continue;
if (!(pvm = dm_pool_zalloc(mem, sizeof(*pvm)))) {
stack;
return 0;
pvm = NULL;
list_iterate_items(pvm2, pvms)
if (pvm2->pv->dev == pvl->pv->dev) {
pvm = pvm2;
break;
}
if (!pvm) {
if (!(pvm = dm_pool_zalloc(mem, sizeof(*pvm)))) {
stack;
return 0;
}
pvm->pv = pvl->pv;
list_init(&pvm->areas);
list_add(pvms, &pvm->list);
}
pvm->pv = pvl->pv;
list_init(&pvm->areas);
list_add(pvms, &pvm->list);
if (!_create_all_areas_for_pv(mem, pvm, pvl->pe_ranges)) {
stack;
return 0;
@@ -180,6 +192,7 @@ struct list *create_pv_maps(struct dm_pool *mem, struct volume_group *vg,
void consume_pv_area(struct pv_area *pva, uint32_t to_go)
{
list_del(&pva->list);
pva->map->pe_count -= pva->count;
assert(to_go <= pva->count);
@@ -190,3 +203,14 @@ void consume_pv_area(struct pv_area *pva, uint32_t to_go)
_insert_area(&pva->map->areas, pva);
}
}
uint32_t pv_maps_size(struct list *pvms)
{
struct pv_map *pvm;
uint32_t pe_count = 0;
list_iterate_items(pvm, pvms)
pe_count += pvm->pe_count;
return pe_count;
}

View File

@@ -37,6 +37,7 @@ struct pv_area {
struct pv_map {
struct physical_volume *pv;
struct list areas; /* struct pv_areas */
uint32_t pe_count; /* Total number of PEs */
struct list list;
};
@@ -49,4 +50,6 @@ struct list *create_pv_maps(struct dm_pool *mem, struct volume_group *vg,
void consume_pv_area(struct pv_area *area, uint32_t to_go);
uint32_t pv_maps_size(struct list *pvms);
#endif

View File

@@ -76,7 +76,7 @@ struct segtype_handler {
struct lv_segment *seg, char *params,
uint64_t *total_numerator,
uint64_t *total_denominator, float *percent);
int (*target_present) (void);
int (*target_present) (const struct lv_segment *seg);
int (*modules_needed) (struct dm_pool *mem,
const struct lv_segment *seg,
struct list *modules);

View File

@@ -336,7 +336,7 @@ static int _mirrored_add_target_line(struct dev_manager *dm, struct dm_pool *mem
return add_areas_line(dm, seg, node, start_area, area_count);
}
static int _mirrored_target_present(void)
static int _mirrored_target_present(const struct lv_segment *seg __attribute((unused)))
{
static int _mirrored_checked = 0;
static int _mirrored_present = 0;
@@ -397,6 +397,7 @@ static int _target_register_events(struct lv_segment *seg,
char *dso, *name;
struct logical_volume *lv;
struct volume_group *vg;
struct dm_event_handler *handler;
lv = seg->lv;
vg = lv->vg;
@@ -409,10 +410,18 @@ static int _target_register_events(struct lv_segment *seg,
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 (!(handler = dm_event_handler_create()))
return_0;
dm_event_handler_set_dso(handler, dso);
dm_event_handler_set_name(handler, name);
dm_event_handler_set_events(handler, DM_EVENT_ALL_ERRORS);
if (!dm_event_register(handler)) {
dm_event_handler_destroy(handler);
return_0;
}
dm_event_handler_destroy(handler);
log_info("Registered %s for events", name);
return 1;
@@ -425,6 +434,7 @@ static int _target_unregister_events(struct lv_segment *seg,
char *name;
struct logical_volume *lv;
struct volume_group *vg;
struct dm_event_handler *handler;
lv = seg->lv;
vg = lv->vg;
@@ -436,10 +446,18 @@ static int _target_unregister_events(struct lv_segment *seg,
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))
if (!(handler = dm_event_handler_create()))
return_0;
dm_event_handler_set_dso(handler, dso);
dm_event_handler_set_name(handler, name);
dm_event_handler_set_events(handler, DM_EVENT_ALL_ERRORS);
if (!dm_event_unregister(handler)) {
dm_event_handler_destroy(handler);
return_0;
}
dm_event_handler_destroy(handler);
log_info("Unregistered %s for events", name);
return 1;

View File

@@ -244,3 +244,61 @@ void sync_dir(const char *file)
out:
dm_free(dir);
}
/*
* Attempt to obtain fcntl lock on a file, if necessary creating file first
* or waiting.
* Returns file descriptor on success, else -1.
* mode is F_WRLCK or F_RDLCK
*/
int fcntl_lock_file(const char *file, short lock_type, int warn_if_read_only)
{
int lockfd;
struct flock lock = {
.l_type = lock_type,
.l_whence = 0,
.l_start = 0,
.l_len = 0
};
log_very_verbose("Locking %s (%s, %hd)", file,
(lock_type == F_WRLCK) ? "F_WRLCK" : "F_RDLCK",
lock_type);
if ((lockfd = open(file, O_RDWR | O_CREAT, 0777)) < 0) {
/* EACCES has been reported on NFS */
if (warn_if_read_only || (errno != EROFS && errno != EACCES))
log_sys_error("open", file);
else
stack;
return -1;
}
if (fcntl(lockfd, F_SETLKW, &lock)) {
log_sys_error("fcntl", file);
return -1;
}
return lockfd;
}
void fcntl_unlock_file(int lockfd)
{
struct flock lock = {
.l_type = F_UNLCK,
.l_whence = 0,
.l_start = 0,
.l_len = 0
};
log_very_verbose("Unlocking fd %d", lockfd);
if (fcntl(lockfd, F_SETLK, &lock) == -1)
log_error("fcntl unlock failed on fd %d: %s", lockfd,
strerror(errno));
if (close(lockfd))
log_error("lock file close failed on fd %d: %s", lockfd,
strerror(errno));
}

View File

@@ -48,4 +48,8 @@ int create_dir(const char *dir);
/* Sync directory changes */
void sync_dir(const char *file);
/* fcntl locking wrappers */
int fcntl_lock_file(const char *file, short lock_type, int warn_if_read_only);
void fcntl_unlock_file(int lockfd);
#endif

View File

@@ -112,7 +112,7 @@ static int _snap_target_percent(void **target_state __attribute((unused)),
return 1;
}
static int _snap_target_present(void)
static int _snap_target_present(const struct lv_segment *seg __attribute((unused)))
{
static int _snap_checked = 0;
static int _snap_present = 0;

View File

@@ -174,7 +174,7 @@ static int _striped_add_target_line(struct dev_manager *dm,
return add_areas_line(dm, seg, node, 0u, seg->area_count);
}
static int _striped_target_present(void)
static int _striped_target_present(const struct lv_segment *seg __attribute((unused)))
{
static int _striped_checked = 0;
static int _striped_present = 0;

View File

@@ -49,7 +49,7 @@ static int _zero_add_target_line(struct dev_manager *dm __attribute((unused)),
return dm_tree_node_add_zero_target(node, len);
}
static int _zero_target_present(void)
static int _zero_target_present(const struct lv_segment *seg __attribute((unused)))
{
static int _zero_checked = 0;
static int _zero_present = 0;

View File

@@ -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,5 @@ dm_task_set_geometry
dm_split_lvm_name
dm_split_words
dm_snprintf
dm_basename
dm_saprintf

View File

@@ -38,8 +38,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

View File

@@ -1506,6 +1506,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)) ||

View File

@@ -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,15 @@ 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.
*/
int dm_saprintf(char **buf, const char *format, ...);
#endif /* LIB_DEVICE_MAPPER_H */

View File

@@ -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);

View File

@@ -121,3 +121,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_saprintf(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;
}

View File

@@ -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) $@

View File

@@ -18,8 +18,8 @@ VPATH = @srcdir@
MAN5=lvm.conf.5
MAN8=lvchange.8 lvconvert.8 lvcreate.8 lvdisplay.8 lvextend.8 lvm.8 \
lvmchange.8 \
lvmdiskscan.8 lvreduce.8 lvremove.8 lvrename.8 lvresize.8 lvs.8 \
lvmchange.8 lvmdiskscan.8 lvmdump.8 \
lvreduce.8 lvremove.8 lvrename.8 lvresize.8 lvs.8 \
lvscan.8 pvchange.8 pvcreate.8 pvdisplay.8 pvmove.8 pvremove.8 \
pvresize.8 pvs.8 pvscan.8 vgcfgbackup.8 vgcfgrestore.8 vgchange.8 \
vgck.8 vgcreate.8 vgconvert.8 vgdisplay.8 vgexport.8 vgextend.8 \

View File

@@ -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

View File

@@ -30,6 +30,9 @@ dmsetup \- low level logical volume management
.B dmsetup rename
.I device_name new_name
.br
.B dmsetup message
.I device_name sector message
.br
.B dmsetup ls [--target target_type] [--exec command] [--tree [-o options]]
.br
.B dmsetup info
@@ -58,6 +61,9 @@ dmsetup \- low level logical volume management
.br
.B dmsetup version
.br
.B dmsetup setgeometry
.I device_name cyl head sect start
.br
.B devmap_name
.I major minor
@@ -167,6 +173,10 @@ ascii, utf, vt100; compact, inverted, notrunc.
.br
Loads <table> or table_file into the inactive table slot for device_name.
If neither is supplied, reads a table from standard input.
.IP \fBmessage
.I device_name sector message
.br
Send message to target. If sector not needed use 0.
.IP \fBmknodes
.I [device_name]
.br
@@ -205,6 +215,10 @@ Renames a device.
Un-suspends a device.
If an inactive table has been loaded, it becomes live.
Postponed I/O then gets re-queued for processing.
.IP \fBsetgeometry
.I device_name cyl head sect start
.br
Sets the device geometry to C/H/S.
.IP \fBstatus
.I [--target target_type]
.I [device_name]

View File

@@ -7,6 +7,7 @@ lvchange \- change attributes of a logical volume
[\-A/\-\-autobackup y/n] [\-a/\-\-available y/n/ey/en/ly/ln]
[\-\-alloc AllocationPolicy]
[\-C/\-\-contiguous y/n] [\-d/\-\-debug] [\-\-deltag Tag]
[\-\-resync]
[\-h/\-?/\-\-help]
[\-\-ignorelockingfailure]
[\-\-monitor {y|n}]
@@ -40,6 +41,14 @@ logical volumes. It's only possible to change a non-contiguous
logical volume's allocation policy to contiguous, if all of the
allocated physical extents are already contiguous.
.TP
.I \-\-resync
Forces the complete resynchronization of a mirror. In normal
circumstances you should not need this option because synchronization
happens automatically. Data is read from the primary mirror device
and copied to the others, so this can take a considerable amount of
time - and during this time you are without a complete redundant copy
of your data.
.TP
.I \-\-minor minor
Set the minor number.
.TP

View File

@@ -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),

View File

@@ -70,10 +70,11 @@ This can also be expressed as a percentage of the total space
in the Volume Group with the suffix %VG or of the remaining free space
with the suffix %FREE.
.TP
.I \-L, \-\-size LogicalVolumeSize[kKmMgGtT]
.I \-L, \-\-size LogicalVolumeSize[kKmMgGtTpPeE]
Gives the size to allocate for the new logical volume.
A size suffix of K for kilobytes, M for megabytes,
G for gigabytes or T for terabytes is optional.
G for gigabytes, T for terabytes, P for petabytes
or E for exabytes is optional.
.br
Default unit is megabytes.
.TP
@@ -138,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

View File

@@ -30,10 +30,12 @@ in the Volume Group with the suffix %VG or relative to the existing
size of the Logical Volume with the suffix %LV or as a percentage of the remaining
free space in the Volume Group with the suffix %FREE.
.TP
.I \-L, \-\-size [+]LogicalVolumeSize[kKmMgGtT]
Extend or set the logical volume size in units in units of megabytes.
A size suffix of M for megabytes, G for gigabytes or T for terabytes is
optional. With the + sign the value is added to the actual size
.I \-L, \-\-size [+]LogicalVolumeSize[kKmMgGtTpPeE]
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.
With the + sign the value is added to the actual size
of the logical volume and without it, the value is taken as an absolute one.
.TP
.I \-i, \-\-stripes Stripes

50
man/lvmdump.8 Normal file
View File

@@ -0,0 +1,50 @@
.TH LVMDUMP "8" "" "Red Hat, Inc."
.SH NAME
lvmdump - create lvm2 information dumps for diagnostic purposes
.SH SYNOPSIS
\fBlvmdump\fP [options] [-d directory]
.SH DESCRIPTION
\fBlvmdump\fP is a tool to dump various information concerning LVM2. By default, it creates a tarball suitable for submission along with a problem report.
.PP
The content of the tarball is as follows:
.br
- dmsetup info
.br
- table of currently running processes
.br
- recent entries from /var/log/messages (containing system messages)
.br
- complete lvm configuration and cache
.br
- list of device nodes present under /dev
.br
- if enabled with -m, metadata dump will be also included
.br
- if enabled with -a, debug output of vgscan, pvscan and list of all available volume groups, physical volumes and logical volumes will be included
.br
- if enabled with -c, cluster status info
.SH OPTIONS
.TP
\fB\-h\fR \(em print help message
.TP
\fB\-a\fR \(em advanced collection
\fBWARNING\fR: if lvm is already hung, then this script may hang as well if \fB\-a\fR is used
.TP
\fB\-m\fR \(em gather LVM metadata from the PVs
This option generates a 1:1 dump of the metadata area from all PVs visible to the system, which can cause the dump to increase in size considerably. However, the metadata dump may represent a valuable diagnostic resource.
.TP
\fB\-d\fR directory \(em dump into a directory instead of tarball
By default, lvmdump will produce a single compressed tarball containing all the information. Using this option, it can be instructed to only produce the raw dump tree, rooted in \fBdirectory\fP.
.TP
\fB\-c\fR \(em if clvmd is running, gather cluster data as well
.SH ENVIRONMENT VARIABLES
.TP
\fBLVM_BINARY\fP
The LVM2 binary to use.
Defaults to "lvm".
Sometimes you might need to set this to "/sbin/lvm.static", for example.
.TP
\fBDMSETUP_BINARY\fP
The dmsetup binary to use.
Defaults to "dmsetup".
.PP

View File

@@ -46,10 +46,11 @@ in the Volume Group with the suffix %VG or relative to the existing
size of the Logical Volume with the suffix %LV or as a percentage of the remaining
free space in the Volume Group with the suffix %FREE.
.TP
.I \-L, \-\-size [\-]LogicalVolumeSize[kKmMgGtT]
.I \-L, \-\-size [\-]LogicalVolumeSize[kKmMgGtTpPeE]
Reduce or set the logical volume size in units of megabyte by default.
A size suffix of k for kilobyte, m for megabyte, g for gigabyte or
t for terabyte is optional.
A size suffix of k for kilobyte, m for megabyte,
g for gigabytes, t for terabytes, p for petabytes
or e for exabytes is optional.
With the - sign the value will be subtracted from
the logical volume's actual size and without it it will be taken as
an absolute size.

View File

@@ -12,6 +12,10 @@ lvremove \- remove a logical volume
Confirmation will be requested before deactivating any active logical
volume prior to removal. Logical volumes cannot be deactivated
or removed while they are open (e.g. if they contain a mounted filesystem).
.sp
If the logical volume is clustered then it must be deactivated on all
nodes in the cluster before it can be removed. A single lvchange command
issued from one node can do this.
.SH OPTIONS
See \fBlvm\fP(8) for common options.
.TP
@@ -28,7 +32,8 @@ Remove all logical volumes in volume group vg00:
\ \fBlvremove vg00\fP
.SH SEE ALSO
.BR lvcreate (8),
.BR lvdisplay (8),
.BR lvdisplay (8),
.BR lvchange (8),
.BR lvm (8),
.BR lvs (8),
.BR lvscan (8),

View File

@@ -34,10 +34,12 @@ in the Volume Group with the suffix %VG or relative to the existing
size of the Logical Volume with the suffix %LV or as a percentage of the remaining
free space in the Volume Group with the suffix %FREE.
.TP
.I \-L, \-\-size [+/-]LogicalVolumeSize[kKmMgGtT]
.I \-L, \-\-size [+/-]LogicalVolumeSize[kKmMgGtTpPeE]
Change or set the logical volume size in units of megabytes.
A size suffix of M for megabytes, G for gigabytes or T for terabytes is
optional. With the + or - sign the value is added to or subtracted from
A size suffix of M for megabytes,
G for gigabytes, T for terabytes, P for petabytes
or E for exabytes is optional.
With the + or - sign the value is added to or subtracted from
the actual size of the logical volume and without it, the value is taken as an
absolute one.
.TP

23
scripts/Makefile.in Normal file
View File

@@ -0,0 +1,23 @@
#
# Copyright (C) 2006 Red Hat, Inc. All rights reserved.
#
# This file is part of the LVM2.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
include $(top_srcdir)/make.tmpl
install:
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) lvm_dump.sh \
$(sbindir)/lvmdump

View File

@@ -1,6 +1,6 @@
#!/bin/bash
#
# chkconfig: 345 24 76
# chkconfig: - 24 76
# description: Starts and stops clvmd
#
#
@@ -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 ]
@@ -73,7 +74,7 @@ stop()
done
else
# Hack to only deactivate clustered volumes
clustervgs=`$VGDISPLAY \`$VGS --noheadings -o name\` | awk 'BEGIN {RS="VG Name"} {if (/Clustered/) print $1;}'`
clustervgs=`$VGDISPLAY 2> /dev/null | awk 'BEGIN {RS="VG Name"} {if (/Clustered/) print $1;}'`
for vg in $clustervgs; do
if ! action "Deactivating VG $vg:" $VGCHANGE -anl $vg
then

View File

@@ -29,6 +29,8 @@
# PATH entries to /sbin/init shell script so chroot works without /usr mounted. Remove
# mkdir /initrd so we don't cause problems if root filesystem is corrupted. -- Jeff Layton
# 15/05/2004 initial support for modules, create lvm.conf from lvm dumpconfig, other cleanups -- Jeff Layton
# 14/11/2006 Update handling of ldd output to handle hardcoded library links and virtual dll linux-gate.
# Add support for Gentoo-style MAKEDEV. Remove hardcoded BINUTILS paths -- Douglas Mayle
#
# Copyright Miguel Cabeca, Jeffrey Layton, 2004
#
@@ -52,7 +54,7 @@ TMPMNT=/tmp/mnt.$$
DEVRAM=/tmp/initrd.$$
# set defaults
BINFILES=${BINFILES:-"/lib/lvm-200/lvm /bin/bash /bin/busybox /sbin/pivot_root"}
BINFILES=${BINFILES:-"`which lvm` `which bash` `which busybox` `which pivot_root`"}
BASICDEVICES=${BASICDEVICES:-"std consoleonly fd"}
BLOCKDEVICES=${BLOCKDEVICES:-"md hda hdb hdc hdd sda sdb sdc sdd"}
MAKEDEV=${MAKEDEV:-"debian"}
@@ -269,7 +271,27 @@ done
# Figure out which shared libraries we actually need in our initrd
echo "$cmd -- finding required shared libraries"
verbose "BINFILES: `echo $BINFILES`"
LIBFILES=`ldd $BINFILES 2>/dev/null | awk '{if (/=>/) { print $3 }}' | sort -u`
# We need to strip certain lines from ldd output. This is the full output of an example ldd:
#lvmhost~ # ldd /sbin/lvm /bin/bash
#/sbin/lvm:
# not a dynamic executable
#/bin/bash:
# linux-gate.so.1 => (0xbfffe000)
# libncurses.so.5 => /lib/libncurses.so.5 (0xb7ee3000)
# libdl.so.2 => /lib/libdl.so.2 (0xb7edf000)
# libc.so.6 => /lib/libc.so.6 (0xb7dc1000)
# /lib/ld-linux.so.2 (0xb7f28000)
#
# 1) Lines with a ":" contain the name of the original binary we're examining, and so are unnecessary.
# We need to strip them because they contain "/", and can be confused with links with a hardcoded path.
# 2) The linux-gate library is a virtual dll that does not exist on disk, but is instead loaded automatically
# into the process space, and can't be copied to the ramdisk
#
# After these lines have been stripped, we're interested in the lines remaining if they
# 1) Contain "=>" because they are pathless links, and the value following the token is the path on the disk
# 2) Contain "/" because it's a link with a hardcoded path, and so we're interested in the link itself.
LIBFILES=`ldd $BINFILES 2>/dev/null |grep -v -E \(linux-gate\|:\) | awk '{if (/=>/) { print $3 } else if (/\//) { print $1 }}' | sort -u`
if [ $? -ne 0 ]; then
echo "$cmd -- ERROR figuring out needed shared libraries"
exit 1
@@ -356,6 +378,10 @@ redhat)
(cd $TMPMNT/dev; /dev/MAKEDEV $OPT_Q -d $TMPMNT/dev -m 2)
RETCODE=$?
;;
gentoo)
(cd $TMPMNT/dev; /usr/sbin/MAKEDEV $OPT_Q $BASICDEVICES $BLOCKDEVICES)
RETCODE=$?
;;
*)
echo "$cmd -- ERROR: $MAKEDEV is not a known MAKEDEV style."
RETCODE=1

View File

@@ -1,8 +1,41 @@
#!/bin/bash
#
# we use some bash-isms (getopts?)
# lvm_dump: This script is used to collect pertinent information for
# the debugging of lvm issues.
#
# following external commands are used throughout the script
# which, echo and test are internal in bash at least
MKDIR=mkdir # need -p
TAR=tar # need czf
RM=rm # need -rf
CP=cp
TAIL=tail # we need -n
LS=ls # need -la
PS=ps # need alx
SED=sed
DD=dd
CUT=cut
DATE=date
BASENAME=basename
# user may override lvm and dmsetup location by setting LVM_BINARY
# and DMSETUP_BINARY respectively
LVM=${LVM_BINARY-lvm}
DMSETUP=${DMSETUP_BINARY-dmsetup}
die() {
code=$1; shift
echo "$@" 1>&2
exit $code
}
# which should error out if the binary is not executable, although i
# am not sure we can rely on this
which $LVM >& /dev/null || die 2 "Fatal: could not find lvm binary '$LVM'"
test -x `which $LVM` || die 2 "Fatal: lvm binary '$LVM' not executable"
which $DMSETUP >& /dev/null || die 2 "Fatal: could not find dmsetup binary '$DMSETUP'"
test -x `which $DMSETUP` || die 2 "Fatal: dmsetup binary '$DMSETUP' not executable"
function usage {
echo "$0 [options]"
@@ -10,7 +43,7 @@ function usage {
echo " -a advanced collection - warning: if lvm is already hung,"
echo " then this script may hang as well if -a is used"
echo " -m gather LVM metadata from the PVs"
echo " -d dump directory to place data in (default=/tmp/lvm_dump.\$\$)"
echo " -d <directory> dump into a directory instead of tarball"
echo " -c if running clvmd, gather cluster data as well"
echo ""
@@ -22,9 +55,10 @@ clustered=0
metadata=0
while getopts :acd:hm opt; do
case $opt in
s) sysreport=1 ;;
a) advanced=1 ;;
c) clustered=1 ;;
d) lvm_dir=$OPTARG ;;
d) userdir=$OPTARG ;;
h) usage ;;
m) metadata=1 ;;
:) echo "$0: $OPTARG requires a value:"; usage ;;
@@ -33,86 +67,119 @@ while getopts :acd:hm opt; do
esac
done
dir=`mktemp -d -p /tmp lvm_dump.XXXXXX` || exit 2
lvm_dir="$dir/lvm_dump"
NOW=`$DATE -u +%G%m%d%k%M%S | /usr/bin/tr -d ' '`
if test -n "$userdir"; then
dir="$userdir"
else
dirbase="lvmdump-$HOSTNAME-$NOW"
dir="$HOME/$dirbase"
fi
test -e $dir && die 3 "Fatal: $dir already exists"
$MKDIR -p $dir || die 4 "Fatal: could not create $dir"
log="$dir/lvmdump.log"
myecho() {
echo "$@"
echo "$@" >> $log
}
log() {
echo "$@" >> $log
eval "$@"
}
echo " "
echo "Creating dump directory: $lvm_dir"
myecho "Creating dump directory: $dir"
echo " "
mkdir -p $lvm_dir || exit 3
if (( $advanced )); then
echo "Gathering LVM volume info..."
myecho "Gathering LVM volume info..."
echo " vgscan..."
vgscan -vvvv > $lvm_dir/vgscan 2>&1
myecho " vgscan..."
log "$LVM vgscan -vvvv > $dir/vgscan 2>&1"
echo " pvscan..."
pvscan -v >> $lvm_dir/pvscan 2>/dev/null
myecho " pvscan..."
log "$LVM pvscan -v >> $dir/pvscan 2>> $log"
echo " lvs..."
lvs -a -o +devices >> $lvm_dir/lvs 2>/dev/null
myecho " lvs..."
log "$LVM lvs -a -o +devices >> $dir/lvs 2>> $log"
echo " pvs..."
pvs -a -v > $lvm_dir/pvs 2>/dev/null
myecho " pvs..."
log "$LVM pvs -a -v > $dir/pvs 2>> $log"
echo " vgs..."
vgs -v > $lvm_dir/vgs 2>/dev/null
log "$LVM vgs -v > $dir/vgs 2>> $log"
fi
if (( $clustered )); then
echo "Gathering cluster info..."
echo "STATUS: " > $lvm_dir/cluster_info
echo "----------------------------------" >> $lvm_dir/cluster_info
cman_tool status >> $lvm_dir/cluster_info
echo " " >> $lvm_dir/lvm_info
myecho "Gathering cluster info..."
echo "STATUS: " > $dir/cluster_info
echo "----------------------------------" >> $dir/cluster_info
log "cman_tool status >> $dir/cluster_info 2>> $log"
echo " " >> $dir/lvm_info
echo "SERVICES: " >> $lvm_dir/cluster_info
echo "----------------------------------" >> $lvm_dir/cluster_info
cman_tool services >> $lvm_dir/cluster_info
echo " " >> $lvm_dir/lvm_info
echo "SERVICES: " >> $dir/cluster_info
echo "----------------------------------" >> $dir/cluster_info
log "cman_tool services >> $dir/cluster_info 2>> $log"
echo " " >> $dir/lvm_info
fi
echo "Gathering LVM & device-mapper version info..."
echo "LVM VERSION:" > $lvm_dir/versions
lvs --version >> $lvm_dir/versions
echo "DEVICE MAPPER VERSION:" >> $lvm_dir/versions
dmsetup --version >> $lvm_dir/versions
myecho "Gathering LVM & device-mapper version info..."
echo "LVM VERSION:" > $dir/versions
$LVM lvs --version >> $dir/versions 2>> $log
echo "DEVICE MAPPER VERSION:" >> $dir/versions
$DMSETUP --version >> $dir/versions 2>> $log
echo "Gathering dmsetup info..."
dmsetup info -c > $lvm_dir/dmsetup_info
dmsetup table > $lvm_dir/dmsetup_table
dmsetup status > $lvm_dir/dmsetup_status
myecho "Gathering dmsetup info..."
log "$DMSETUP info -c > $dir/dmsetup_info 2>> $log"
log "$DMSETUP table > $dir/dmsetup_table 2>> $log"
log "$DMSETUP status > $dir/dmsetup_status 2>> $log"
echo "Gathering process info..."
ps alx > $lvm_dir/ps_info
myecho "Gathering process info..."
log "$PS alx > $dir/ps_info 2>> $log"
echo "Gathering console messages..."
tail -n 75 /var/log/messages > $lvm_dir/messages
myecho "Gathering console messages..."
log "$TAIL -n 75 /var/log/messages > $dir/messages 2>> $log"
echo "Gathering /etc/lvm info..."
cp -a /etc/lvm $lvm_dir/lvm
myecho "Gathering /etc/lvm info..."
log "$CP -a /etc/lvm $dir/lvm 2>> $log"
echo "Gathering /dev listing..."
ls -la /dev > $lvm_dir/dev_listing
myecho "Gathering /dev listing..."
log "$LS -la /dev > $dir/dev_listing 2>> $log"
if (( $metadata )); then
echo "Gathering LVM metadata from Physical Volumes..."
myecho "Gathering LVM metadata from Physical Volumes..."
mkdir -p $lvm_dir/metadata
log "$MKDIR -p $dir/metadata"
for pv in `pvs --noheadings -o name`
pvs="$($LVM pvs --separator , --noheadings --units s --nosuffix -o \
name,pe_start 2>> $log | $SED -e 's/^ *//')"
for line in "$pvs"
do
echo " $pv"
name=`basename $pv`
dd if=$pv of=$lvm_dir/metadata/$name bs=512 count=`pvs --noheadings --nosuffix --units s -o pe_start $pv | tr -d \ `
done 2>/dev/null
test -z "$line" && continue
pv="$(echo $line | $CUT -d, -f1)"
pe_start="$(echo $line | $CUT -d, -f2)"
name="$($BASENAME $pv)"
myecho " $pv"
log "$DD if=$pv of=$dir/metadata/$name bs=512 count=$pe_start 2>> $log"
done
fi
lvm_dump=$lvm_dir.tgz
echo "Creating tarball $lvm_dump..."
tar czf $lvm_dump $lvm_dir 2>/dev/null
if test -z "$userdir"; then
lvm_dump="$dirbase.tgz"
myecho "Creating report tarball in $HOME/$lvm_dump..."
cd $HOME
$TAR czf $lvm_dump $dirbase 2>/dev/null
$RM -rf $dir
fi
if test "$UID" != "0" && test "$EUID" != "0"; then
myecho
myecho "WARNING! Running as non-privileged user, dump is likely incomplete!"
myecho
fi
exit 0

View File

@@ -82,7 +82,8 @@ LVMLIBS = -llvm
CLEAN_TARGETS = liblvm2cmd.so liblvm2cmd.a liblvm2cmd-static.a lvm lvm.o \
lvm2cmd.o lvm2cmd-static.o lvm2cmdlib.o lvm.static \
lvm.cflow lvm.xref lvm.tree lvm.rxref lvm.rtree
lvm.cflow lvm.xref lvm.tree lvm.rxref lvm.rtree \
lvmcmdlib.o lvm-static.o
ifeq ("@CMDLIB@", "yes")
TARGETS += liblvm2cmd.so
@@ -100,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 > $@

View File

@@ -46,6 +46,7 @@ arg(alloc_ARG, '\0', "alloc", alloc_arg)
arg(separator_ARG, '\0', "separator", string_arg)
arg(mirrorsonly_ARG, '\0', "mirrorsonly", NULL)
arg(nosync_ARG, '\0', "nosync", NULL)
arg(resync_ARG, '\0', "resync", NULL)
arg(corelog_ARG, '\0', "corelog", NULL)
arg(monitor_ARG, '\0', "monitor", yes_no_arg)
arg(config_ARG, '\0', "config", string_arg)

View File

@@ -19,7 +19,7 @@ xx(e2fsadm,
"e2fsadm "
"[-d|--debug] " "[-h|--help] " "[-n|--nofsck]" "\n"
"\t{[-l|--extents] [+|-]LogicalExtentsNumber |" "\n"
"\t [-L|--size] [+|-]LogicalVolumeSize[kKmMgGtT]}" "\n"
"\t [-L|--size] [+|-]LogicalVolumeSize[kKmMgGtTpPeE]}" "\n"
"\t[-t|--test] " "\n"
"\t[-v|--verbose] " "\n"
"\t[--version] " "\n"
@@ -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",
@@ -69,15 +72,17 @@ xx(lvchange,
"\t[-p|--permission r|rw]\n"
"\t[-r|--readahead ReadAheadSectors]\n"
"\t[--refresh]\n"
"\t[--resync]\n"
"\t[-t|--test]\n"
"\t[-v|--verbose]\n"
"\t[-y|--yes]\n"
"\t[--version]" "\n"
"\tLogicalVolume[Path] [LogicalVolume[Path]...]\n",
alloc_ARG, autobackup_ARG, available_ARG, contiguous_ARG, force_ARG,
ignorelockingfailure_ARG, major_ARG, minor_ARG, monitor_ARG,
partial_ARG, permission_ARG, persistent_ARG, readahead_ARG,
refresh_ARG, addtag_ARG, deltag_ARG, test_ARG)
partial_ARG, permission_ARG, persistent_ARG, readahead_ARG, resync_ARG,
refresh_ARG, addtag_ARG, deltag_ARG, test_ARG, yes_ARG)
xx(lvconvert,
"Change logical volume layout",
@@ -115,7 +120,7 @@ xx(lvcreate,
"\t[-h|-?|--help]\n"
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
"\t{-l|--extents LogicalExtentsNumber |\n"
"\t -L|--size LogicalVolumeSize[kKmMgGtT]}\n"
"\t -L|--size LogicalVolumeSize[kKmMgGtTpPeE]}\n"
"\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n"
"\t[-m|--mirrors Mirrors [--nosync] [--corelog]]\n"
"\t[-n|--name LogicalVolumeName]\n"
@@ -139,7 +144,7 @@ xx(lvcreate,
"\t[-h|-?|--help]\n"
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
"\t{-l|--extents LogicalExtentsNumber[%{VG|LV|FREE}] |\n"
"\t -L|--size LogicalVolumeSize[kKmMgGtT]}\n"
"\t -L|--size LogicalVolumeSize[kKmMgGtTpPeE]}\n"
"\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n"
"\t[-n|--name LogicalVolumeName]\n"
"\t[-p|--permission {r|rw}]\n"
@@ -204,7 +209,7 @@ xx(lvextend,
"\t[-h|--help]\n"
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
"\t{-l|--extents [+]LogicalExtentsNumber[%{VG|FREE}] |\n"
"\t -L|--size [+]LogicalVolumeSize[kKmMgGtT]}\n"
"\t -L|--size [+]LogicalVolumeSize[kKmMgGtTpPeE]}\n"
"\t[-m|--mirrors Mirrors]\n"
"\t[-n|--nofsck]\n"
"\t[-r|--resizefs]\n"
@@ -269,11 +274,12 @@ xx(lvreduce,
"\t[-f|--force]\n"
"\t[-h|--help]\n"
"\t{-l|--extents [-]LogicalExtentsNumber[%{VG|LV|FREE}] |\n"
"\t -L|--size [-]LogicalVolumeSize[kKmMgGtT]}\n"
"\t -L|--size [-]LogicalVolumeSize[kKmMgGtTpPeE]}\n"
"\t[-n|--nofsck]\n"
"\t[-r|--resizefs]\n"
"\t[-t|--test]\n"
"\t[-v|--verbose]\n"
"\t[-y|--yes]\n"
"\t[--version]" "\n"
"\tLogicalVolume[Path]\n",
@@ -317,7 +323,7 @@ xx(lvresize,
"\t[-h|--help]\n"
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
"\t{-l|--extents [+|-]LogicalExtentsNumber[%{VG|LV|FREE}] |\n"
"\t -L|--size [+|-]LogicalVolumeSize[kKmMgGtT]}\n"
"\t -L|--size [+|-]LogicalVolumeSize[kKmMgGtTpPeE]}\n"
"\t[-n|--nofsck]\n"
"\t[-r|--resizefs]\n"
"\t[-t|--test]\n"
@@ -393,7 +399,7 @@ xx(pvresize,
"pvresize " "\n"
"\t[-d|--debug]" "\n"
"\t[-h|-?|--help] " "\n"
"\t[--setphysicalvolumesize PhysicalVolumeSize[kKmMgGtT]" "\n"
"\t[--setphysicalvolumesize PhysicalVolumeSize[kKmMgGtTpPeE]" "\n"
"\t[-t|--test] " "\n"
"\t[-v|--verbose] " "\n"
"\t[--version] " "\n"
@@ -411,8 +417,8 @@ xx(pvcreate,
"\t[--labelsector sector] " "\n"
"\t[-M|--metadatatype 1|2]" "\n"
"\t[--metadatacopies #copies]" "\n"
"\t[--metadatasize MetadataSize[kKmMgGtT]]" "\n"
"\t[--setphysicalvolumesize PhysicalVolumeSize[kKmMgGtT]" "\n"
"\t[--metadatasize MetadataSize[kKmMgGtTpPeE]]" "\n"
"\t[--setphysicalvolumesize PhysicalVolumeSize[kKmMgGtTpPeE]" "\n"
"\t[-t|--test] " "\n"
"\t[-u|--uuid uuid] " "\n"
"\t[-v|--verbose] " "\n"
@@ -609,7 +615,7 @@ xx(vgchange,
"\t -x|--resizeable {y|n} |" "\n"
"\t -l|--logicalvolume MaxLogicalVolumes |" "\n"
"\t -p|--maxphysicalvolumes MaxPhysicalVolumes |" "\n"
"\t -s|--physicalextentsize PhysicalExtentSize[kKmMgGtT] |" "\n"
"\t -s|--physicalextentsize PhysicalExtentSize[kKmMgGtTpPeE] |" "\n"
"\t --addtag Tag |\n"
"\t --deltag Tag}\n"
"\t[VolumeGroupName...]\n",
@@ -636,7 +642,7 @@ xx(vgconvert,
"\t[--labelsector sector] " "\n"
"\t[-M|--metadatatype 1|2]" "\n"
"\t[--metadatacopies #copies]" "\n"
"\t[--metadatasize MetadataSize[kKmMgGtT]]" "\n"
"\t[--metadatasize MetadataSize[kKmMgGtTpPeE]]" "\n"
"\t[-t|--test] " "\n"
"\t[-v|--verbose] " "\n"
"\t[--version] " "\n"
@@ -657,7 +663,7 @@ xx(vgcreate,
"\t[-l|--maxlogicalvolumes MaxLogicalVolumes]" "\n"
"\t[-M|--metadatatype 1|2] " "\n"
"\t[-p|--maxphysicalvolumes MaxPhysicalVolumes] " "\n"
"\t[-s|--physicalextentsize PhysicalExtentSize[kKmMgGtT]] " "\n"
"\t[-s|--physicalextentsize PhysicalExtentSize[kKmMgGtTpPeE]] " "\n"
"\t[-t|--test] " "\n"
"\t[-v|--verbose]" "\n"
"\t[--version] " "\n"

View File

@@ -114,6 +114,7 @@ enum {
NOOPENCOUNT_ARG,
NOTABLE_ARG,
OPTIONS_ARG,
SHOWKEYS_ARG,
TABLE_ARG,
TARGET_ARG,
TREE_ARG,
@@ -211,7 +212,11 @@ static int _parse_file(struct dm_task *dmt, const char *file)
r = 1;
out:
#ifndef HAVE_GETLINE
dm_free(buffer);
#else
free(buffer);
#endif
if (file)
fclose(fp);
return r;
@@ -915,7 +920,7 @@ static int _status(int argc, char **argv, void *data)
void *next = NULL;
uint64_t start, length;
char *target_type = NULL;
char *params;
char *params, *c;
int cmd;
struct dm_names *names = (struct dm_names *) data;
const char *name = NULL;
@@ -978,6 +983,17 @@ static int _status(int argc, char **argv, void *data)
if (data && !_switches[VERBOSE_ARG])
printf("%s: ", name);
if (target_type) {
/* Suppress encryption key */
if (!_switches[SHOWKEYS_ARG] &&
!strcmp(target_type, "crypt")) {
c = params;
while (*c && *c != ' ')
c++;
c++;
while (*c && *c != ' ')
*c++ = '0';
}
printf("%" PRIu64 " %" PRIu64 " %s %s",
start, length, target_type, params);
}
@@ -1522,7 +1538,7 @@ static struct command _commands[] = {
{"info", "[<device>]", 0, 1, _info},
{"deps", "[<device>]", 0, 1, _deps},
{"status", "[<device>] [--target <target_type>]", 0, 1, _status},
{"table", "[<device>] [--target <target_type>]", 0, 1, _status},
{"table", "[<device>] [--target <target_type>] [--showkeys]", 0, 1, _status},
{"wait", "<device> [<event_nr>]", 0, 2, _wait},
{"mknodes", "[<device>]", 0, 1, _mknodes},
{"targets", "", 0, 0, _targets},
@@ -1868,6 +1884,7 @@ static int _process_switches(int *argc, char ***argv)
{"noopencount", 0, &ind, NOOPENCOUNT_ARG},
{"notable", 0, &ind, NOTABLE_ARG},
{"options", 1, &ind, OPTIONS_ARG},
{"showkeys", 0, &ind, SHOWKEYS_ARG},
{"table", 1, &ind, TABLE_ARG},
{"target", 1, &ind, TARGET_ARG},
{"tree", 0, &ind, TREE_ARG},
@@ -1988,6 +2005,8 @@ static int _process_switches(int *argc, char ***argv)
_switches[NOLOCKFS_ARG]++;
if ((ind == NOOPENCOUNT_ARG))
_switches[NOOPENCOUNT_ARG]++;
if ((ind == SHOWKEYS_ARG))
_switches[SHOWKEYS_ARG]++;
if ((ind == TABLE_ARG)) {
_switches[TABLE_ARG]++;
_table = optarg;

View File

@@ -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;

View File

@@ -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 \

View File

@@ -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",
@@ -127,10 +135,10 @@ static int lvchange_availability(struct cmd_context *cmd,
}
} else {
if (lockingfailed() && (lv->vg->status & CLUSTERED)) {
log_verbose("Locking failed: ignoring clustered "
log_verbose("Locking failed: ignoring clustered "
"logical volume %s", lv->name);
return 0;
}
return 0;
}
if (lv_is_origin(lv) || (activate == CHANGE_AE)) {
log_verbose("Activating logical volume \"%s\" "
@@ -175,6 +183,159 @@ static int lvchange_refresh(struct cmd_context *cmd, struct logical_volume *lv)
return 1;
}
static int lvchange_resync(struct cmd_context *cmd,
struct logical_volume *lv)
{
int active = 0;
struct lvinfo info;
struct logical_volume *log_lv;
if (!(lv->status & MIRRORED)) {
log_error("Unable to resync %s because it is not mirrored.",
lv->name);
return 1;
}
if (lv->status & PVMOVE) {
log_error("Unable to resync pvmove volume %s", lv->name);
return 0;
}
if (lv->status & LOCKED) {
log_error("Unable to resync locked volume %s", lv->name);
return 0;
}
if (lv_info(cmd, lv, &info, 1)) {
if (info.open_count) {
log_error("Can't resync open logical volume \"%s\"",
lv->name);
return ECMD_FAILED;
}
if (info.exists) {
if (!arg_count(cmd, yes_ARG) &&
yes_no_prompt("Do you really want to deactivate "
"logical volume %s to resync it? [y/n]: ",
lv->name) == 'n') {
log_print("Logical volume \"%s\" not resynced",
lv->name);
return ECMD_FAILED;
}
active = 1;
}
}
if ((lv->vg->status & CLUSTERED) && !activate_lv_excl(cmd, lv)) {
log_error("Can't get exclusive access to clustered volume %s",
lv->name);
return ECMD_FAILED;
}
if (!deactivate_lv(cmd, lv)) {
log_error("Unable to deactivate %s for resync", lv->name);
return 0;
}
log_lv = first_seg(lv)->log_lv;
log_very_verbose("Starting resync of %s%s%s mirror \"%s\"",
(active) ? "active " : "",
(lv->vg->status & CLUSTERED) ? "clustered " : "",
(log_lv) ? "disk-logged" : "core-logged",
lv->name);
/*
* If this mirror has a core log (i.e. !log_lv),
* then simply deactivating/activating will cause
* it to reset the sync status. We only need to
* worry about persistent logs.
*/
if (!log_lv && !(lv->status & MIRROR_NOTSYNCED)) {
if (active && !activate_lv(cmd, lv)) {
log_error("Failed to reactivate %s to resynchronize "
"mirror", lv->name);
return 0;
}
return 1;
}
lv->status &= ~MIRROR_NOTSYNCED;
if (log_lv) {
/* Separate mirror log so we can clear it */
first_seg(lv)->log_lv = NULL;
log_lv->status &= ~MIRROR_LOG;
log_lv->status |= VISIBLE_LV;
if (!vg_write(lv->vg)) {
log_error("Failed to write intermediate VG metadata.");
if (active) {
first_seg(lv)->log_lv = log_lv;
log_lv->status |= MIRROR_LOG;
log_lv->status &= ~VISIBLE_LV;
if (!activate_lv(cmd, lv))
stack;
}
return 0;
}
backup(lv->vg);
if (!vg_commit(lv->vg)) {
log_error("Failed to commit intermediate VG metadata.");
if (active) {
first_seg(lv)->log_lv = log_lv;
log_lv->status |= MIRROR_LOG;
log_lv->status &= ~VISIBLE_LV;
if (!activate_lv(cmd, lv))
stack;
}
return 0;
}
if (!activate_lv(cmd, log_lv)) {
log_error("Unable to activate %s for mirror log resync",
log_lv->name);
return 0;
}
log_very_verbose("Clearing log device %s", log_lv->name);
if (!set_lv(cmd, log_lv, log_lv->size, 0)) {
log_error("Unable to reset sync status for %s", lv->name);
if (!deactivate_lv(cmd, log_lv))
log_error("Failed to deactivate log LV after "
"wiping failed");
return 0;
}
if (!deactivate_lv(cmd, log_lv)) {
log_error("Unable to deactivate log LV %s after wiping "
"for resync", log_lv->name);
return 0;
}
/* Put mirror log back in place */
first_seg(lv)->log_lv = log_lv;
log_lv->status |= MIRROR_LOG;
log_lv->status &= ~VISIBLE_LV;
}
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
if (!vg_write(lv->vg) || !vg_commit(lv->vg)) {
log_error("Failed to update metadata on disk.");
return 0;
}
if (active && !activate_lv(cmd, lv)) {
log_error("Failed to reactivate %s after resync", lv->name);
return 0;
}
return 1;
}
static int lvchange_alloc(struct cmd_context *cmd, struct logical_volume *lv)
{
int want_contiguous = 0;
@@ -294,16 +455,15 @@ static int lvchange_persistent(struct cmd_context *cmd,
log_error("Major number must be specified with -My");
return 0;
}
if (lv_info(cmd, lv, &info, 0) && info.exists &&
!arg_count(cmd, force_ARG)) {
if (yes_no_prompt("Logical volume %s will be "
"deactivated temporarily. "
"Continue? [y/n]: ", lv->name) == 'n') {
log_print("%s device number not changed.",
lv->name);
return 0;
}
if (lv_info(cmd, lv, &info, 0) && info.exists)
active = 1;
if (active && !arg_count(cmd, force_ARG) &&
yes_no_prompt("Logical volume %s will be "
"deactivated temporarily. "
"Continue? [y/n]: ", lv->name) == 'n') {
log_print("%s device number not changed.",
lv->name);
return 0;
}
log_verbose("Ensuring %s is inactive.", lv->name);
if (!deactivate_lv(cmd, lv)) {
@@ -496,6 +656,10 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
if (doit)
log_print("Logical volume \"%s\" changed", lv->name);
if (arg_count(cmd, resync_ARG))
if (!lvchange_resync(cmd, lv))
return ECMD_FAILED;
/* availability change */
if (arg_count(cmd, available_ARG)) {
if (!lvchange_availability(cmd, lv))
@@ -523,9 +687,10 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
&& !arg_count(cmd, minor_ARG) && !arg_count(cmd, major_ARG)
&& !arg_count(cmd, persistent_ARG) && !arg_count(cmd, addtag_ARG)
&& !arg_count(cmd, deltag_ARG) && !arg_count(cmd, refresh_ARG)
&& !arg_count(cmd, alloc_ARG) && !arg_count(cmd, monitor_ARG)) {
&& !arg_count(cmd, alloc_ARG) && !arg_count(cmd, monitor_ARG)
&& !arg_count(cmd, resync_ARG)) {
log_error("Need 1 or more of -a, -C, -j, -m, -M, -p, -r, "
"--refresh, --alloc, --addtag, --deltag "
"--resync, --refresh, --alloc, --addtag, --deltag "
"or --monitor");
return EINVALID_CMD_LINE;
}

View File

@@ -212,7 +212,7 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
}
if (activation() && lp->segtype->ops->target_present &&
!lp->segtype->ops->target_present()) {
!lp->segtype->ops->target_present(NULL)) {
log_error("%s: Required device-mapper target(s) not "
"detected in your kernel", lp->segtype->name);
return 0;
@@ -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,9 +446,9 @@ static int lvconvert_snapshot(struct cmd_context *cmd,
return 0;
}
if (!lp->zero)
log_error("WARNING: \"%s\" not zeroed", lv->name);
else if (!set_lv(cmd, lv, 0)) {
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.");
return 0;

View File

@@ -386,7 +386,7 @@ static int _lvcreate_params(struct lvcreate_params *lp, struct cmd_context *cmd,
}
if (activation() && lp->segtype->ops->target_present &&
!lp->segtype->ops->target_present()) {
!lp->segtype->ops->target_present(NULL)) {
log_error("%s: Required device-mapper target(s) not "
"detected in your kernel", lp->segtype->name);
return 0;
@@ -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);
@@ -556,7 +560,16 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
display_size(cmd, tmp_size));
}
lp->extents = tmp_size / vg->extent_size;
if (tmp_size > (uint64_t) UINT32_MAX * vg->extent_size) {
log_error("Volume too large (%s) for extent size %s. "
"Upper limit is %s.",
display_size(cmd, tmp_size),
display_size(cmd, vg->extent_size),
display_size(cmd, (uint64_t) UINT32_MAX *
vg->extent_size));
return 0;
}
lp->extents = (uint64_t) tmp_size / vg->extent_size;
}
switch(lp->percent) {
@@ -618,8 +631,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
}
if (!lp->extents) {
log_error("Unable to create logical volume %s with no extents",
lp->lv_name);
log_error("Unable to create new logical volume with no extents");
return 0;
}
@@ -761,18 +773,19 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
return 0;
}
if (!activate_lv(cmd, lv)) {
if (lp->snapshot)
/* FIXME Remove the failed lv we just added */
if (lp->snapshot) {
if (!activate_lv_excl(cmd, lv)) {
log_error("Aborting. Failed to activate snapshot "
"exception store. Remove new LV and retry.");
else
log_error("Failed to activate new LV.");
return 0;
}
} else if (!activate_lv(cmd, lv)) {
log_error("Failed to activate new LV.");
return 0;
}
if ((lp->zero || lp->snapshot) && activation()) {
if (!set_lv(cmd, lv, 0) && lp->snapshot) {
if (!set_lv(cmd, lv, 0, 0) && lp->snapshot) {
/* FIXME Remove the failed lv we just added */
log_error("Aborting. Failed to wipe snapshot "
"exception store. Remove new LV and retry.");
@@ -787,10 +800,8 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
/* Reset permission after zeroing */
if (!(lp->permission & LVM_WRITE))
lv->status &= ~LVM_WRITE;
if (!deactivate_lv(cmd, lv)) {
log_err("Couldn't deactivate new snapshot.");
return 0;
}
/* cow LV remains active and becomes snapshot LV */
if (!vg_add_snapshot(vg->fid, NULL, org, lv, NULL,
org->le_count, lp->chunk_size)) {

View File

@@ -77,7 +77,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);

View File

@@ -186,7 +186,7 @@ static int _size_arg(struct cmd_context *cmd __attribute((unused)), struct arg *
{
char *ptr;
int i;
static const char *suffixes = "kmgt";
static const char *suffixes = "kmgtpe";
char *val;
double v;
@@ -712,10 +712,8 @@ static int _get_settings(struct cmd_context *cmd)
cmd->default_settings.activation);
}
if (arg_count(cmd, autobackup_ARG)) {
cmd->current_settings.archive = 1;
cmd->current_settings.backup = 1;
}
cmd->current_settings.archive = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.archive);
cmd->current_settings.backup = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.backup);
if (arg_count(cmd, partial_ARG)) {
init_partial(1);

View File

@@ -75,6 +75,16 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
if (!archive(vg))
return ECMD_FAILED;
/* If the VG is clustered then make sure no-one else is using the LV
we are about to remove */
if (vg->status & CLUSTERED) {
if (!activate_lv_excl(cmd, lv)) {
log_error("Can't get exclusive access to volume \"%s\"",
lv->name);
return ECMD_FAILED;
}
}
/* FIXME Snapshot commit out of sequence if it fails after here? */
if (!deactivate_lv(cmd, lv)) {
log_error("Unable to deactivate logical volume \"%s\"",

View File

@@ -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;

Some files were not shown because too many files have changed in this diff Show More