1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-10-04 05:44:18 +03:00

Compare commits

...

111 Commits

Author SHA1 Message Date
Alasdair Kergon
fdc49402ec fix clvmd lv_info_by_lvid open_count 2005-01-19 18:10:09 +00:00
Alasdair Kergon
5457c133e1 Add some comments. 2005-01-19 17:31:51 +00:00
Alasdair Kergon
292e588ee3 move recover_vg 2005-01-19 17:30:50 +00:00
Alasdair Kergon
243494c25e Store snapshot and origin sizes separately. 2005-01-19 17:19:39 +00:00
Alasdair Kergon
e4365f3706 Update vgcreate man page. 2005-01-19 17:01:18 +00:00
Alasdair Kergon
310f3038d3 Post-2.01.00 2005-01-17 20:45:05 +00:00
Alasdair Kergon
4e6033273d update po 2005-01-17 20:16:37 +00:00
Alasdair Kergon
73718586d3 2.01.00 2005-01-17 20:13:01 +00:00
Alasdair Kergon
011abe61e8 post-1.01.00 2005-01-17 20:12:12 +00:00
Alasdair Kergon
fe3a37f89d 1.01.00 2005-01-17 20:00:28 +00:00
Alasdair Kergon
8aea44e77b Fix vgscan metadata auto-correction. 2005-01-17 18:24:28 +00:00
Patrick Caulfield
5529aec0d6 You can now build clvmd with cman & gulm support in the same binary.
./configure --with-clvmd
wil do this by default. Or you can choose which you want with
./configure --with-clvmd=gulm    or
./configure --with-clvmd=cman

When clvmd with both included is run, it will automatically detect the cluster
manager in use.
2005-01-13 13:24:02 +00:00
Alasdair Kergon
369549d23f Only ask libdevmapper for open_count when we need it. 2005-01-12 22:58:21 +00:00
Alasdair Kergon
181ea9a381 Add dm_task_no_open_count() to skip getting open_count. 2005-01-12 22:10:14 +00:00
Alasdair Kergon
76b8f2854e Adjust RHEL4 clvmd init script priority. 2005-01-11 22:00:36 +00:00
Alasdair Kergon
320e5198f9 post-2.00.33 2005-01-07 20:06:49 +00:00
Alasdair Kergon
e522539e2d 2.00.33 2005-01-07 19:50:54 +00:00
Alasdair Kergon
7c996b83d2 post-1.00.21 2005-01-07 17:10:16 +00:00
Alasdair Kergon
3dd354d7aa 1.00.21 2005-01-07 15:53:37 +00:00
Alasdair Kergon
f4ad6e2157 Fix /proc/devices parsing. 2005-01-07 15:39:53 +00:00
Patrick Caulfield
8b170dc2bf Fix off-by-one error in cluster_locking that could case read hangs. 2005-01-07 14:22:49 +00:00
Alasdair Kergon
dcb9d779bf post-1.00.20 2005-01-06 18:41:38 +00:00
Alasdair Kergon
80f736d670 1.00.20 2005-01-06 18:30:17 +00:00
Alasdair Kergon
8502c6da3c Attempt to fix /dev/mapper/control transparently if it's wrong. 2005-01-06 18:22:44 +00:00
Patrick Caulfield
b131449422 Some more gulm fixes from "Mr gulm" himself. 2005-01-06 11:48:25 +00:00
Alasdair Kergon
6eebc4a620 Configuration-time option for setting uid/gid/mode for /dev/mapper nodes. 2005-01-05 22:00:40 +00:00
Alasdair Kergon
4661ab1179 pvcreate wipes first 4 sectors unless given --zero n. 2005-01-05 17:25:25 +00:00
Patrick Caulfield
86046445ed Improve clvmd failure message if it's already running.
Allow user to kill clvmd during initialisation.
2005-01-05 14:41:54 +00:00
Patrick Caulfield
baea9bf944 Typo in "for" caused first node in ccs to be ignored. 2005-01-04 15:11:34 +00:00
Patrick Caulfield
0951ee9e63 Use new CCS key names for nodes in the GULM version of clvmd.
based on a patch from Mike Tilstra
2005-01-04 11:48:10 +00:00
Alasdair Kergon
5492528287 post-2.00.32 2004-12-22 22:04:03 +00:00
Alasdair Kergon
14dbd220c2 update pofile 2004-12-22 21:58:26 +00:00
Alasdair Kergon
babc890c59 Drop static/dl config restriction for now. 2004-12-22 21:55:36 +00:00
Alasdair Kergon
6f7b47ff40 update version 2004-12-22 21:47:50 +00:00
Alasdair Kergon
3991f03202 Fix an error fprintf. 2004-12-22 21:47:31 +00:00
Alasdair Kergon
27271d5da7 Fix vgdisplay -s. Breaks (undocumented) lvs/pvs/vgs -s instead for now. 2004-12-21 21:40:36 +00:00
Alasdair Kergon
627312e1de Fix device reference counting on re-opens. 2004-12-21 20:23:16 +00:00
Alasdair Kergon
bfc9550e4e Ignore sysfs symlinks when DT_UNKNOWN. 2004-12-21 18:29:46 +00:00
Alasdair Kergon
2b9c21268b Add RHEL4 clvmd init script. 2004-12-21 18:07:15 +00:00
Alasdair Kergon
3dce4ed6f1 Skip devices that are too small to be PVs. 2004-12-21 17:54:52 +00:00
Alasdair Kergon
0f16c2ea87 Add CONTRIBUTORS file. 2004-12-21 16:24:19 +00:00
Alasdair Kergon
9a635f0686 Fix pvchange -x segfault with lvm2-format orphan. 2004-12-21 16:12:02 +00:00
Alasdair Kergon
6a0d4b2baa Cope with empty msdos partition tables. 2004-12-21 16:10:25 +00:00
Alasdair Kergon
ac017098ad post-2.00.31 2004-12-12 21:55:46 +00:00
Alasdair Kergon
98fef2640d update pofile 2004-12-12 21:51:59 +00:00
Alasdair Kergon
8bb66e133a 2.00.31 2004-12-12 21:47:55 +00:00
Alasdair Kergon
68a582901d Reopen RO file descriptor RW if necessary. 2004-12-12 21:47:14 +00:00
Alasdair Kergon
c094f4c06e post-2.00.30 2004-12-10 18:01:49 +00:00
Alasdair Kergon
f7ca545544 update pofile 2004-12-10 16:07:37 +00:00
Alasdair Kergon
69b4716894 2.00.30 2004-12-10 16:02:35 +00:00
Alasdair Kergon
7e44dcc5bf Additional device-handling debug messages.
Additional verbosity level -vvvv includes line numbers and backtraces.
Verbose messages now go to stderr not stdout.
Close any stray file descriptors before starting.
Refine partitionable checks for certain device types.
Allow devices/types to override built-ins.
2004-12-10 16:01:35 +00:00
Alasdair Kergon
ab9843e183 Fix lvreduce man page .i->.I 2004-12-09 16:59:18 +00:00
Alasdair Kergon
01af706ade Fix vgsplit man page title. 2004-12-09 16:58:31 +00:00
Alasdair Kergon
9ebdb08e99 Fix clvmd man makefile. 2004-12-09 16:57:37 +00:00
Alasdair Kergon
a74ffe25d9 Extend dev_open logging. 2004-12-09 16:56:51 +00:00
Patrick Caulfield
7f95e27707 Make clvmd_fix_conf.sh UNDOable 2004-12-01 14:47:31 +00:00
Alasdair Kergon
1facf5bba3 post-29 2004-11-27 22:56:58 +00:00
Alasdair Kergon
03d77009eb xlate compilation fix 2004-11-27 22:07:41 +00:00
Alasdair Kergon
8afd6812b5 update version 2004-11-27 21:38:34 +00:00
Alasdair Kergon
ec9ad78fcf Endian fix to signature detection. 2004-11-27 21:37:54 +00:00
Alasdair Kergon
6f4e93dc90 Configure/makefile tidy. 2004-11-26 18:07:17 +00:00
Alasdair Kergon
a38e43862d fix partition table signature size 2004-11-26 14:40:34 +00:00
Alasdair Kergon
39294bb037 update pofile 2004-11-24 21:39:30 +00:00
Alasdair Kergon
edc5e59b78 Trap large memory allocation requests. 2004-11-24 21:34:56 +00:00
Alasdair Kergon
c00fd9fd37 Fix to partition table detection code. 2004-11-24 20:38:05 +00:00
Alasdair Kergon
b3e621dd9f Improve filter debug msgs. 2004-11-24 20:36:52 +00:00
Alasdair Kergon
6e8c49b978 post-release 2004-11-23 18:36:01 +00:00
Alasdair Kergon
398d57133d update po 2004-11-23 18:27:57 +00:00
Alasdair Kergon
16521a6feb pool debugging 2004-11-23 18:23:23 +00:00
Alasdair Kergon
3ca0b37a3e 2.00.26 2004-11-23 17:47:19 +00:00
Alasdair Kergon
cf2ec1229d fix a md filter log mesg 2004-11-23 17:45:48 +00:00
Alasdair Kergon
fe9b1e5f9b update pofile 2004-11-23 17:44:10 +00:00
Alasdair Kergon
f5b96ddf01 Detect partition table signature. 2004-11-23 11:44:04 +00:00
Alasdair Kergon
2fe076fb27 Only wipe signature bytes when destroying md superblock, so process
is reversible.
2004-11-19 19:32:09 +00:00
Alasdair Kergon
99249cff04 pvcreate wipes md superblocks. (With --uuid or --restorefile it prompts.) 2004-11-19 19:25:07 +00:00
Alasdair Kergon
0cdf7b0613 Separate out md superblock detection code. 2004-11-18 20:02:21 +00:00
Alasdair Kergon
90bcf4f157 Prevent snapshot origin resizing. 2004-11-18 19:49:48 +00:00
Alasdair Kergon
03c3ec4e12 Improve a vgremove error message. 2004-11-18 19:45:53 +00:00
Alasdair Kergon
ca9bb20d64 More tagging documentation, with some cluster examples. 2004-11-17 18:34:49 +00:00
Alasdair Kergon
c6bc078fd9 More lvm.conf and tagging documentation. 2004-11-17 17:49:32 +00:00
Alasdair Kergon
2f4bd6e52c More man page updates. 2004-11-16 18:09:32 +00:00
Patrick Caulfield
2affe53727 Tidy the socket callbacks so that all the work is done outside the
main loop.
2004-11-16 10:55:01 +00:00
Alasdair Kergon
09654d7dd8 update WHATS_NEW 2004-11-12 16:02:08 +00:00
Alasdair Kergon
90a4e37815 Update some man pages. 2004-11-12 15:59:09 +00:00
Alasdair Kergon
60889c0c79 Also accept y/n with -ae. 2004-11-12 15:58:26 +00:00
Patrick Caulfield
20f3408d96 Report detailed errors in cluster initialisation to syslog, and point the user
at syslog if clvmd fails to intialise.
2004-11-11 14:51:23 +00:00
Patrick Caulfield
e9d86789db Can now build a gulm version of clvmd instead of a cman one. use
./configure --with-clvmd=gulm

The default is still cman, and you can't have both - sorry.
2004-11-03 10:45:07 +00:00
Alasdair Kergon
5152b7c66c update 2004-10-15 17:31:37 +00:00
Alasdair Kergon
c494c4e12c Fixes to lvcreate vgname processing. 2004-10-15 15:53:18 +00:00
Alasdair Kergon
54d58ccb7e Add --noheadings option to dmsetup -c for colon-separated output. 2004-10-12 16:42:40 +00:00
Alasdair Kergon
714a77bfbe Fix size of dm_name string. 2004-10-11 15:59:23 +00:00
Patrick Caulfield
d48f8bf5cc Make clvmd -V display the lvm version number too rather than just
the protocol version (which is not that useful and doesn't change very often).
2004-10-06 12:36:47 +00:00
Patrick Caulfield
99d97754a6 Revert the fork back to where it was as it seems to confuse pthreads.
Instead, the parent now waits for the daemon to signal that it has
completed successfully (or not) so it can return status to the user.
2004-10-06 10:12:34 +00:00
Patrick Caulfield
b9d437de2a Change some perror() calls to log_error() so they'll appear in
syslog when we're a daemon.
2004-10-06 10:02:25 +00:00
Patrick Caulfield
11403f2019 Check the UUID length when readingthe output of the "lvs" command at startup.
This way we should not get quite so confused by any debugging output
that may come our way.
2004-10-04 09:23:52 +00:00
Alasdair Kergon
1ca102d639 Support device referencing by uuid or major/minor. 2004-10-01 19:11:37 +00:00
Alasdair Kergon
339ba55111 printf->fprintf 2004-10-01 19:07:41 +00:00
Patrick Caulfield
14ae59885a Make clvmd cope with large gaps in nodeIDs 2004-09-30 14:18:29 +00:00
Patrick Caulfield
e3ef54f99b Fork a little later in the startup sequence so that we can return
an error code if the cluster infrastructure isn't there.
2004-09-30 14:16:28 +00:00
Alasdair Kergon
001901f9a9 post-2.00.25 2004-09-29 15:25:43 +00:00
Alasdair Kergon
6a98f60e2e 2.00.25 2004-09-29 15:08:20 +00:00
Alasdair Kergon
6f2e24c47d Use macro in vgremove locking fix. 2004-09-27 10:32:36 +00:00
Patrick Caulfield
aafa368923 Hold VG lock while doing vgremove.
agk - you may want to check this.
2004-09-24 12:48:43 +00:00
Patrick Caulfield
eb783cab4c Remove spurious trailing dot in man page. 2004-09-24 10:34:53 +00:00
Patrick Caulfield
6533aa865a Keep client locks (VG locks usually) in their own hash table so
we can actually have more then one of them per client.
2004-09-24 09:39:57 +00:00
Patrick Caulfield
f1a1e1bc07 Update WHATS_NEW with latest clvmd change 2004-09-23 13:12:09 +00:00
Patrick Caulfield
953f4838dd Make the thread handling a little less cavalier. In particular, calling
pthread_exit in a signal handler was a /really/ bad idea.
2004-09-23 12:51:56 +00:00
Patrick Caulfield
130b892d34 Don't use hold_lock for VG locks as that doesn't stop processes contending
on the same node, only across the cluster.
2004-09-23 12:29:35 +00:00
Alasdair Kergon
6ad525c77e Fix return code from rm_link for vgmknodes. 2004-09-22 13:38:37 +00:00
Patrick Caulfield
d0ca74ad27 Put some locking round the LV hash table as it could be accessed by
different threads concurrently.
2004-09-22 12:10:34 +00:00
Alasdair Kergon
9806f69b4d post-2.00.24 2004-09-16 21:48:26 +00:00
114 changed files with 5349 additions and 2335 deletions

0
CONTRIBUTORS Normal file
View File

View File

@@ -1 +1 @@
2.00.24-cvs (2004-09-16)
2.01.01-cvs (2005-01-19)

View File

@@ -1,3 +1,101 @@
Version 2.01.01 - 19th January 2005
===================================
Fix clvmd lv_info_by_lvid open_count.
Store snapshot and origin sizes separately.
Update vgcreate man page.
Version 2.01.00 - 17th January 2005
===================================
Fix vgscan metadata auto-correction.
Only ask libdevmapper for open_count when we need it.
Adjust RHEL4 clvmd init script priority.
Enable building of CMAN & GULM versions of clvmd into a single binary
Version 2.00.33 - 7th January 2005
==================================
pvcreate wipes first 4 sectors unless given --zero n.
gulm clvmd now uses new ccsd key names.
gulm clvmd now doesn't ignore the first node in cluster.conf
Improve clvmd failure message if it's already running.
Allow user to kill clvmd during initialisation.
Fix off-by-one error in cluster_locking that could cause read hangs.
Version 2.00.32 - 22nd December 2004
====================================
Drop static/dl restriction for now.
Fix an error fprintf.
Fix vgdisplay -s. Breaks (undocumented) lvs/pvs/vgs -s instead for now.
Fix device reference counting on re-opens.
Ignore sysfs symlinks when DT_UNKNOWN.
Add clvmd init script for RHEL4.
Skip devices that are too small to be PVs.
Fix pvchange -x segfault with lvm2-format orphan.
Cope with empty msdos partition tables.
Add CONTRIBUTORS file.
Version 2.00.31 - 12th December 2004
====================================
Reopen RO file descriptors RW if necessary.
Version 2.00.30 - 10th December 2004
====================================
Additional device-handling debug messages.
Additional verbosity level -vvvv includes line numbers and backtraces.
Verbose messages now go to stderr not stdout.
Close any stray file descriptors before starting.
Refine partitionable checks for certain device types.
Allow devices/types to override built-ins.
Fix lvreduce man page .i->.I
Fix vgsplit man page title.
Fix clvmd man makefile.
Extend dev_open logging.
Make clvmd_fix_conf.sh UNDOable.
Version 2.00.29 - 27th November 2004
====================================
xlate compilation fix.
Version 2.00.28 - 27th November 2004
====================================
Fix partition table & md signature detection.
Minor configure/makefile tidy.
Export version.h from tools for clvmd.
Version 2.00.27 - 24th November 2004
====================================
Trap large memory allocation requests.
Fix to partition table detection code.
Improve filter debug mesgs.
Make clvmd_fix_conf.sh UNDOable
Version 2.00.26 - 23rd November 2004
====================================
Improve pool debugging stats.
Detect partition table signature.
pvcreate wipes md superblocks. (With --uuid or --restorefile it prompts.)
Separate out md superblock detection code.
Prevent snapshot origin resizing.
Improve a vgremove error message.
Update some man pages.
Allow y/n with -ae args (exclusive activation).
Fixes to lvcreate vgname parsing.
Fix dm_name string size calculation.
Improve clvmd error reporting during startup.
Make clvmd cope with large gaps in node numbers IDs.
Make clvmd initialisation cope better with debugging output.
Tidy clvmd socket callbacks so all work happens outside main loop.
clvmd -V now displays lvm version too.
Add optional gulm build for clvmd
Version 2.00.25 - 29th September 2004
=====================================
Fix return code from rm_link for vgmknodes.
Make clvmd LV hash table thread-safe.
Fix clvmd locking so it will lock out multiple users on the same node.
Fix clvmd VG locking to it can cope with multiple VG locks.
Remove spurious trailing dot in lvreduce man page.
Fix vgremove locking.
Version 2.00.24 - 16th September 2004
=====================================
Fix pool_empty so it really does empty the memory pool.

View File

@@ -1,6 +1,24 @@
Version 1.00.20 -
Version 1.01.01 -
=============================
Version 1.01.00 - 17 Jan 2005
=============================
Add dm_task_no_open_count() to skip getting open_count.
Version 1.00.21 - 7 Jan 2005
============================
Fix /proc/devices parsing.
Version 1.00.20 - 6 Jan 2005
============================
Attempt to fix /dev/mapper/control transparently if it's wrong.
Configuration-time option for setting uid/gid/mode for /dev/mapper nodes.
Update kernel patches for 2.4.27/2.4.28-pre-4 (includes minor fixes).
Add --noheadings columns option for colon-separated dmsetup output.
Support device referencing by uuid or major/minor.
Warn if kernel data didn't fit in buffer.
Fix a printf.
Version 1.00.19 - 3 July 2004
=============================
More autoconf fixes.

2467
configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -280,12 +280,18 @@ AC_MSG_RESULT($SELINUX)
################################################################################
dnl -- Build cluster LVM daemon
AC_MSG_CHECKING(whether to build cluster LVM daemon)
AC_ARG_WITH(clvmd, [ --with-clvmd Build cluster LVM Daemon],
CLVMD=$withval, CLVMD=no)
AC_ARG_WITH(clvmd,
[ --with-clvmd=TYPE Build cluster LVM Daemon: cman/gulm/none/all
[TYPE=none] ],
[ CLVMD="$withval" ],
[ CLVMD="none" ])
if test x$CLVMD = xyes; then
CLVMD=all
fi
AC_MSG_RESULT($CLVMD)
dnl -- If clvmd enabled without cluster locking, automagically include it
if test x$CLVMD = xyes && test x$CLUSTER = xnone; then
if test x$CLVMD != xnone && test x$CLUSTER = xnone; then
CLUSTER=internal
fi
@@ -383,7 +389,7 @@ fi
dnl -- Check for dlopen
AC_CHECK_LIB(dl, dlopen, HAVE_LIBDL=yes, HAVE_LIBDL=no)
if [[ "x$HAVE_LIBDL" = xyes -a "x$STATIC_LINK" = xno ]]; then
if [[ "x$HAVE_LIBDL" = xyes ]]; then
CFLAGS="$CFLAGS -DHAVE_LIBDL"
LIBS="-ldl $LIBS"
else
@@ -475,7 +481,7 @@ if test x$READLINE = xyes; then
AC_CHECK_HEADERS(readline/readline.h readline/history.h,,AC_MSG_ERROR(bailing out))
fi
if test x$CLVMD = xyes; then
if test x$CLVMD != xnone; then
AC_CHECK_HEADERS(mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h,,AC_MSG_ERROR(bailing out))
AC_CHECK_FUNCS(dup2 getmntent memmove select socket,,AC_MSG_ERROR(bailing out))
AC_FUNC_GETMNTENT

View File

@@ -15,7 +15,7 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
ifeq ("@CLVMD@", "yes")
ifneq ("@CLVMD@", "none")
SUBDIRS = clvmd
endif

View File

@@ -16,26 +16,50 @@ top_srcdir = @top_srcdir@
VPATH = @srcdir@
SOURCES = \
clvmd-cman.c \
clvmd-command.c \
clvmd.c \
libclvm.c \
lvm-functions.c \
system-lv.c
ifeq ("@CLVMD@", "gulm")
GULM = yes
endif
ifeq ("@CLVMD@", "cman")
CMAN = yes
endif
ifeq ("@CLVMD@", "all")
GULM = yes
CMAN = yes
endif
ifeq ("$(GULM)", "yes")
SOURCES += clvmd-gulm.c tcp-comms.c
LMLIBS += -lccs -lgulm
CFLAGS += -DUSE_GULM
endif
ifeq ("$(CMAN)", "yes")
SOURCES += clvmd-cman.c
LMLIBS += -ldlm
CFLAGS += -DUSE_CMAN
endif
TARGETS = \
clvmd
include $(top_srcdir)/make.tmpl
CFLAGS += -D_REENTRANT -fno-strict-aliasing
LIBS += -ldevmapper -ldlm -llvm -lpthread
LIBS += -ldevmapper -llvm -lpthread
INSTALL_TARGETS = \
install_clvmd
clvmd: $(OBJECTS) $(top_srcdir)/lib/liblvm.a
$(CC) -o clvmd $(OBJECTS) $(LDFLAGS) $(LVMLIBS) $(LIBS)
$(CC) -o clvmd $(OBJECTS) $(LDFLAGS) $(LVMLIBS) $(LMLIBS) $(LIBS)
.PHONY: install_clvmd

View File

@@ -55,7 +55,6 @@ static int max_updown_nodes = 50; /* Current size of the allocated array */
static int *node_updown = NULL;
static dlm_lshandle_t *lockspace;
static void sigusr1_handler(int sig);
static void count_clvmds_running(void);
static void get_members(void);
static int nodeid_from_csid(char *csid);
@@ -67,7 +66,7 @@ struct lock_wait {
struct dlm_lksb lksb;
};
int init_cluster()
static int _init_cluster(void)
{
struct sockaddr_cl saddr;
int port = CLUSTER_PORT_CLVMD;
@@ -75,7 +74,7 @@ int init_cluster()
/* Open the cluster communication socket */
cluster_sock = socket(AF_CLUSTER, SOCK_DGRAM, CLPROTO_CLIENT);
if (cluster_sock == -1) {
perror("Can't open cluster socket");
syslog(LOG_ERR, "Can't open cman cluster manager socket: %m");
return -1;
}
@@ -87,7 +86,7 @@ int init_cluster()
if (bind
(cluster_sock, (struct sockaddr *) &saddr,
sizeof(struct sockaddr_cl))) {
log_error("Can't bind cluster socket: %m");
syslog(LOG_ERR, "Can't bind cluster socket: %m");
return -1;
}
@@ -98,25 +97,25 @@ int init_cluster()
/* Create a lockspace for LV & VG locks to live in */
lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
if (!lockspace) {
log_error("Unable to create lockspace for CLVM\n");
syslog(LOG_ERR, "Unable to create lockspace for CLVM: %m");
return -1;
}
dlm_ls_pthread_init(lockspace);
return 0;
}
int get_main_cluster_fd()
static int _get_main_cluster_fd()
{
return cluster_sock;
}
int get_num_nodes()
static int _get_num_nodes()
{
return num_nodes;
}
/* send_message with the fd check removed */
int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
static int _cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
{
struct iovec iov[2];
struct msghdr msg;
@@ -136,7 +135,7 @@ int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
if (csid) {
msg.msg_name = &saddr;
msg.msg_namelen = sizeof(saddr);
memcpy(&saddr.scl_nodeid, csid, MAX_CSID_LEN);
memcpy(&saddr.scl_nodeid, csid, CMAN_MAX_CSID_LEN);
} else { /* Cluster broadcast */
msg.msg_name = NULL;
@@ -152,26 +151,26 @@ int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
return len;
}
void get_our_csid(char *csid)
static void _get_our_csid(char *csid)
{
int i;
memset(csid, 0, MAX_CSID_LEN);
memset(csid, 0, CMAN_MAX_CSID_LEN);
for (i = 0; i < num_nodes; i++) {
if (nodes[i].us)
memcpy(csid, &nodes[i].node_id, MAX_CSID_LEN);
memcpy(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN);
}
}
/* Call a callback routine for each node that known (down mean not running a clvmd) */
int cluster_do_node_callback(struct local_client *client,
static int _cluster_do_node_callback(struct local_client *client,
void (*callback) (struct local_client *, char *,
int))
{
int i;
int somedown = 0;
for (i = 0; i < get_num_nodes(); i++) {
for (i = 0; i < _get_num_nodes(); i++) {
callback(client, (char *)&nodes[i].node_id, node_updown[nodes[i].node_id]);
if (!node_updown[nodes[i].node_id])
somedown = -1;
@@ -203,7 +202,7 @@ static void process_oob_msg(char *buf, int len, int nodeid)
}
}
int cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
static int _cluster_fd_callback(struct local_client *client, char *buf, int len, char *csid,
struct local_client **new_client)
{
struct iovec iov[2];
@@ -247,34 +246,39 @@ int cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
len = -1;
errno = EAGAIN;
}
memcpy(csid, &saddr.scl_nodeid, sizeof(saddr.scl_nodeid));
else {
memcpy(csid, &saddr.scl_nodeid, sizeof(saddr.scl_nodeid));
/* Send it back to clvmd */
process_message(client, buf, len, csid);
}
return len;
}
void add_up_node(char *csid)
static void _add_up_node(char *csid)
{
/* It's up ! */
int nodeid = nodeid_from_csid(csid);
if (nodeid >= max_updown_nodes) {
int *new_updown = realloc(node_updown, max_updown_nodes + 10);
int new_size = nodeid + 10;
int *new_updown = realloc(node_updown, new_size);
if (new_updown) {
node_updown = new_updown;
max_updown_nodes += 10;
max_updown_nodes = new_size;
DEBUGLOG("realloced more space for nodes. now %d\n",
max_updown_nodes);
} else {
log_error
("Realloc failed. Node status for clvmd will be wrong\n");
return;
("Realloc failed. Node status for clvmd will be wrong. quitting\n");
exit(999);
}
}
node_updown[nodeid] = 1;
DEBUGLOG("Added new node %d to updown list\n", nodeid);
}
void cluster_closedown()
static void _cluster_closedown()
{
unlock_all();
dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
@@ -303,7 +307,7 @@ static int is_listening(int nodeid)
/* Populate the list of CLVMDs running.
called only at startup time */
void count_clvmds_running(void)
static void count_clvmds_running(void)
{
int i;
@@ -319,7 +323,7 @@ static void get_members()
num_nodes = ioctl(cluster_sock, SIOCCLUSTER_GETMEMBERS, 0);
if (num_nodes == -1) {
perror("get nodes");
log_error("Unable to get node count");
} else {
/* Not enough room for new nodes list ? */
if (num_nodes > count_nodes && nodes) {
@@ -331,16 +335,16 @@ static void get_members()
count_nodes = num_nodes + 10; /* Overallocate a little */
nodes = malloc(count_nodes * sizeof(struct cl_cluster_node));
if (!nodes) {
perror("Unable to allocate nodes array\n");
log_error("Unable to allocate nodes array\n");
exit(5);
}
}
nodelist.max_members = count_nodes;
nodelist.nodes = nodes;
num_nodes = ioctl(cluster_sock, SIOCCLUSTER_GETMEMBERS, &nodelist);
if (num_nodes <= 0) {
perror("get node details");
log_error("Unable to get node details");
exit(6);
}
@@ -362,13 +366,13 @@ static void get_members()
}
/* Convert a node name to a CSID */
int csid_from_name(char *csid, char *name)
static int _csid_from_name(char *csid, char *name)
{
int i;
for (i = 0; i < num_nodes; i++) {
if (strcmp(name, nodes[i].name) == 0) {
memcpy(csid, &nodes[i].node_id, MAX_CSID_LEN);
memcpy(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN);
return 0;
}
}
@@ -376,12 +380,12 @@ int csid_from_name(char *csid, char *name)
}
/* Convert a CSID to a node name */
int name_from_csid(char *csid, char *name)
static int _name_from_csid(char *csid, char *name)
{
int i;
for (i = 0; i < num_nodes; i++) {
if (memcmp(csid, &nodes[i].node_id, MAX_CSID_LEN) == 0) {
if (memcmp(csid, &nodes[i].node_id, CMAN_MAX_CSID_LEN) == 0) {
strcpy(name, nodes[i].name);
return 0;
}
@@ -392,7 +396,7 @@ int name_from_csid(char *csid, char *name)
}
/* Convert a node ID to a node name */
int name_from_nodeid(int nodeid, char *name)
static int name_from_nodeid(int nodeid, char *name)
{
int i;
@@ -412,12 +416,12 @@ static int nodeid_from_csid(char *csid)
{
int nodeid;
memcpy(&nodeid, csid, MAX_CSID_LEN);
memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
return nodeid;
}
int is_quorate()
static int _is_quorate()
{
return ioctl(cluster_sock, SIOCCLUSTER_ISQUORATE, 0);
}
@@ -431,7 +435,7 @@ static void sync_ast_routine(void *arg)
pthread_mutex_unlock(&lwait->mutex);
}
int sync_lock(const char *resource, int mode, int flags, int *lockid)
static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
{
int status;
struct lock_wait lwait;
@@ -441,6 +445,7 @@ int sync_lock(const char *resource, int mode, int flags, int *lockid)
return -1;
}
DEBUGLOG("sync_lock: '%s' mode:%d flags=%d\n", resource,mode,flags);
/* Conversions need the lockid in the LKSB */
if (flags & LKF_CONVERT)
lwait.lksb.sb_lkid = *lockid;
@@ -466,17 +471,20 @@ int sync_lock(const char *resource, int mode, int flags, int *lockid)
*lockid = lwait.lksb.sb_lkid;
errno = lwait.lksb.sb_status;
DEBUGLOG("sync_lock: returning lkid %x\n", *lockid);
if (lwait.lksb.sb_status)
return -1;
else
return 0;
}
int sync_unlock(const char *resource /* UNUSED */, int lockid)
static int _sync_unlock(const char *resource /* UNUSED */, int lockid)
{
int status;
struct lock_wait lwait;
DEBUGLOG("sync_unlock: '%s' lkid:%x\n", resource, lockid);
pthread_cond_init(&lwait.cond, NULL);
pthread_mutex_init(&lwait.mutex, NULL);
pthread_mutex_lock(&lwait.mutex);
@@ -497,3 +505,28 @@ int sync_unlock(const char *resource /* UNUSED */, int lockid)
return 0;
}
static struct cluster_ops _cluster_cman_ops = {
.cluster_init_completed = NULL,
.cluster_send_message = _cluster_send_message,
.name_from_csid = _name_from_csid,
.csid_from_name = _csid_from_name,
.get_num_nodes = _get_num_nodes,
.cluster_fd_callback = _cluster_fd_callback,
.get_main_cluster_fd = _get_main_cluster_fd,
.cluster_do_node_callback = _cluster_do_node_callback,
.is_quorate = _is_quorate,
.get_our_csid = _get_our_csid,
.add_up_node = _add_up_node,
.cluster_closedown = _cluster_closedown,
.sync_lock = _sync_lock,
.sync_unlock = _sync_unlock,
};
struct cluster_ops *init_cman_cluster(void)
{
if (!_init_cluster())
return &_cluster_cman_ops;
else
return NULL;
}

View File

@@ -66,6 +66,7 @@
#include <errno.h>
#include "list.h"
#include "hash.h"
#include "locking.h"
#include "log.h"
#include "lvm-functions.h"
@@ -135,6 +136,61 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
}
static int lock_vg(struct local_client *client)
{
struct hash_table *lock_hash;
struct clvm_header *header =
(struct clvm_header *) client->bits.localsock.cmd;
unsigned char lock_cmd;
unsigned char lock_flags;
char *args = header->node + strlen(header->node) + 1;
int lkid;
int status = 0;
char *lockname;
/* Keep a track of VG locks in our own hash table. In current
practice there should only ever be more than two VGs locked
if a user tries to merge lots of them at once */
if (client->bits.localsock.private) {
lock_hash = (struct hash_table *)client->bits.localsock.private;
}
else {
lock_hash = hash_create(3);
if (!lock_hash)
return ENOMEM;
client->bits.localsock.private = (void *)lock_hash;
}
lock_cmd = args[0];
lock_flags = args[1];
lockname = &args[2];
DEBUGLOG("doing PRE command LOCK_VG '%s' at %x (client=%p)\n", lockname, lock_cmd, client);
if (lock_cmd == LCK_UNLOCK) {
lkid = (int)(long)hash_lookup(lock_hash, lockname);
if (lkid == 0)
return EINVAL;
status = sync_unlock(lockname, lkid);
if (status)
status = errno;
else
hash_remove(lock_hash, lockname);
}
else {
status = sync_lock(lockname, (int)lock_cmd, (int)lock_flags, &lkid);
if (status)
status = errno;
else
hash_insert(lock_hash, lockname, (void *)lkid);
}
return status;
}
/* Pre-command is a good place to get locks that are needed only for the duration
of the commands around the cluster (don't forget to free them in post-command),
and to sanity check the command arguments */
@@ -156,20 +212,7 @@ int do_pre_command(struct local_client *client)
break;
case CLVMD_CMD_LOCK_VG:
lock_cmd = args[0];
lock_flags = args[1];
lockname = &args[2];
DEBUGLOG("doing PRE command LOCK_VG %s at %x\n", lockname,
lock_cmd);
if (lock_cmd == LCK_UNLOCK) {
hold_unlock(lockname);
} else {
status =
hold_lock(lockname, (int) lock_cmd,
(int) lock_flags);
if (status)
status = errno;
}
status = lock_vg(client);
break;
case CLVMD_CMD_LOCK_LV:
@@ -202,6 +245,7 @@ int do_post_command(struct local_client *client)
case CLVMD_CMD_TEST:
status =
sync_unlock("CLVMD_TEST", (int) (long) client->bits.localsock.private);
client->bits.localsock.private = 0;
break;
case CLVMD_CMD_LOCK_VG:
@@ -217,3 +261,25 @@ int do_post_command(struct local_client *client)
}
return status;
}
/* Called when the client is about to be deleted */
void cmd_client_cleanup(struct local_client *client)
{
if (client->bits.localsock.private) {
struct hash_node *v;
struct hash_table *lock_hash =
(struct hash_table *)client->bits.localsock.private;
hash_iterate(v, lock_hash) {
int lkid = (int)(long)hash_get_data(lock_hash, v);
DEBUGLOG("cleanup: Unlocking lkid %x\n", lkid);
sync_unlock("DUMMY", lkid);
}
hash_destroy(lock_hash);
client->bits.localsock.private = 0;
}
}

View File

@@ -22,33 +22,47 @@
struct local_client;
extern int cluster_send_message(void *buf, int msglen, char *csid,
struct cluster_ops {
void (*cluster_init_completed) (void);
int (*cluster_send_message) (void *buf, int msglen, char *csid,
const char *errtext);
extern int name_from_csid(char *csid, char *name);
extern int csid_from_name(char *csid, char *name);
extern int get_num_nodes(void);
extern int cluster_fd_callback(struct local_client *fd, char *buf, int len,
int (*name_from_csid) (char *csid, char *name);
int (*csid_from_name) (char *csid, char *name);
int (*get_num_nodes) (void);
int (*cluster_fd_callback) (struct local_client *fd, char *buf, int len,
char *csid, struct local_client **new_client);
extern int init_cluster(void);
extern int get_main_cluster_fd(void); /* gets accept FD or cman cluster socket */
extern int cluster_do_node_callback(struct local_client *client,
int (*get_main_cluster_fd) (void); /* gets accept FD or cman cluster socket */
int (*cluster_do_node_callback) (struct local_client *client,
void (*callback) (struct local_client *,
char *csid, int node_up));
extern int is_quorate(void);
int (*is_quorate) (void);
extern void get_our_csid(char *csid);
extern void add_up_node(char *csid);
extern void cluster_closedown(void);
void (*get_our_csid) (char *csid);
void (*add_up_node) (char *csid);
void (*cluster_closedown) (void);
extern int sync_lock(const char *resource, int mode, int flags, int *lockid);
extern int sync_unlock(const char *resource, int lockid);
int (*sync_lock) (const char *resource, int mode, int flags, int *lockid);
int (*sync_unlock) (const char *resource, int lockid);
};
#ifdef USE_GULM
#include "tcp-comms.h"
#else
/* cman */
#include "cnxman-socket.h"
#define MAX_CSID_LEN 4
# include "tcp-comms.h"
struct cluster_ops *init_gulm_cluster(void);
#define MAX_CSID_LEN GULM_MAX_CSID_LEN
#define MAX_CLUSTER_MEMBER_NAME_LEN GULM_MAX_CLUSTER_MEMBER_NAME_LEN
#endif
#ifdef USE_CMAN
# include "cnxman-socket.h"
# define CMAN_MAX_CSID_LEN 4
# ifndef MAX_CSID_LEN
# define MAX_CSID_LEN CMAN_MAX_CSID_LEN
# endif
# undef MAX_CLUSTER_MEMBER_NAME_LEN
# define MAX_CLUSTER_MEMBER_NAME_LEN CMAN_MAX_CLUSTER_MEMBER_NAME_LEN
struct cluster_ops *init_cman_cluster(void);
#endif

View File

@@ -72,7 +72,7 @@ static volatile int lock_start_flag;
struct node_info
{
enum {NODE_UNKNOWN, NODE_DOWN, NODE_UP, NODE_CLVMD} state;
char name[MAX_CLUSTER_MEMBER_NAME_LEN];
char name[GULM_MAX_CLUSTER_MEMBER_NAME_LEN];
};
struct lock_wait
@@ -88,6 +88,8 @@ static int read_from_core_sock(struct local_client *client, char *buf, int len,
static int read_from_lock_sock(struct local_client *client, char *buf, int len, char *csid,
struct local_client **new_client);
static int get_all_cluster_nodes(void);
static int _csid_from_name(char *csid, char *name);
static void _cluster_closedown(void);
/* In tcp-comms.c */
extern struct hash_table *sock_hash;
@@ -123,7 +125,7 @@ static lg_lockspace_callbacks_t lock_callbacks;
static void badsig_handler(int sig)
{
DEBUGLOG("got sig %d\n", sig);
cluster_closedown();
_cluster_closedown();
exit(0);
}
@@ -135,15 +137,34 @@ static void sighup_handler(int sig)
get_all_cluster_nodes();
}
int init_cluster()
static int _init_cluster(void)
{
int status;
int ccs_h;
int port = 0;
char *portstr;
/* Get cluster name from CCS */
/* TODO: is this right? */
ccs_h = ccs_connect();
ccs_h = ccs_force_connect(NULL, 0);
if (ccs_h < 0)
{
syslog(LOG_ERR, "Cannot login in to CCSD server\n");
return -1;
}
ccs_get(ccs_h, "//cluster/@name", &cluster_name);
DEBUGLOG("got cluster name %s\n", cluster_name);
if (!ccs_get(ccs_h, "//cluster/clvm/@port", &portstr))
{
port = atoi(portstr);
free(portstr);
DEBUGLOG("got port number %d\n", port);
if (port <= 0 && port >= 65536)
port = 0;
}
ccs_disconnect(ccs_h);
/* Block locking until we are logged in */
@@ -155,7 +176,8 @@ int init_cluster()
lock_hash = hash_create(10);
/* Get all nodes from CCS */
get_all_cluster_nodes();
if (get_all_cluster_nodes())
return -1;
/* Initialise GULM library */
status = lg_initialize(&gulm_if, cluster_name, "clvmd");
@@ -174,7 +196,7 @@ int init_cluster()
}
/* Initialise the inter-node comms */
status = init_comms();
status = init_comms(port);
if (status)
return status;
@@ -221,12 +243,11 @@ int init_cluster()
return 0;
}
void cluster_closedown()
static void _cluster_closedown(void)
{
DEBUGLOG("cluster_closedown\n");
lg_lock_logout(gulm_if);
lg_core_logout(gulm_if);
lg_core_shutdown(gulm_if);
lg_release(gulm_if);
}
@@ -316,11 +337,11 @@ static void set_node_state(struct node_info *ninfo, char *csid, uint8_t nodestat
ninfo->name, ninfo->state, num_nodes);
}
static struct node_info *add_or_set_node(char *name, uint32_t ip, uint8_t state)
static struct node_info *add_or_set_node(char *name, struct in6_addr *ip, uint8_t state)
{
struct node_info *ninfo;
ninfo = hash_lookup_binary(node_hash, (char *)&ip, MAX_CSID_LEN);
ninfo = hash_lookup_binary(node_hash, (char *)ip, GULM_MAX_CSID_LEN);
if (!ninfo)
{
/* If we can't find that node then re-read the config file in case it
@@ -329,7 +350,7 @@ static struct node_info *add_or_set_node(char *name, uint32_t ip, uint8_t state)
get_all_cluster_nodes();
/* Now try again */
ninfo = hash_lookup_binary(node_hash, (char *)&ip, MAX_CSID_LEN);
ninfo = hash_lookup_binary(node_hash, (char *)ip, GULM_MAX_CSID_LEN);
if (!ninfo)
{
DEBUGLOG("Ignoring node %s, not part of the SAN cluster\n", name);
@@ -342,7 +363,12 @@ static struct node_info *add_or_set_node(char *name, uint32_t ip, uint8_t state)
return ninfo;
}
static int core_nodelist(void *misc, lglcb_t type, char *name, uint32_t ip, uint8_t state)
static void _get_our_csid(char *csid)
{
get_our_gulm_csid(csid);
}
static int core_nodelist(void *misc, lglcb_t type, char *name, struct in6_addr *ip, uint8_t state)
{
DEBUGLOG("CORE nodelist\n");
@@ -354,7 +380,7 @@ static int core_nodelist(void *misc, lglcb_t type, char *name, uint32_t ip, uint
{
if (type == lglcb_item)
{
DEBUGLOG("Got nodelist, item: %s, %#x, %#x\n", name, ip, state);
DEBUGLOG("Got nodelist, item: %s, %#x\n", name, state);
add_or_set_node(name, ip, state);
}
@@ -362,14 +388,14 @@ static int core_nodelist(void *misc, lglcb_t type, char *name, uint32_t ip, uint
{
if (type == lglcb_stop)
{
char ourcsid[MAX_CSID_LEN];
char ourcsid[GULM_MAX_CSID_LEN];
DEBUGLOG("Got Nodelist, stop\n");
clvmd_cluster_init_completed();
/* Mark ourself as up */
get_our_csid(ourcsid);
add_up_node(ourcsid);
_get_our_csid(ourcsid);
gulm_add_up_node(ourcsid);
}
else
{
@@ -381,24 +407,24 @@ static int core_nodelist(void *misc, lglcb_t type, char *name, uint32_t ip, uint
return 0;
}
static int core_statechange(void *misc, uint8_t corestate, uint32_t masterip, char *mastername)
static int core_statechange(void *misc, uint8_t corestate, uint8_t quorate, struct in6_addr *masterip, char *mastername)
{
DEBUGLOG("CORE Got statechange corestate:%#x masterip:%#x mastername:%s\n",
corestate, masterip, mastername);
DEBUGLOG("CORE Got statechange corestate:%#x mastername:%s\n",
corestate, mastername);
current_corestate = corestate;
return 0;
}
static int core_nodechange(void *misc, char *nodename, uint32_t nodeip, uint8_t nodestate)
static int core_nodechange(void *misc, char *nodename, struct in6_addr *nodeip, uint8_t nodestate)
{
struct node_info *ninfo;
DEBUGLOG("CORE node change, name=%s, ip=%x, state = %d\n", nodename, nodeip, nodestate);
DEBUGLOG("CORE node change, name=%s, state = %d\n", nodename, nodestate);
/* If we don't get nodeip here, try a lookup by name */
if (!nodeip)
csid_from_name((char *)&nodeip, nodename);
_csid_from_name((char *)nodeip, nodename);
if (!nodeip)
return 0;
@@ -443,7 +469,9 @@ static int lock_login_reply(void *misc, uint32_t error, uint8_t which)
return 0;
}
static int lock_lock_state(void *misc, uint8_t *key, uint16_t keylen, uint8_t state, uint32_t flags, uint32_t error,
static int lock_lock_state(void *misc, uint8_t *key, uint16_t keylen,
uint64_t subid, uint64_t start, uint64_t stop,
uint8_t state, uint32_t flags, uint32_t error,
uint8_t *LVB, uint16_t LVBlen)
{
struct lock_wait *lwait;
@@ -519,19 +547,18 @@ int get_next_node_csid(void **context, char *csid)
return 0;
}
memcpy(csid, hash_get_key(node_hash, *context), MAX_CSID_LEN);
memcpy(csid, hash_get_key(node_hash, *context), GULM_MAX_CSID_LEN);
return 1;
}
int name_from_csid(char *csid, char *name)
int gulm_name_from_csid(char *csid, char *name)
{
struct node_info *ninfo;
ninfo = hash_lookup_binary(node_hash, csid, MAX_CSID_LEN);
ninfo = hash_lookup_binary(node_hash, csid, GULM_MAX_CSID_LEN);
if (!ninfo)
{
sprintf(name, "UNKNOWN [%d.%d.%d.%d]",
csid[0], csid[1], csid[2], csid[3]);
sprintf(name, "UNKNOWN %s", print_csid(csid));
return -1;
}
@@ -540,7 +567,7 @@ int name_from_csid(char *csid, char *name)
}
int csid_from_name(char *csid, char *name)
static int _csid_from_name(char *csid, char *name)
{
struct hash_node *hn;
struct node_info *ninfo;
@@ -550,25 +577,25 @@ int csid_from_name(char *csid, char *name)
ninfo = hash_get_data(node_hash, hn);
if (strcmp(ninfo->name, name) == 0)
{
memcpy(csid, hash_get_key(node_hash, hn), MAX_CSID_LEN);
memcpy(csid, hash_get_key(node_hash, hn), GULM_MAX_CSID_LEN);
return 0;
}
}
return -1;
}
int get_num_nodes()
static int _get_num_nodes()
{
DEBUGLOG("num_nodes = %d\n", num_nodes);
return num_nodes;
}
/* Node is now known to be running a clvmd */
void add_up_node(char *csid)
void gulm_add_up_node(char *csid)
{
struct node_info *ninfo;
ninfo = hash_lookup_binary(node_hash, csid, MAX_CSID_LEN);
ninfo = hash_lookup_binary(node_hash, csid, GULM_MAX_CSID_LEN);
if (!ninfo)
return;
@@ -581,7 +608,7 @@ void add_down_node(char *csid)
{
struct node_info *ninfo;
ninfo = hash_lookup_binary(node_hash, csid, MAX_CSID_LEN);
ninfo = hash_lookup_binary(node_hash, csid, GULM_MAX_CSID_LEN);
if (!ninfo)
return;
@@ -594,7 +621,7 @@ void add_down_node(char *csid)
}
/* Call a callback for each node, so the caller knows whether it's up or down */
int cluster_do_node_callback(struct local_client *master_client,
static int _cluster_do_node_callback(struct local_client *master_client,
void (*callback)(struct local_client *, char *csid, int node_up))
{
struct hash_node *hn;
@@ -602,15 +629,15 @@ int cluster_do_node_callback(struct local_client *master_client,
hash_iterate(hn, node_hash)
{
char csid[MAX_CSID_LEN];
char csid[GULM_MAX_CSID_LEN];
struct local_client *client;
ninfo = hash_get_data(node_hash, hn);
memcpy(csid, hash_get_key(node_hash, hn), MAX_CSID_LEN);
memcpy(csid, hash_get_key(node_hash, hn), GULM_MAX_CSID_LEN);
DEBUGLOG("down_callback. node %s, state = %d\n", ninfo->name, ninfo->state);
client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
if (client)
callback(master_client, csid, ninfo->state == NODE_CLVMD);
}
@@ -661,6 +688,7 @@ static int _lock_resource(char *resource, int mode, int flags, int *lockid)
DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
status = lg_lock_state_req(gulm_if, resource, strlen(resource)+1,
0, 0, 0,
mode, flags, NULL, 0);
if (status)
{
@@ -692,6 +720,7 @@ static int _unlock_resource(char *resource, int lockid)
DEBUGLOG("unlock_resource %s\n", resource);
status = lg_lock_state_req(gulm_if, resource, strlen(resource)+1,
0, 0, 0,
lg_lock_state_Unlock, 0, NULL, 0);
if (status)
@@ -720,7 +749,7 @@ static int _unlock_resource(char *resource, int lockid)
To aid unlocking, we store the lock mode in the lockid (as GULM
doesn't use this).
*/
int sync_lock(const char *resource, int mode, int flags, int *lockid)
static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
{
int status;
char lock1[strlen(resource)+3];
@@ -764,7 +793,7 @@ int sync_lock(const char *resource, int mode, int flags, int *lockid)
return status;
}
int sync_unlock(const char *resource, int lockid)
static int _sync_unlock(const char *resource, int lockid)
{
int status = 0;
char lock1[strlen(resource)+3];
@@ -800,7 +829,7 @@ int sync_unlock(const char *resource, int lockid)
return status;
}
int is_quorate()
static int _is_quorate()
{
if (current_corestate == lg_core_Slave ||
current_corestate == lg_core_Master ||
@@ -819,31 +848,43 @@ static int get_all_cluster_nodes()
int ctree;
char *nodename;
int error;
int i;
/* Open the config file */
ctree = ccs_connect();
if (ctree <= 0)
ctree = ccs_force_connect(NULL, 1);
if (ctree < 0)
{
log_error("Error connecting to CCS");
return -1;
}
error = ccs_get(ctree, "//nodes/node/@name", &nodename);
while (nodename)
for (i=1;;i++)
{
char nodeip[MAX_CSID_LEN];
char *clvmflag;
char nodekey[256];
char nodeip[GULM_MAX_CSID_LEN];
int clvmflag = 1;
char *clvmflagstr;
char key[256];
sprintf(key, "//nodes/node[@name=\"%s\"]/clvm", nodename);
ccs_get(ctree, key, &clvmflag);
sprintf(nodekey, "//cluster/clusternodes/clusternode[%d]/@name", i);
error = ccs_get(ctree, nodekey, &nodename);
if (error)
break;
if ((get_ip_address(nodename, nodeip) == 0) && atoi(clvmflag))
sprintf(key, "//cluster/clusternodes/clusternode[@name=\"%s\"]/clvm", nodename);
if (!ccs_get(ctree, key, &clvmflagstr))
{
clvmflag = atoi(clvmflagstr);
free(clvmflagstr);
}
DEBUGLOG("Got node %s from ccs(clvmflag = %d)\n", nodename, clvmflag);
if ((get_ip_address(nodename, nodeip) == 0) && clvmflag)
{
struct node_info *ninfo;
/* If it's not in the list, then add it */
ninfo = hash_lookup_binary(node_hash, nodeip, MAX_CSID_LEN);
ninfo = hash_lookup_binary(node_hash, nodeip, GULM_MAX_CSID_LEN);
if (!ninfo)
{
ninfo = malloc(sizeof(struct node_info));
@@ -856,16 +897,14 @@ static int get_all_cluster_nodes()
strcpy(ninfo->name, nodename);
ninfo->state = NODE_DOWN;
hash_insert_binary(node_hash, nodeip, MAX_CSID_LEN, ninfo);
hash_insert_binary(node_hash, nodeip, GULM_MAX_CSID_LEN, ninfo);
}
}
else
{
DEBUGLOG("node %s has clvm disabled\n", nodename);
}
if (clvmflag) free(clvmflag);
free(nodename);
error = ccs_get(ctree, "//nodes/node/@name", &nodename);
}
/* Finished with config file */
@@ -874,7 +913,47 @@ static int get_all_cluster_nodes()
return 0;
}
int gulm_fd(void)
static void _cluster_init_completed(void)
{
return lg_core_selector(gulm_if);
clvmd_cluster_init_completed();
}
static int _get_main_cluster_fd(void)
{
return get_main_gulm_cluster_fd();
}
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid, struct local_client **new_client)
{
return cluster_fd_gulm_callback(fd, buf, len, csid, new_client);
}
static int _cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
{
return gulm_cluster_send_message(buf, msglen, csid, errtext);
}
static struct cluster_ops _cluster_gulm_ops = {
.cluster_init_completed = _cluster_init_completed,
.cluster_send_message = _cluster_send_message,
.name_from_csid = gulm_name_from_csid,
.csid_from_name = _csid_from_name,
.get_num_nodes = _get_num_nodes,
.cluster_fd_callback = _cluster_fd_callback,
.get_main_cluster_fd = _get_main_cluster_fd,
.cluster_do_node_callback = _cluster_do_node_callback,
.is_quorate = _is_quorate,
.get_our_csid = _get_our_csid,
.add_up_node = gulm_add_up_node,
.cluster_closedown = _cluster_closedown,
.sync_lock = _sync_lock,
.sync_unlock = _sync_unlock,
};
struct cluster_ops *init_gulm_cluster(void)
{
if (!_init_cluster())
return &_cluster_gulm_ops;
else
return NULL;
}

View File

@@ -7,3 +7,6 @@ extern int gulm_fd(void);
extern int get_ip_address(char *node, char *addr);
extern void tcp_remove_client(char *csid);
extern int alloc_client(int fd, char *csid, struct local_client **new_client);
void gulm_add_up_node(char *csid);
int gulm_name_from_csid(char *csid, char *name);

View File

@@ -39,6 +39,7 @@
#include "clvmd-comms.h"
#include "lvm-functions.h"
#include "clvm.h"
#include "version.h"
#include "clvmd.h"
#include "libdlm.h"
#include "system-lv.h"
@@ -54,9 +55,9 @@
/* The maximum size of a message that will fit into a packet. Anything bigger
than this is sent via the system LV */
#define MAX_INLINE_MESSAGE (MAX_CLUSTER_MESSAGE-sizeof(struct clvm_header))
#define MAX_INLINE_MESSAGE (max_cluster_message-sizeof(struct clvm_header))
#define ISLOCAL_CSID(c) (memcmp(c, our_csid, MAX_CSID_LEN) == 0)
#define ISLOCAL_CSID(c) (memcmp(c, our_csid, max_csid_len) == 0)
/* Head of the fd list. Also contains
the cluster_socket details */
@@ -64,7 +65,12 @@ static struct local_client local_client_head;
static unsigned short global_xid = 0; /* Last transaction ID issued */
static struct cluster_ops *clops = NULL;
static char our_csid[MAX_CSID_LEN];
static unsigned max_csid_len;
static unsigned max_cluster_message;
static unsigned max_cluster_member_name_len;
/* Structure of items on the LVM thread list */
struct lvm_thread_cmd {
@@ -82,6 +88,14 @@ static pthread_mutex_t lvm_thread_mutex;
static pthread_cond_t lvm_thread_cond;
static struct list lvm_cmd_head;
static int quit = 0;
static int child_pipe[2];
/* Reasons the daemon failed initialisation */
#define DFAIL_INIT 1
#define DFAIL_LOCAL_SOCK 2
#define DFAIL_CLUSTER_IF 3
#define DFAIL_MALLOC 4
#define SUCCESS 0
/* Prototypes for code further down */
static void sigusr2_handler(int sig);
@@ -129,6 +143,18 @@ static void usage(char *prog, FILE *file)
fprintf(file, "\n");
}
/* Called to signal the parent how well we got on during initialisation */
static void child_init_signal(int status)
{
if (child_pipe[1]) {
write(child_pipe[1], &status, sizeof(status));
close(child_pipe[1]);
}
if (status)
exit(status);
}
int main(int argc, char *argv[])
{
int local_sock;
@@ -166,7 +192,8 @@ int main(int argc, char *argv[])
break;
case 'V':
printf("\nCluster LVM Daemon version %d.%d.%d\n\n",
printf("Cluster LVM daemon version: %s\n", LVM_VERSION);
printf("Protocol version: %d.%d.%d\n",
CLVMD_MAJOR_VERSION, CLVMD_MINOR_VERSION,
CLVMD_PATCH_VERSION);
exit(1);
@@ -188,14 +215,12 @@ int main(int argc, char *argv[])
but the cluster is not ready yet */
local_sock = open_local_sock();
if (local_sock < 0)
exit(2);
child_init_signal(DFAIL_LOCAL_SOCK);
/* Set up signal handlers, USR1 is for cluster change notifications (in cman)
USR2 causes child threads to exit.
PIPE should be ignored */
signal(SIGUSR2, sigusr2_handler);
signal(SIGTERM, sigterm_handler);
signal(SIGINT, sigterm_handler);
signal(SIGPIPE, SIG_IGN);
/* Block SIGUSR2 in the main process */
@@ -210,26 +235,42 @@ int main(int argc, char *argv[])
init_lvhash();
/* Start the cluster interface */
if (init_cluster()) {
#ifdef USE_CMAN
if ((clops = init_cman_cluster())) {
max_csid_len = CMAN_MAX_CSID_LEN;
max_cluster_message = CMAN_MAX_CLUSTER_MESSAGE;
max_cluster_member_name_len = CMAN_MAX_CLUSTER_MEMBER_NAME_LEN;
}
#endif
#ifdef USE_GULM
if (!clops)
if ((clops = init_gulm_cluster())) {
max_csid_len = GULM_MAX_CSID_LEN;
max_cluster_message = GULM_MAX_CLUSTER_MESSAGE;
max_cluster_member_name_len = GULM_MAX_CLUSTER_MEMBER_NAME_LEN;
}
#endif
if (!clops) {
DEBUGLOG("Can't initialise cluster interface\n");
log_error("Can't initialise cluster interface\n");
exit(5);
child_init_signal(DFAIL_CLUSTER_IF);
}
DEBUGLOG("Cluster ready, doing some more initialisation\n");
/* Save our CSID */
uname(&nodeinfo);
get_our_csid(our_csid);
clops->get_our_csid(our_csid);
/* Initialise the FD list head */
local_client_head.fd = get_main_cluster_fd();
local_client_head.fd = clops->get_main_cluster_fd();
local_client_head.type = CLUSTER_MAIN_SOCK;
local_client_head.callback = cluster_fd_callback;
local_client_head.callback = clops->cluster_fd_callback;
/* Add the local socket to the list */
newfd = malloc(sizeof(struct local_client));
if (!newfd)
exit(2);
child_init_signal(DFAIL_MALLOC);
newfd->fd = local_sock;
newfd->type = LOCAL_RENDEZVOUS;
@@ -242,15 +283,19 @@ int main(int argc, char *argv[])
DEBUGLOG("starting LVM thread\n");
pthread_create(&lvm_thread, NULL, lvm_thread_fn, nodeinfo.nodename);
#ifndef USE_GULM
/* Tell the rest of the cluster our version number */
/* CMAN can do this immediately, gulm needs to wait until
the core initialisation has finished and the node list
has been gathered */
send_version_message();
#endif
if (clops->cluster_init_completed)
clops->cluster_init_completed();
DEBUGLOG("clvmd ready for work\n");
child_init_signal(SUCCESS);
/* Try to shutdown neatly */
signal(SIGTERM, sigterm_handler);
signal(SIGINT, sigterm_handler);
/* Do some work */
main_loop(local_sock, cmd_timeout);
@@ -303,6 +348,7 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
newfd->bits.localsock.threadid = 0;
newfd->bits.localsock.finished = 0;
newfd->bits.localsock.pipe_client = NULL;
newfd->bits.localsock.private = NULL;
newfd->bits.localsock.all_success = 1;
DEBUGLOG("Got new connection on fd %d\n", newfd->fd);
*new_client = newfd;
@@ -391,9 +437,9 @@ static void timedout_callback(struct local_client *client, char *csid,
{
if (node_up) {
struct node_reply *reply;
char nodename[MAX_CLUSTER_MEMBER_NAME_LEN];
char nodename[max_cluster_member_name_len];
name_from_csid(csid, nodename);
clops->name_from_csid(csid, nodename);
DEBUGLOG("PJC: checking for a reply from %s\n", nodename);
pthread_mutex_lock(&client->bits.localsock.reply_mutex);
@@ -422,7 +468,7 @@ static void timedout_callback(struct local_client *client, char *csid,
static void request_timed_out(struct local_client *client)
{
DEBUGLOG("Request timed-out. padding\n");
cluster_do_node_callback(client, timedout_callback);
clops->cluster_do_node_callback(client, timedout_callback);
if (client->bits.localsock.num_replies !=
client->bits.localsock.expected_replies) {
@@ -447,7 +493,7 @@ static void main_loop(int local_sock, int cmd_timeout)
int select_status;
struct local_client *thisfd;
struct timeval tv = { cmd_timeout, 0 };
int quorate = is_quorate();
int quorate = clops->is_quorate();
/* Wait on the cluster FD and all local sockets/pipes */
FD_ZERO(&in);
@@ -461,9 +507,8 @@ static void main_loop(int local_sock, int cmd_timeout)
if ((select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv)) > 0) {
struct local_client *lastfd = NULL;
struct clvm_header *inheader;
char csid[MAX_CSID_LEN];
char buf[MAX_CLUSTER_MESSAGE];
char buf[max_cluster_message];
for (thisfd = &local_client_head; thisfd != NULL;
thisfd = thisfd->next) {
@@ -490,12 +535,12 @@ static void main_loop(int local_sock, int cmd_timeout)
type == CLUSTER_INTERNAL)
goto closedown;
DEBUGLOG
("ret == %d, errno = %d. removing client\n",
ret, errno);
DEBUGLOG("ret == %d, errno = %d. removing client\n",
ret, errno);
lastfd->next = thisfd->next;
free_fd = thisfd;
thisfd = lastfd;
cmd_client_cleanup(free_fd);
free(free_fd);
break;
}
@@ -506,33 +551,6 @@ static void main_loop(int local_sock, int cmd_timeout)
thisfd->next = newfd;
break;
}
switch (thisfd->type) {
case CLUSTER_MAIN_SOCK:
case CLUSTER_DATA_SOCK:
inheader =
(struct clvm_header *) buf;
ntoh_clvm(inheader); /* Byteswap fields */
if (inheader->cmd ==
CLVMD_CMD_REPLY)
process_reply
(inheader, ret,
csid);
else
add_to_lvmqueue(thisfd,
inheader,
ret,
csid);
break;
/* All the work for these is done in the callback
rightly or wrongly... */
case LOCAL_RENDEZVOUS:
case LOCAL_SOCK:
case THREAD_PIPE:
case CLUSTER_INTERNAL:
break;
}
}
lastfd = thisfd;
}
@@ -575,30 +593,69 @@ static void main_loop(int local_sock, int cmd_timeout)
}
closedown:
cluster_closedown();
clops->cluster_closedown();
close(local_sock);
}
/* Fork into the background and detach from our parent process */
/*
* 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()
{
pid_t pid;
pid_t pid;
int child_status;
int devnull = open("/dev/null", O_RDWR);
if (devnull == -1) {
perror("Can't open /dev/null");
exit(3);
}
pipe(child_pipe);
switch (pid = fork()) {
case -1:
perror("clvmd: can't fork");
exit(2);
case 0: /* child */
case 0: /* Child */
close(child_pipe[0]);
break;
default: /* Parent */
exit(0);
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);
}
}
/* Detach ourself from the calling environment */
@@ -717,6 +774,7 @@ static int read_from_local_sock(struct local_client *thisfd)
struct local_client *newfd;
char csid[MAX_CSID_LEN];
struct clvm_header *inheader;
int status;
inheader = (struct clvm_header *) buffer;
@@ -791,7 +849,7 @@ static int read_from_local_sock(struct local_client *thisfd)
}
/* Check the node name for validity */
if (inheader->node[0] && csid_from_name(csid, inheader->node)) {
if (inheader->node[0] && clops->csid_from_name(csid, inheader->node)) {
/* Error, node is not in the cluster */
struct clvm_header reply;
DEBUGLOG("Unknown node: '%s'\n", inheader->node);
@@ -863,8 +921,10 @@ static int read_from_local_sock(struct local_client *thisfd)
/* Run the pre routine */
thisfd->bits.localsock.in_progress = TRUE;
thisfd->bits.localsock.state = PRE_COMMAND;
pthread_create(&thisfd->bits.localsock.threadid, NULL,
DEBUGLOG("Creating pre&post thread\n");
status = pthread_create(&thisfd->bits.localsock.threadid, NULL,
pre_and_post_thread, thisfd);
DEBUGLOG("Created pre&post thread, state = %d\n", status);
}
return len;
}
@@ -921,7 +981,7 @@ static int distribute_command(struct local_client *thisfd)
/* if node is empty then do it on the whole cluster */
if (inheader->node[0] == '\0') {
thisfd->bits.localsock.expected_replies =
get_num_nodes();
clops->get_num_nodes();
thisfd->bits.localsock.num_replies = 0;
thisfd->bits.localsock.sent_time = time(NULL);
thisfd->bits.localsock.in_progress = TRUE;
@@ -942,7 +1002,7 @@ static int distribute_command(struct local_client *thisfd)
/* Do it on a single node */
char csid[MAX_CSID_LEN];
if (csid_from_name(csid, inheader->node)) {
if (clops->csid_from_name(csid, inheader->node)) {
/* This has already been checked so should not happen */
return 0;
} else {
@@ -952,7 +1012,7 @@ static int distribute_command(struct local_client *thisfd)
thisfd->bits.localsock.in_progress = TRUE;
/* Are we the requested node ?? */
if (memcmp(csid, our_csid, MAX_CSID_LEN) == 0) {
if (memcmp(csid, our_csid, max_csid_len) == 0) {
DEBUGLOG("Doing command on local node only\n");
add_to_lvmqueue(thisfd, inheader, len, NULL);
} else {
@@ -984,14 +1044,14 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
char *csid)
{
char *replyargs;
char nodename[MAX_CLUSTER_MEMBER_NAME_LEN];
char nodename[max_cluster_member_name_len];
int replylen = 0;
int buflen = MAX_CLUSTER_MESSAGE - sizeof(struct clvm_header) - 1;
int buflen = max_cluster_message - sizeof(struct clvm_header) - 1;
int status;
int msg_malloced = 0;
/* Get the node name as we /may/ need it later */
name_from_csid(csid, nodename);
clops->name_from_csid(csid, nodename);
DEBUGLOG("process_remote_command %d for clientid 0x%x on node %s\n",
msg->cmd, msg->clientid, nodename);
@@ -1057,7 +1117,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
if (msg->cmd == CLVMD_CMD_VERSION) {
int *version_nums = (int *) msg->args;
char node[256];
name_from_csid(csid, node);
clops->name_from_csid(csid, node);
DEBUGLOG("Remote node %s is version %d.%d.%d\n",
node,
ntohl(version_nums[0]),
@@ -1078,17 +1138,17 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
byebyemsg.flags = 0;
byebyemsg.arglen = 0;
byebyemsg.clientid = 0;
cluster_send_message(&byebyemsg, sizeof(byebyemsg),
clops->cluster_send_message(&byebyemsg, sizeof(byebyemsg),
our_csid,
"Error Sending GOAWAY message");
} else {
add_up_node(csid);
clops->add_up_node(csid);
}
return;
}
/* Allocate a default reply buffer */
replyargs = malloc(MAX_CLUSTER_MESSAGE - sizeof(struct clvm_header));
replyargs = malloc(max_cluster_message - sizeof(struct clvm_header));
if (replyargs != NULL) {
/* Run the command */
@@ -1188,7 +1248,7 @@ static void add_reply_to_list(struct local_client *client, int status,
reply = malloc(sizeof(struct node_reply));
if (reply) {
reply->status = status;
name_from_csid(csid, reply->node);
clops->name_from_csid(csid, reply->node);
DEBUGLOG("Reply from node %s: %d bytes\n", reply->node, len);
if (len > 0) {
@@ -1273,6 +1333,7 @@ static void *pre_and_post_thread(void *arg)
DEBUGLOG("Got post command condition...\n");
status = 0;
do_post_command(client);
write(pipe_fd, &status, sizeof(int));
@@ -1292,7 +1353,8 @@ static void *pre_and_post_thread(void *arg)
DEBUGLOG("Got pre command condition...\n");
}
DEBUGLOG("Subthread finished\n");
return (void *) 0;
pthread_exit((void *) 0);
return 0;
}
/* Process a command on the local node and store the result */
@@ -1300,8 +1362,8 @@ static int process_local_command(struct clvm_header *msg, int msglen,
struct local_client *client,
unsigned short xid)
{
char *replybuf = malloc(MAX_CLUSTER_MESSAGE);
int buflen = MAX_CLUSTER_MESSAGE - sizeof(struct clvm_header) - 1;
char *replybuf = malloc(max_cluster_message);
int buflen = max_cluster_message - sizeof(struct clvm_header) - 1;
int replylen = 0;
int status;
@@ -1465,7 +1527,7 @@ static void send_version_message()
version_nums[1] = htonl(CLVMD_MINOR_VERSION);
version_nums[2] = htonl(CLVMD_PATCH_VERSION);
cluster_send_message(message, sizeof(message), NULL,
clops->cluster_send_message(message, sizeof(message), NULL,
"Error Sending version number");
}
@@ -1478,7 +1540,7 @@ static int send_message(void *buf, int msglen, char *csid, int fd,
/* Send remote messages down the cluster socket */
if (csid == NULL || !ISLOCAL_CSID(csid)) {
hton_clvm((struct clvm_header *) buf); /* Byte swap if necessary */
return cluster_send_message(buf, msglen, csid, errtext);
return clops->cluster_send_message(buf, msglen, csid, errtext);
} else {
int ptr = 0;
@@ -1579,7 +1641,7 @@ static int add_to_lvmqueue(struct local_client *client, struct clvm_header *msg,
cmd->xid = client->xid;
memcpy(cmd->msg, msg, msglen);
if (csid) {
memcpy(cmd->csid, csid, MAX_CSID_LEN);
memcpy(cmd->csid, csid, max_csid_len);
cmd->remote = 1;
} else {
cmd->remote = 0;
@@ -1630,6 +1692,19 @@ static int open_local_sock()
return local_socket;
}
void process_message(struct local_client *client, char *buf, int len, char *csid)
{
struct clvm_header *inheader;
inheader = (struct clvm_header *) buf;
ntoh_clvm(inheader); /* Byteswap fields */
if (inheader->cmd == CLVMD_CMD_REPLY)
process_reply(inheader, len, csid);
else
add_to_lvmqueue(client, inheader, len, csid);
}
static void check_all_callback(struct local_client *client, char *csid,
int node_up)
{
@@ -1644,7 +1719,7 @@ static void check_all_callback(struct local_client *client, char *csid,
static int check_all_clvmds_running(struct local_client *client)
{
DEBUGLOG("check_all_clvmds_running\n");
return cluster_do_node_callback(client, check_all_callback);
return clops->cluster_do_node_callback(client, check_all_callback);
}
/* Return a local_client struct given a client ID.
@@ -1681,7 +1756,6 @@ static void ntoh_clvm(struct clvm_header *hdr)
static void sigusr2_handler(int sig)
{
DEBUGLOG("SIGUSR2 received\n");
pthread_exit((void *) -1);
return;
}
@@ -1691,3 +1765,14 @@ static void sigterm_handler(int sig)
quit = 1;
return;
}
int sync_lock(const char *resource, int mode, int flags, int *lockid)
{
return clops->sync_lock(resource, mode, flags, lockid);
}
int sync_unlock(const char *resource, int lockid)
{
return clops->sync_unlock(resource, lockid);
}

View File

@@ -93,7 +93,7 @@ struct local_client {
struct netsock_bits net;
} bits;
};
#define DEBUG
#ifdef DEBUG
#define DEBUGLOG(fmt, args...) fprintf(stderr, "CLVMD[%d]: %ld ", getpid(), time(NULL) ); fprintf(stderr, fmt, ## args)
#else
@@ -111,9 +111,13 @@ extern int do_command(struct local_client *client, struct clvm_header *msg,
/* Pre and post command routines are called only on the local node */
extern int do_pre_command(struct local_client *client);
extern int do_post_command(struct local_client *client);
extern void cmd_client_cleanup(struct local_client *client);
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);
int sync_lock(const char *resource, int mode, int flags, int *lockid);
int sync_unlock(const char *resource, int lockid);
#endif

View File

@@ -63,8 +63,8 @@
/* Maximum size of a cluster message */
#define MAX_CLUSTER_MESSAGE 1500
#define MAX_CLUSTER_MEMBER_NAME_LEN 255
#define CMAN_MAX_CLUSTER_MESSAGE 1500
#define CMAN_MAX_CLUSTER_MEMBER_NAME_LEN 255
#define MAX_BARRIER_NAME_LEN 33
#define MAX_SA_ADDR_LEN 12
#define MAX_CLUSTER_NAME_LEN 16
@@ -105,6 +105,7 @@
#define MSG_MULTICAST 0x080000 /* Message was sent to all nodes in the cluster
*/
#define MSG_ALLINT 0x100000 /* Send out of all interfaces */
#define MSG_REPLYEXP 0x200000 /* Reply is expected */
typedef enum { NODESTATE_REMOTEMEMBER, NODESTATE_JOINING, NODESTATE_MEMBER,
NODESTATE_DEAD } nodestate_t;
@@ -146,7 +147,7 @@ struct cl_cluster_node {
unsigned int leave_reason;
unsigned int incarnation;
nodestate_t state;
char name[MAX_CLUSTER_MEMBER_NAME_LEN];
char name[CMAN_MAX_CLUSTER_MEMBER_NAME_LEN];
unsigned char votes;
};

View File

@@ -46,6 +46,7 @@
static struct cmd_context *cmd = NULL;
static struct hash_table *lv_hash = NULL;
static pthread_mutex_t lv_hash_lock;
struct lv_info {
int lock_id;
@@ -57,7 +58,9 @@ static int get_current_lock(char *resource)
{
struct lv_info *lvi;
pthread_mutex_lock(&lv_hash_lock);
lvi = hash_lookup(lv_hash, resource);
pthread_mutex_unlock(&lv_hash_lock);
if (lvi) {
return lvi->lock_mode;
} else {
@@ -69,11 +72,14 @@ static int get_current_lock(char *resource)
void unlock_all()
{
struct hash_node *v;
pthread_mutex_lock(&lv_hash_lock);
hash_iterate(v, lv_hash) {
struct lv_info *lvi = hash_get_data(lv_hash, v);
sync_unlock(hash_get_key(lv_hash, v), lvi->lock_id);
}
pthread_mutex_unlock(&lv_hash_lock);
}
/* Gets a real lock and keeps the info in the hash table */
@@ -85,7 +91,9 @@ int hold_lock(char *resource, int mode, int flags)
flags &= LKF_NOQUEUE; /* Only LKF_NOQUEUE is valid here */
pthread_mutex_lock(&lv_hash_lock);
lvi = hash_lookup(lv_hash, resource);
pthread_mutex_unlock(&lv_hash_lock);
if (lvi) {
/* Already exists - convert it */
status =
@@ -113,7 +121,9 @@ int hold_lock(char *resource, int mode, int flags)
DEBUGLOG("hold_lock. lock at %d failed: %s\n", mode,
strerror(errno));
} else {
pthread_mutex_lock(&lv_hash_lock);
hash_insert(lv_hash, resource, lvi);
pthread_mutex_unlock(&lv_hash_lock);
}
errno = saved_errno;
}
@@ -127,8 +137,9 @@ int hold_unlock(char *resource)
int status;
int saved_errno;
pthread_mutex_lock(&lv_hash_lock);
lvi = hash_lookup(lv_hash, resource);
pthread_mutex_unlock(&lv_hash_lock);
if (!lvi) {
DEBUGLOG("hold_unlock, lock not already held\n");
return 0;
@@ -137,7 +148,9 @@ int hold_unlock(char *resource)
status = sync_unlock(resource, lvi->lock_id);
saved_errno = errno;
if (!status) {
pthread_mutex_lock(&lv_hash_lock);
hash_remove(lv_hash, resource);
pthread_mutex_unlock(&lv_hash_lock);
free(lvi);
} else {
DEBUGLOG("hold_unlock. unlock failed(%d): %s\n", status,
@@ -185,7 +198,7 @@ static int do_activate_lv(char *resource, int mode)
return errno;
/* If it's suspended then resume it */
if (!lv_info_by_lvid(cmd, resource, &lvi))
if (!lv_info_by_lvid(cmd, resource, &lvi, 0))
return EIO;
if (lvi.suspended)
@@ -231,7 +244,7 @@ static int do_suspend_lv(char *resource)
}
/* Only suspend it if it exists */
if (!lv_info_by_lvid(cmd, resource, &lvi))
if (!lv_info_by_lvid(cmd, resource, &lvi, 0))
return EIO;
if (lvi.exists) {
@@ -350,7 +363,7 @@ int post_lock_lv(unsigned char command, unsigned char lock_flags,
if (oldmode == LKM_PWMODE) {
struct lvinfo lvi;
if (!lv_info_by_lvid(cmd, resource, &lvi))
if (!lv_info_by_lvid(cmd, resource, &lvi, 0))
return EIO;
if (lvi.exists) {
@@ -394,9 +407,11 @@ static void *get_initial_state()
return NULL;
while (fgets(line, sizeof(line), lvs)) {
if (sscanf(line, "%s %s %s\n", vg, lv, flags) == 3) {
if (sscanf(line, "%s %s %s\n", vg, lv, flags) == 3) {
/* States: s:suspended a:active S:dropped snapshot I:invalid snapshot */
if (flags[4] == 'a' || flags[4] == 's') { /* is it active or suspended? */
if (strlen(vg) == 38 && /* is is a valid UUID ? */
(flags[4] == 'a' || flags[4] == 's')) { /* is it active or suspended? */
/* Convert hyphen-separated UUIDs into one */
memcpy(&uuid[0], &vg[0], 6);
memcpy(&uuid[6], &vg[7], 4);
@@ -427,6 +442,7 @@ void init_lvhash()
{
/* Create hash table for keeping LV locks & status */
lv_hash = hash_create(100);
pthread_mutex_init(&lv_hash_lock, NULL);
}
/* Called to initialise the LVM context of the daemon */

View File

@@ -42,7 +42,9 @@
#include "list.h"
#include "locking.h"
#include "system-lv.h"
#include "clvm.h"
#include "clvmd-comms.h"
#include "clvmd.h"
#ifdef HAVE_CCS
#include "ccs.h"
#endif

View File

@@ -34,7 +34,6 @@
#include <netdb.h>
#include <assert.h>
#include "ccs.h"
#include "clvm.h"
#include "clvmd-comms.h"
#include "clvmd.h"
@@ -47,43 +46,19 @@ static int listen_fd = -1;
static int tcp_port;
struct hash_table *sock_hash;
static int get_tcp_port(int default_port);
static int get_our_ip_address(char *addr, int *family);
static int read_from_tcpsock(struct local_client *fd, char *buf, int len, char *csid,
struct local_client **new_client);
/* Called by init_cluster() to open up the listening socket */
// TODO: IPv6 compat.
int init_comms()
int init_comms(unsigned short port)
{
struct sockaddr *addr = NULL;
struct sockaddr_in addr4;
struct sockaddr_in6 addr6;
int addr_len;
int family;
char address[MAX_CSID_LEN];
struct sockaddr_in6 addr;
sock_hash = hash_create(100);
tcp_port = get_tcp_port(DEFAULT_TCP_PORT);
tcp_port = port ? port : DEFAULT_TCP_PORT;
/* Get IP address and IP type */
get_our_ip_address(address, &family);
if (family == AF_INET)
{
memcpy(&addr4.sin_addr, addr, sizeof(struct in_addr));
addr = (struct sockaddr *)&addr4;
addr4.sin_port = htons(tcp_port);
addr_len = sizeof(addr4);
}
else
{
memcpy(&addr6.sin6_addr, addr, sizeof(struct in6_addr));
addr = (struct sockaddr *)&addr6;
addr6.sin6_port = htons(tcp_port);
addr_len = sizeof(addr6);
}
listen_fd = socket(family, SOCK_STREAM, 0);
listen_fd = socket(AF_INET6, SOCK_STREAM, 0);
if (listen_fd < 0)
{
@@ -95,11 +70,13 @@ int init_comms()
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
}
addr->sa_family = family;
memset(&addr, 0, sizeof(addr)); // Bind to INADDR_ANY
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(tcp_port);
if (bind(listen_fd, addr, addr_len) < 0)
if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
DEBUGLOG("Can't bind to port\n");
DEBUGLOG("Can't bind to port: %s\n", strerror(errno));
syslog(LOG_ERR, "Can't bind to port %d, is clvmd already running ?", tcp_port);
close(listen_fd);
return -1;
@@ -119,19 +96,19 @@ void tcp_remove_client(char *csid)
job of clvmd.c whch will do the job when it notices the
other end has gone. We just need to remove the client(s) from
the hash table so we don't try to use it for sending any more */
client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
if (client)
{
hash_remove_binary(sock_hash, csid, MAX_CSID_LEN);
hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
}
/* Look for a mangled one too */
csid[0] ^= 0x80;
client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
if (client)
{
hash_remove_binary(sock_hash, csid, MAX_CSID_LEN);
hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
}
/* Put it back as we found it */
@@ -142,7 +119,7 @@ int alloc_client(int fd, char *csid, struct local_client **new_client)
{
struct local_client *client;
DEBUGLOG("alloc_client %d csid = [%d.%d.%d.%d]\n", fd,csid[0],csid[1],csid[2],csid[3]);
DEBUGLOG("alloc_client %d csid = %s\n", fd, print_csid(csid));
/* Create a local_client and return it */
client = malloc(sizeof(struct local_client));
@@ -160,7 +137,7 @@ int alloc_client(int fd, char *csid, struct local_client **new_client)
*new_client = client;
/* Add to our list of node sockets */
if (hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN))
if (hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN))
{
DEBUGLOG("alloc_client mangling CSID for second connection\n");
/* This is a duplicate connection but we can't close it because
@@ -173,7 +150,7 @@ int alloc_client(int fd, char *csid, struct local_client **new_client)
/* If it still exists then kill the connection as we should only
ever have one incoming connection from each node */
if (hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN))
if (hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN))
{
DEBUGLOG("Multiple incoming connections from node\n");
syslog(LOG_ERR, " Bogus incoming connection from %d.%d.%d.%d\n", csid[0],csid[1],csid[2],csid[3]);
@@ -183,26 +160,26 @@ int alloc_client(int fd, char *csid, struct local_client **new_client)
return -1;
}
}
hash_insert_binary(sock_hash, csid, MAX_CSID_LEN, client);
hash_insert_binary(sock_hash, csid, GULM_MAX_CSID_LEN, client);
return 0;
}
int get_main_cluster_fd()
int get_main_gulm_cluster_fd()
{
return listen_fd;
}
/* Read on main comms (listen) socket, accept it */
int cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, char *csid,
struct local_client **new_client)
{
int newfd;
struct sockaddr_in addr;
struct sockaddr_in6 addr;
socklen_t addrlen = sizeof(addr);
int status;
char name[MAX_CLUSTER_MEMBER_NAME_LEN];
char name[GULM_MAX_CLUSTER_MEMBER_NAME_LEN];
DEBUGLOG("cluster_fd_callback\n");
*new_client = NULL;
@@ -218,22 +195,20 @@ int cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
/* Check that the client is a member of the cluster
and reject if not.
// FIXME: IPv4 specific
*/
if (name_from_csid((char *)&addr.sin_addr.s_addr, name) < 0)
if (gulm_name_from_csid((char *)&addr.sin6_addr, name) < 0)
{
char *ip = (char *)&addr.sin_addr.s_addr;
syslog(LOG_ERR, "Got connect from non-cluster node %d.%d.%d.%d\n",
ip[0], ip[1], ip[2], ip[3]);
DEBUGLOG("Got connect from non-cluster node %d.%d.%d.%d\n",
ip[0], ip[1], ip[2], ip[3]);
syslog(LOG_ERR, "Got connect from non-cluster node %s\n",
print_csid((char *)&addr.sin6_addr));
DEBUGLOG("Got connect from non-cluster node %s\n",
print_csid((char *)&addr.sin6_addr));
close(newfd);
errno = EAGAIN;
return -1;
}
status = alloc_client(newfd, (char *)&addr.sin_addr.s_addr, new_client);
status = alloc_client(newfd, (char *)&addr.sin6_addr, new_client);
if (status)
{
DEBUGLOG("cluster_fd_callback, alloc_client failed, status = %d\n", status);
@@ -250,7 +225,7 @@ int cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
static int read_from_tcpsock(struct local_client *client, char *buf, int len, char *csid,
struct local_client **new_client)
{
struct sockaddr_in addr;
struct sockaddr_in6 addr;
socklen_t slen = sizeof(addr);
int status;
@@ -259,7 +234,7 @@ static int read_from_tcpsock(struct local_client *client, char *buf, int len, ch
/* Get "csid" */
getpeername(client->fd, (struct sockaddr *)&addr, &slen);
memcpy(csid, &addr.sin_addr.s_addr, MAX_CSID_LEN);
memcpy(csid, &addr.sin6_addr, GULM_MAX_CSID_LEN);
status = read(client->fd, buf, len);
@@ -270,30 +245,34 @@ static int read_from_tcpsock(struct local_client *client, char *buf, int len, ch
if (status == 0 ||
(status < 0 && errno != EAGAIN && errno != EINTR))
{
char remcsid[MAX_CSID_LEN];
char remcsid[GULM_MAX_CSID_LEN];
memcpy(remcsid, csid, MAX_CSID_LEN);
memcpy(remcsid, csid, GULM_MAX_CSID_LEN);
close(client->fd);
/* If the csid was mangled, then make sure we remove the right entry */
if (client->bits.net.flags)
remcsid[0] ^= 0x80;
hash_remove_binary(sock_hash, remcsid, MAX_CSID_LEN);
hash_remove_binary(sock_hash, remcsid, GULM_MAX_CSID_LEN);
/* Tell cluster manager layer */
add_down_node(remcsid);
}
else {
/* Send it back to clvmd */
process_message(client, buf, len, csid);
}
return status;
}
static int connect_csid(char *csid, struct local_client **newclient)
{
int fd;
struct sockaddr_in addr;
struct sockaddr_in6 addr;
int status;
DEBUGLOG("Connecting socket\n");
fd = socket(PF_INET, SOCK_STREAM, 0);
fd = socket(PF_INET6, SOCK_STREAM, 0);
if (fd < 0)
{
@@ -301,12 +280,12 @@ static int connect_csid(char *csid, struct local_client **newclient)
return -1;
}
addr.sin_family = AF_INET;
memcpy(&addr.sin_addr.s_addr, csid, MAX_CSID_LEN);
addr.sin_port = htons(tcp_port);
addr.sin6_family = AF_INET6;
memcpy(&addr.sin6_addr, csid, GULM_MAX_CSID_LEN);
addr.sin6_port = htons(tcp_port);
DEBUGLOG("Connecting socket %d\n", fd);
if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0)
if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)) < 0)
{
syslog(LOG_ERR, "Unable to connect to remote node: %m");
DEBUGLOG("Unable to connect to remote node: %s\n", strerror(errno));
@@ -321,7 +300,7 @@ static int connect_csid(char *csid, struct local_client **newclient)
add_client(*newclient);
/* If we can connect to it, it must be running a clvmd */
add_up_node(csid);
gulm_add_up_node(csid);
return status;
}
@@ -330,18 +309,18 @@ static int tcp_send_message(void *buf, int msglen, unsigned char *csid, const ch
{
int status;
struct local_client *client;
char ourcsid[MAX_CSID_LEN];
char ourcsid[GULM_MAX_CSID_LEN];
assert(csid);
DEBUGLOG("tcp_send_message, csid = [%d.%d.%d.%d], msglen = %d\n", csid[0],csid[1],csid[2],csid[3], msglen);
DEBUGLOG("tcp_send_message, csid = %s, msglen = %d\n", print_csid(csid), msglen);
/* Don't connect to ourself */
get_our_csid(ourcsid);
if (memcmp(csid, ourcsid, MAX_CSID_LEN) == 0)
get_our_gulm_csid(ourcsid);
if (memcmp(csid, ourcsid, GULM_MAX_CSID_LEN) == 0)
return msglen;
client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
if (!client)
{
status = connect_csid(csid, &client);
@@ -354,7 +333,7 @@ static int tcp_send_message(void *buf, int msglen, unsigned char *csid, const ch
}
int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
int gulm_cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
{
int status=0;
@@ -364,7 +343,7 @@ int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
if (!csid)
{
void *context = NULL;
char loop_csid[MAX_CSID_LEN];
char loop_csid[GULM_MAX_CSID_LEN];
/* Loop round all gulm-known nodes */
while (get_next_node_csid(&context, loop_csid))
@@ -383,62 +362,24 @@ int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
return status;
}
static int get_tcp_port(int default_port)
{
int ccs_handle;
int port = default_port;
char *portstr;
ccs_handle = ccs_connect();
if (ccs_handle)
{
return port;
}
if (!ccs_get(ccs_handle, "//clvm/@port", &portstr))
{
port = atoi(portstr);
free(portstr);
if (port <= 0 && port >= 65536)
port = default_port;
}
ccs_disconnect(ccs_handle);
DEBUGLOG("Using port %d for communications\n", port);
return port;
}
/* To get our own IP address we get the locally bound address of the
socket that's talking to GULM in the assumption(eek) that it will
be on the "right" network in a multi-homed system */
static int get_our_ip_address(char *addr, int *family)
{
/* Use a sockaddr_in6 to make sure it's big enough */
struct sockaddr_in6 saddr;
int socklen = sizeof(saddr);
struct utsname info;
uname(&info);
get_ip_address(info.nodename, addr);
if (!getsockname(gulm_fd(), (struct sockaddr *)&saddr, &socklen))
{
if (saddr.sin6_family == AF_INET6)
{
memcpy(addr, &saddr.sin6_addr, sizeof(saddr.sin6_addr));
}
else
{
struct sockaddr_in *sin4 = (struct sockaddr_in *)&saddr;
memcpy(addr, &sin4->sin_addr, sizeof(sin4->sin_addr));
}
return 0;
}
return -1;
}
/* Public version of above for those that don't care what protocol
we're using */
void get_our_csid(char *csid)
void get_our_gulm_csid(char *csid)
{
static char our_csid[MAX_CSID_LEN];
static char our_csid[GULM_MAX_CSID_LEN];
static int got_csid = 0;
if (!got_csid)
@@ -451,7 +392,15 @@ void get_our_csid(char *csid)
got_csid = 1;
}
}
memcpy(csid, our_csid, MAX_CSID_LEN);
memcpy(csid, our_csid, GULM_MAX_CSID_LEN);
}
static void map_v4_to_v6(struct in_addr *ip4, struct in6_addr *ip6)
{
ip6->s6_addr32[0] = 0;
ip6->s6_addr32[1] = 0;
ip6->s6_addr32[2] = htonl(0xffff);
ip6->s6_addr32[3] = ip4->s_addr;
}
/* Get someone else's IP address from DNS */
@@ -459,7 +408,7 @@ int get_ip_address(char *node, char *addr)
{
struct hostent *he;
memset(addr, 0, MAX_CSID_LEN);
memset(addr, 0, GULM_MAX_CSID_LEN);
// TODO: what do we do about multi-homed hosts ???
// CCSs ip_interfaces solved this but some bugger removed it.
@@ -467,14 +416,29 @@ int get_ip_address(char *node, char *addr)
/* Try IPv6 first. The man page for gethostbyname implies that
it will lookup ip6 & ip4 names, but it seems not to */
he = gethostbyname2(node, AF_INET6);
if (!he)
if (he)
{
memcpy(addr, he->h_addr_list[0],
he->h_length);
}
else
{
he = gethostbyname2(node, AF_INET);
if (!he)
return -1;
/* For IPv4 address just use the lower 4 bytes */
memcpy(&addr, he->h_addr_list[0],
he->h_length);
if (!he)
return -1;
map_v4_to_v6((struct in_addr *)he->h_addr_list[0], (struct in6_addr *)addr);
}
return 0;
}
char *print_csid(char *csid)
{
static char buf[128];
int *icsid = (int *)csid;
sprintf(buf, "[%x.%x.%x.%x]",
icsid[0],icsid[1],icsid[2],icsid[3]);
return buf;
}

View File

@@ -1,7 +1,12 @@
#include <netinet/in.h>
#define MAX_CLUSTER_MESSAGE 1600
#define MAX_CSID_LEN sizeof(struct in6_addr)
#define MAX_CLUSTER_MEMBER_NAME_LEN 128
#define GULM_MAX_CLUSTER_MESSAGE 1600
#define GULM_MAX_CSID_LEN sizeof(struct in6_addr)
#define GULM_MAX_CLUSTER_MEMBER_NAME_LEN 128
extern int init_comms(void);
extern int init_comms(unsigned short);
extern char *print_csid(char *);
int get_main_gulm_cluster_fd(void);
int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, char *csid, struct local_client **new_client);
int gulm_cluster_send_message(void *buf, int msglen, char *csid, const char *errtext);
void get_our_gulm_csid(char *csid);

View File

@@ -27,6 +27,12 @@ devices {
# the device will be accepted or rejected (ignored). Devices that
# don't match any patterns are accepted.
# Be careful if there there are symbolic links or multiple filesystem
# entries for the same device as each name is checked separately against
# the list of patterns. The effect is that if any name matches any 'a'
# pattern, the device is accepted; otherwise if any name matches any 'r'
# pattern it is rejected; otherwise it is accepted.
# Remember to run vgscan after you change this parameter to ensure
# that the cache file gets regenerated (see below).

165
doc/tagging.txt Normal file
View File

@@ -0,0 +1,165 @@
Tagging aims
============
1) Ability to attach an unordered list of tags to LVM metadata objects.
2) Ability to add or remove tags easily.
3) Ability to select LVM objects for processing according to presence/absence
of specific tags.
4) Ability to control through the config file which VGs/LVs are activated
on different machines using names or tags.
5) Ability to overlay settings from different config files e.g. override
some settings in a global config file locally.
Clarifications
==============
1) Tag character set: A-Za-z0-9_+.-
Can't start with hyphen & max length is 128 (NAME_LEN).
2) LVM object types that can be tagged:
VG, LV, LV segment
PV - tags are stored in VG metadata so disappear when PV becomes orphaned
Snapshots can't be tagged, but their origin may be.
3) A tag can be used in place of any command line LVM object reference that
accepts (a) a list of objects; or (b) a single object as long as the
tag expands to a single object. This is not supported everywhere yet.
Duplicate arguments in a list after argument expansion may get removed
retaining the first copy of each argument.
4) Wherever there may be ambiguity of argument type, a tag must be prefixed
by '@'; elsewhere an '@' prefix is optional.
5) LVM1 objects cannot be tagged, as the disk format doesn't support it.
6) Tags can be added or removed with --addtag or --deltag.
Config file Extensions
======================
To define host tags in config file:
tags {
# Set a tag with the hostname
hosttags = 1
tag1 { }
tag2 {
# If no exact match, tag is not set.
host_list = [ "hostname", "dbase" ]
}
}
Activation config file example
==============================
activation {
volume_list = [ "vg1/lvol0", "@database" ]
}
Matches against vgname, vgname/lvname or @tag set in *metadata*.
@* matches exactly against *any* tag set on the host.
The VG or LV only gets activated if a metadata tag matches.
The default if there is no match is not to activate.
If volume_list is not present and any tags are defined on the host
then it only activates if a host tag matches a metadata tag.
If volume_list is not present and no tags are defined on the host
then it does activate.
Multiple config files
=====================
(a) lvm.conf
(b) lvm_<host_tag>.conf
At startup, load lvm.conf.
Process tag settings.
If any host tags were defined, load lvm_tag.conf for each tag, if present.
When searching for a specific config file entry, search order is (b)
then (a), stopping at the first match.
Within (b) use reverse order tags got set, so file for last tag set is
searched first.
New tags set in (b) *do* trigger additional config file loads.
Usage Examples
==============
1) Simple activation control via metadata with static config files
lvm.conf: (Identical on every machine - global settings)
tags {
hostname_tags = 1
}
From any machine in the cluster, add db1 to the list of machines that
activate vg1/lvol2:
lvchange --tag @db1 vg1/lvol2
(followed by lvchange -ay to actually activate it)
2) Multiple hosts.
Activate vg1 only on the database hosts, db1 and db2.
Activate vg2 only on the fileserver host fs1.
Activate nothing initially on the fileserver backup host fsb1, but be
prepared for it to take over from fs1.
Option (i) - centralised admin, static configuration replicated between hosts
# Add @database tag to vg1's metadata
vgchange --tag @database vg1
# Add @fileserver tag to vg2's metadata
vgchange --tag @fileserver vg2
lvm.conf: (Identical on every machine)
tags {
database {
host_list = [ "db1", "db2" ]
}
fileserver {
host_list = [ "fs1" ]
}
fileserverbackup {
host_list = [ "fsb1" ]
}
}
activation {
# Only activate if host has a tag that matches a metadata tag
volume_list = [ "@*" ]
}
In the event of the fileserver host going down, vg2 can be brought up
on fsb1 by running *on any node* 'vgchange --tag @fileserverbackup vg2'
followed by 'vgchange -ay vg2'
Option (ii) - localised admin & configuation
(i.e. each host holds *locally* which classes of volumes to activate)
# Add @database tag to vg1's metadata
vgchange --tag @database vg1
# Add @fileserver tag to vg2's metadata
vgchange --tag @fileserver vg2
lvm.conf: (Identical on every machine - global settings)
tags {
hosttags = 1
}
lvm_db1.conf: (only needs to be on db1 - could be symlink to lvm_db.conf)
activation {
volume_list = [ "@database" ]
}
lvm_db2.conf: (only needs to be on db2 - could be symlink to lvm_db.conf)
activation {
volume_list = [ "@database" ]
}
lvm_fs1.conf: (only needs to be on fs1 - could be symlink to lvm_fs.conf)
activation {
volume_list = [ "@fileserver" ]
}
If fileserver goes down, to bring a spare machine fsb1 in as fileserver,
create lvm_fsb1.conf on fsb1 (or symlink to lvm_fs.conf):
activation {
volume_list = [ "@fileserver" ]
}
and run 'vgchange -ay vg2' or 'vgchange -ay @fileserver'

View File

@@ -47,3 +47,4 @@
../lib/report/report.h
../lib/uuid/uuid.h
../po/pogen.h
../tools/version.h

View File

@@ -43,6 +43,7 @@ SOURCES =\
datastruct/str_list.c \
device/dev-cache.c \
device/dev-io.c \
device/dev-md.c \
device/device.c \
display/display.c \
error/errseg.c \
@@ -75,6 +76,7 @@ SOURCES =\
misc/crc.c \
misc/lvm-file.c \
misc/lvm-string.c \
mm/dbg_malloc.c \
mm/memlock.c \
mm/pool.c \
regex/matcher.c \
@@ -120,10 +122,6 @@ ifeq ("@MIRRORS@", "internal")
SOURCES += mirror/mirrored.c
endif
ifeq ("@DEBUG@", "yes")
SOURCES += mm/dbg_malloc.c
endif
ifeq ("@DEVMAPPER@", "yes")
SOURCES +=\
activate/dev_manager.c \

View File

@@ -78,12 +78,13 @@ int target_present(const char *target_name)
{
return 0;
}
int lv_info(const struct logical_volume *lv, struct lvinfo *info)
int lv_info(const struct logical_volume *lv, struct lvinfo *info,
int with_open_count)
{
return 0;
}
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
struct lvinfo *info)
struct lvinfo *info, int with_open_count)
{
return 0;
}
@@ -333,7 +334,7 @@ int target_present(const char *target_name)
* Returns 1 if info structure populated, else 0 on failure.
*/
static int _lv_info(const struct logical_volume *lv, int mknodes,
struct lvinfo *info)
struct lvinfo *info, int with_open_count)
{
int r;
struct dev_manager *dm;
@@ -347,7 +348,7 @@ static int _lv_info(const struct logical_volume *lv, int mknodes,
return 0;
}
if (!(r = dev_manager_info(dm, lv, mknodes, &dminfo)))
if (!(r = dev_manager_info(dm, lv, mknodes, with_open_count, &dminfo)))
stack;
info->exists = dminfo.exists;
@@ -361,20 +362,21 @@ static int _lv_info(const struct logical_volume *lv, int mknodes,
return r;
}
int lv_info(const struct logical_volume *lv, struct lvinfo *info)
int lv_info(const struct logical_volume *lv, struct lvinfo *info,
int with_open_count)
{
return _lv_info(lv, 0, info);
return _lv_info(lv, 0, info, with_open_count);
}
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
struct lvinfo *info)
struct lvinfo *info, int with_open_count)
{
struct logical_volume *lv;
if (!(lv = lv_from_lvid(cmd, lvid_s)))
return 0;
return _lv_info(lv, 0, info);
return _lv_info(lv, 0, info, with_open_count);
}
/*
@@ -412,7 +414,7 @@ int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
if (!activation())
return 0;
if (!lv_info(lv, &info)) {
if (!lv_info(lv, &info, 0)) {
stack;
return 0;
}
@@ -437,7 +439,7 @@ static int _lv_active(struct logical_volume *lv)
{
struct lvinfo info;
if (!lv_info(lv, &info)) {
if (!lv_info(lv, &info, 0)) {
stack;
return -1;
}
@@ -449,7 +451,7 @@ static int _lv_open_count(struct logical_volume *lv)
{
struct lvinfo info;
if (!lv_info(lv, &info)) {
if (!lv_info(lv, &info, 1)) {
stack;
return -1;
}
@@ -566,7 +568,7 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
return 1;
}
if (!lv_info(lv, &info)) {
if (!lv_info(lv, &info, 0)) {
stack;
return 0;
}
@@ -612,7 +614,7 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
return 1;
}
if (!lv_info(lv, &info)) {
if (!lv_info(lv, &info, 0)) {
stack;
return 0;
}
@@ -657,7 +659,7 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
return 1;
}
if (!lv_info(lv, &info)) {
if (!lv_info(lv, &info, 1)) {
stack;
return 0;
}
@@ -726,7 +728,7 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, int filter)
return 1;
}
if (!lv_info(lv, &info)) {
if (!lv_info(lv, &info, 0)) {
stack;
return 0;
}
@@ -765,7 +767,7 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
return r;
}
if (!_lv_info(lv, 1, &info)) {
if (!_lv_info(lv, 1, &info, 0)) {
stack;
return 0;
}

View File

@@ -55,9 +55,10 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv);
/*
* Returns 1 if info structure has been populated, else 0.
*/
int lv_info(const struct logical_volume *lv, struct lvinfo *info);
int lv_info(const struct logical_volume *lv, struct lvinfo *info,
int with_open_count);
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
struct lvinfo *info);
struct lvinfo *info, int with_open_count);
/*
* Returns 1 if activate_lv has been set: 1 = activate; 0 = don't.

View File

@@ -211,7 +211,8 @@ static struct dm_task *_setup_task(const char *name, const char *uuid,
}
static int _info_run(const char *name, const char *uuid, struct dm_info *info,
int mknodes, struct pool *mem, char **uuid_out)
int mknodes, int with_open_count, struct pool *mem,
char **uuid_out)
{
int r = 0;
struct dm_task *dmt;
@@ -225,6 +226,10 @@ static int _info_run(const char *name, const char *uuid, struct dm_info *info,
return 0;
}
if (!with_open_count)
if (!dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
if (!dm_task_run(dmt)) {
stack;
goto out;
@@ -250,14 +255,17 @@ static int _info_run(const char *name, const char *uuid, struct dm_info *info,
}
static int _info(const char *name, const char *uuid, int mknodes,
struct dm_info *info, struct pool *mem, char **uuid_out)
int with_open_count, struct dm_info *info,
struct pool *mem, char **uuid_out)
{
if (!mknodes && uuid && *uuid &&
_info_run(NULL, uuid, info, 0, mem, uuid_out) && info->exists)
_info_run(NULL, uuid, info, 0, with_open_count, mem, uuid_out) &&
info->exists)
return 1;
if (name)
return _info_run(name, NULL, info, mknodes, mem, uuid_out);
return _info_run(name, NULL, info, mknodes, with_open_count,
mem, uuid_out);
return 0;
}
@@ -279,6 +287,9 @@ static int _status_run(const char *name, const char *uuid,
return 0;
}
if (!dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
if (!dm_task_run(dmt)) {
stack;
goto out;
@@ -357,6 +368,9 @@ static int _percent_run(struct dev_manager *dm, const char *name,
return 0;
}
if (!dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
if (!dm_task_run(dmt)) {
stack;
goto out;
@@ -460,6 +474,9 @@ static int _rename(struct dev_manager *dm, struct dev_layer *dl, char *newname)
goto out;
}
if (!dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
if (!(r = dm_task_run(dmt))) {
log_error("Couldn't rename device '%s'.", dl->name);
goto out;
@@ -488,6 +505,9 @@ static int _suspend_or_resume(const char *name, action_t suspend)
return 0;
}
if (!dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
if (!(r = dm_task_run(dmt)))
log_error("Couldn't %s device '%s'", sus ? "suspend" : "resume",
name);
@@ -579,6 +599,9 @@ static int _load(struct dev_manager *dm, struct dev_layer *dl, int task)
log_very_verbose("Activating %s read-only", dl->name);
}
if (!dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
if (!(r = dm_task_run(dmt))) {
log_error("Couldn't load device '%s'.", dl->name);
if ((dl->lv->minor >= 0 || dl->lv->major >= 0) &&
@@ -635,6 +658,9 @@ static int _remove(struct dev_layer *dl)
return 0;
}
if (!dm_task_no_open_count(dmt))
log_error("Failed to disable open_count");
/* Suppress error message if it's still in use - we'll log it later */
log_suppress(1);
@@ -852,6 +878,7 @@ static int _populate_snapshot(struct dev_manager *dm,
struct snapshot *s;
struct dev_layer *dlo, *dlc;
char devbufo[10], devbufc[10];
uint64_t size;
if (!(s = find_cow(dl->lv))) {
log_error("Couldn't find snapshot for '%s'.", dl->lv->name);
@@ -899,10 +926,10 @@ static int _populate_snapshot(struct dev_manager *dm,
return 0;
}
log_debug("Adding target: 0 %" PRIu64 " snapshot %s",
s->origin->size, params);
if (!dm_task_add_target
(dmt, UINT64_C(0), s->origin->size, "snapshot", params)) {
size = (uint64_t) s->le_count * s->origin->vg->extent_size;
log_debug("Adding target: 0 %" PRIu64 " snapshot %s", size, params);
if (!dm_task_add_target(dmt, UINT64_C(0), size, "snapshot", params)) {
stack;
return 0;
}
@@ -919,7 +946,7 @@ struct dev_manager *dev_manager_create(struct cmd_context *cmd,
struct pool *mem;
struct dev_manager *dm;
if (!(mem = pool_create(16 * 1024))) {
if (!(mem = pool_create("dev_manager", 16 * 1024))) {
stack;
return NULL;
}
@@ -970,7 +997,7 @@ void dev_manager_destroy(struct dev_manager *dm)
}
int dev_manager_info(struct dev_manager *dm, const struct logical_volume *lv,
int mknodes, struct dm_info *info)
int mknodes, int with_open_count, struct dm_info *info)
{
char *name;
@@ -986,7 +1013,8 @@ int dev_manager_info(struct dev_manager *dm, const struct logical_volume *lv,
* Try and get some info on this device.
*/
log_debug("Getting device info for %s", name);
if (!_info(name, lv->lvid.s, mknodes, info, NULL, NULL)) {
if (!_info(name, lv->lvid.s, mknodes, with_open_count, info, NULL,
NULL)) {
stack;
return 0;
}
@@ -1065,7 +1093,7 @@ static struct dev_layer *_create_dev(struct dev_manager *dm, char *name,
dl->name = name;
log_debug("Getting device info for %s", dl->name);
if (!_info(dl->name, dlid, 0, &dl->info, dm->mem, &uuid)) {
if (!_info(dl->name, dlid, 0, 0, &dl->info, dm->mem, &uuid)) {
stack;
return NULL;
}

View File

@@ -36,7 +36,7 @@ void dev_manager_exit(void);
* unsuspended until the snapshot is also created.)
*/
int dev_manager_info(struct dev_manager *dm, const struct logical_volume *lv,
int mknodes, struct dm_info *info);
int mknodes, int with_open_count, struct dm_info *info);
int dev_manager_snapshot_percent(struct dev_manager *dm,
struct logical_volume *lv, float *percent);
int dev_manager_mirror_percent(struct dev_manager *dm,

View File

@@ -65,10 +65,10 @@ static int _rm_dir(const char *dev_dir, const char *vg_name)
return 0;
}
log_very_verbose("Removing directory %s", vg_path);
if (is_empty_dir(vg_path))
if (is_empty_dir(vg_path)) {
log_very_verbose("Removing directory %s", vg_path);
rmdir(vg_path);
}
return 1;
}
@@ -202,9 +202,9 @@ static int _rm_link(const char *dev_dir, const char *vg_name,
}
if (lstat(lv_path, &buf) || !S_ISLNK(buf.st_mode)) {
if (errno != ENOENT)
log_error("%s not symbolic link - not removing",
lv_path);
if (errno == ENOENT)
return 1;
log_error("%s not symbolic link - not removing", lv_path);
return 0;
}

View File

@@ -519,8 +519,8 @@ static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
/* regex filter. Optional. */
if (!(cn = find_config_node(cmd->cft->root, "devices/filter")))
log_debug("devices/filter not found in config file: no regex "
"filter installed");
log_very_verbose("devices/filter not found in config file: "
"no regex filter installed");
else if (!(filters[nr_filt++] = regex_filter_create(cn->v))) {
log_error("Failed to create regex device filter");
@@ -537,6 +537,7 @@ static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
/* md component filter. Optional, non-critical. */
if (find_config_bool(cmd->cft->root, "devices/md_component_detection",
DEFAULT_MD_COMPONENT_DETECTION)) {
init_md_filtering(1);
if ((filters[nr_filt] = md_filter_create()))
nr_filt++;
}
@@ -827,7 +828,7 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
if (*cmd->sys_dir && !create_dir(cmd->sys_dir))
goto error;
if (!(cmd->libmem = pool_create(4 * 1024))) {
if (!(cmd->libmem = pool_create("library", 4 * 1024))) {
log_error("Library memory pool creation failed");
return 0;
}
@@ -858,7 +859,7 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
if (!_init_filters(cmd))
goto error;
if (!(cmd->mem = pool_create(4 * 1024))) {
if (!(cmd->mem = pool_create("command", 4 * 1024))) {
log_error("Command memory pool creation failed");
return 0;
}

View File

@@ -99,7 +99,7 @@ static int _tok_match(const char *str, const char *b, const char *e)
struct config_tree *create_config_tree(const char *filename)
{
struct cs *c;
struct pool *mem = pool_create(10 * 1024);
struct pool *mem = pool_create("config", 10 * 1024);
if (!mem) {
stack;

View File

@@ -82,6 +82,7 @@ struct device *dev_create_file(const char *filename, struct device *dev,
dev->dev = 0;
dev->fd = -1;
dev->open_count = 0;
dev->block_size = -1;
memset(dev->pvid, 0, sizeof(dev->pvid));
list_init(&dev->open_list);
@@ -101,6 +102,7 @@ static struct device *_dev_create(dev_t d)
dev->dev = d;
dev->fd = -1;
dev->open_count = 0;
dev->block_size = -1;
dev->end = UINT64_C(0);
memset(dev->pvid, 0, sizeof(dev->pvid));
list_init(&dev->open_list);
@@ -387,7 +389,7 @@ int dev_cache_init(void)
{
_cache.names = NULL;
if (!(_cache.mem = pool_create(10 * 1024))) {
if (!(_cache.mem = pool_create("dev_cache", 10 * 1024))) {
stack;
return 0;
}

View File

@@ -81,7 +81,9 @@ static int _io(struct device_area *where, void *buffer, int should_write)
}
if (lseek(fd, (off_t) where->start, SEEK_SET) < 0) {
log_sys_error("lseek", dev_name(where->dev));
log_error("%s: lseek %" PRIu64 " failed: %s",
dev_name(where->dev), (uint64_t) where->start,
strerror(errno));
return 0;
}
@@ -92,6 +94,14 @@ static int _io(struct device_area *where, void *buffer, int should_write)
read(fd, buffer, (size_t) where->size - total);
while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
if (n < 0)
log_error("%s: %s failed after %" PRIu64 " of %" PRIu64
" at %" PRIu64 ": %s", dev_name(where->dev),
should_write ? "write" : "read",
(uint64_t) total,
(uint64_t) where->size,
(uint64_t) where->start, strerror(errno));
if (n <= 0)
break;
@@ -114,14 +124,18 @@ static int _io(struct device_area *where, void *buffer, int should_write)
*/
static int _get_block_size(struct device *dev, unsigned int *size)
{
int s;
const char *name = dev_name(dev);
if (ioctl(dev_fd(dev), BLKBSZGET, &s) < 0) {
log_sys_error("ioctl BLKBSZGET", dev_name(dev));
return 0;
if ((dev->block_size == -1)) {
if (ioctl(dev_fd(dev), BLKBSZGET, &dev->block_size) < 0) {
log_sys_error("ioctl BLKBSZGET", name);
return 0;
}
log_debug("%s: block size is %u bytes", name, dev->block_size);
}
*size = (unsigned int) s;
*size = (unsigned int) dev->block_size;
return 1;
}
@@ -217,7 +231,6 @@ int dev_get_size(const struct device *dev, uint64_t *size)
int fd;
const char *name = dev_name(dev);
log_very_verbose("Getting size of %s", name);
if ((fd = open(name, O_RDONLY)) < 0) {
log_sys_error("open", name);
return 0;
@@ -225,22 +238,27 @@ int dev_get_size(const struct device *dev, uint64_t *size)
if (ioctl(fd, BLKGETSIZE64, size) < 0) {
log_sys_error("ioctl BLKGETSIZE64", name);
close(fd);
if (close(fd))
log_sys_error("close", name);
return 0;
}
*size >>= BLKSIZE_SHIFT; /* Convert to sectors */
close(fd);
if (close(fd))
log_sys_error("close", name);
log_very_verbose("%s: size is %" PRIu64 " sectors", name, *size);
return 1;
}
/* FIXME Unused
int dev_get_sectsize(struct device *dev, uint32_t *size)
{
int fd;
int s;
const char *name = dev_name(dev);
log_very_verbose("Getting size of %s", name);
if ((fd = open(name, O_RDONLY)) < 0) {
log_sys_error("open", name);
return 0;
@@ -254,8 +272,12 @@ int dev_get_sectsize(struct device *dev, uint32_t *size)
close(fd);
*size = (uint32_t) s;
log_very_verbose("%s: sector size is %" PRIu32 " bytes", name, *size);
return 1;
}
*/
void dev_flush(struct device *dev)
{
@@ -274,8 +296,20 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
const char *name;
if (dev->fd >= 0) {
dev->open_count++;
return 1;
if ((dev->flags & DEV_OPENED_RW) ||
((flags & O_ACCMODE) != O_RDWR)) {
dev->open_count++;
return 1;
}
if (dev->open_count) {
/* FIXME Ensure we never get here */
log_debug("WARNING: %s already opened read-only",
dev_name(dev));
dev->open_count++;
}
dev_close_immediate(dev);
}
if (memlock())
@@ -311,14 +345,18 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
return 0;
}
dev->open_count = 1;
dev->open_count++;
dev->flags &= ~DEV_ACCESSED_W;
if ((flags & O_ACCMODE) == O_RDWR)
dev->flags |= DEV_OPENED_RW;
else
dev->flags &= ~DEV_OPENED_RW;
if (!(dev->flags & DEV_REGULAR) &&
((fstat(dev->fd, &buf) < 0) || (buf.st_rdev != dev->dev))) {
log_error("%s: fstat failed: Has device name changed?", name);
dev_close(dev);
dev->fd = -1;
dev_close_immediate(dev);
dev->open_count = 0;
return 0;
}
@@ -327,12 +365,13 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
dev_flush(dev);
#endif
if ((flags & O_CREAT) && !(flags & O_TRUNC)) {
if ((flags & O_CREAT) && !(flags & O_TRUNC))
dev->end = lseek(dev->fd, (off_t) 0, SEEK_END);
}
list_add(&_open_devices, &dev->open_list);
log_debug("Opened %s", dev_name(dev));
log_debug("Opened %s %s", dev_name(dev),
dev->flags & DEV_OPENED_RW ? "RW" : "RO");
return 1;
}
@@ -360,6 +399,7 @@ static void _close(struct device *dev)
if (close(dev->fd))
log_sys_error("close", dev_name(dev));
dev->fd = -1;
dev->block_size = -1;
list_del(&dev->open_list);
log_debug("Closed %s", dev_name(dev));
@@ -385,8 +425,11 @@ static int _dev_close(struct device *dev, int immediate)
dev_flush(dev);
#endif
if (dev->open_count > 0)
dev->open_count--;
/* FIXME lookup device in cache to get vgname and see if it's locked? */
if (--dev->open_count < 1 && (immediate || !vgs_locked()))
if (immediate || (dev->open_count < 1 && !vgs_locked()))
_close(dev);
return 1;
@@ -418,8 +461,10 @@ int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer)
{
struct device_area where;
if (!dev->open_count)
if (!dev->open_count) {
stack;
return 0;
}
where.dev = dev;
where.start = offset;
@@ -437,8 +482,10 @@ int dev_append(struct device *dev, size_t len, void *buffer)
{
int r;
if (!dev->open_count)
if (!dev->open_count) {
stack;
return 0;
}
r = dev_write(dev, dev->end, len, buffer);
dev->end += (uint64_t) len;
@@ -453,8 +500,10 @@ int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer)
{
struct device_area where;
if (!dev->open_count)
if (!dev->open_count) {
stack;
return 0;
}
where.dev = dev;
where.start = offset;
@@ -501,6 +550,5 @@ int dev_zero(struct device *dev, uint64_t offset, size_t len)
if (!dev_close(dev))
stack;
/* FIXME: Always display error */
return (len == 0);
}

69
lib/device/dev-md.c Normal file
View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2004 Luca Berra
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "metadata.h"
#include "xlate.h"
/* Lifted from <linux/raid/md_p.h> because of difficulty including it */
#define MD_SB_MAGIC 0xa92b4efc
#define MD_RESERVED_BYTES (64 * 1024)
#define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512)
#define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) \
- MD_RESERVED_SECTORS)
/*
* Returns -1 on error
*/
int dev_is_md(struct device *dev, uint64_t *sb)
{
int ret = 0;
#ifdef linux
uint64_t size, sb_offset;
uint32_t md_magic;
if (!dev_get_size(dev, &size)) {
stack;
return -1;
}
if (size < MD_RESERVED_SECTORS * 2)
return 0;
if (!dev_open(dev)) {
stack;
return -1;
}
sb_offset = MD_NEW_SIZE_SECTORS(size) << SECTOR_SHIFT;
/* Check if it is an md component device. */
if (dev_read(dev, sb_offset, sizeof(uint32_t), &md_magic) &&
(md_magic == xlate32(MD_SB_MAGIC))) {
if (sb)
*sb = sb_offset;
ret = 1;
}
if (!dev_close(dev))
stack;
#endif
return ret;
}

View File

@@ -13,6 +13,93 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "lvm-types.h"
#include "device.h"
#include "metadata.h"
#include "filter.h"
#include "xlate.h"
/* See linux/genhd.h and fs/partitions/msdos */
#define PART_MAGIC 0xAA55
#define PART_MAGIC_OFFSET UINT64_C(0x1FE)
#define PART_OFFSET UINT64_C(0x1BE)
struct partition {
uint8_t boot_ind;
uint8_t head;
uint8_t sector;
uint8_t cyl;
uint8_t sys_ind; /* partition type */
uint8_t end_head;
uint8_t end_sector;
uint8_t end_cyl;
uint32_t start_sect;
uint32_t nr_sects;
} __attribute__((packed));
static int _is_partitionable(struct device *dev)
{
int parts = max_partitions(MAJOR(dev->dev));
if ((parts <= 1) || (MINOR(dev->dev) % parts))
return 0;
return 1;
}
static int _has_partition_table(struct device *dev)
{
int ret = 0;
unsigned p;
uint8_t buf[SECTOR_SIZE];
uint16_t *part_magic;
struct partition *part;
if (!dev_open(dev)) {
stack;
return -1;
}
if (!dev_read(dev, 0, sizeof(buf), &buf)) {
stack;
goto out;
}
/* FIXME Check for other types of partition table too */
/* Check for msdos partition table */
part_magic = (uint16_t *)(buf + PART_MAGIC_OFFSET);
if ((*part_magic == xlate16(PART_MAGIC))) {
part = (struct partition *) (buf + PART_OFFSET);
for (p = 0; p < 4; p++, part++) {
/* Table is invalid if boot indicator not 0 or 0x80 */
if ((part->boot_ind & 0x7f)) {
ret = 0;
break;
}
/* Must have at least one non-empty partition */
if (part->nr_sects)
ret = 1;
}
}
out:
if (!dev_close(dev))
stack;
return ret;
}
int is_partitioned_dev(struct device *dev)
{
if (!_is_partitionable(dev))
return 0;
return _has_partition_table(dev);
}
#if 0
#include <sys/stat.h>
#include <sys/mman.h>
@@ -27,24 +114,13 @@
#include <linux/major.h>
#include <linux/genhd.h>
#include "dbg_malloc.h"
#include "log.h"
#include "dev-cache.h"
#include "metadata.h"
#include "device.h"
int _get_partition_type(struct dev_filter *filter, struct device *d);
#define MINOR_PART(dm, d) (MINOR((d)->dev) % dev_max_partitions(dm, (d)->dev))
#define MINOR_PART(dev) (MINOR((dev)->dev) % max_partitions(MINOR((dev)->dev)))
int is_whole_disk(struct dev_filter *filter, struct device *d)
int is_extended_partition(struct device *d)
{
return (MINOR_PART(dm, d)) ? 0 : 1;
}
int is_extended_partition(struct dev_mgr *dm, struct device *d)
{
return (MINOR_PART(dm, d) > 4) ? 1 : 0;
return (MINOR_PART(d) > 4) ? 1 : 0;
}
struct device *dev_primary(struct dev_mgr *dm, struct device *d)

View File

@@ -22,6 +22,7 @@
#define DEV_ACCESSED_W 0x00000001 /* Device written to? */
#define DEV_REGULAR 0x00000002 /* Regular file? */
#define DEV_ALLOCED 0x00000004 /* dbg_malloc used */
#define DEV_OPENED_RW 0x00000008 /* Opened RW */
/*
* All devices in LVM will be represented by one of these.
@@ -34,6 +35,7 @@ struct device {
/* private */
int fd;
int open_count;
int block_size;
uint32_t flags;
uint64_t end;
struct list open_list;
@@ -89,15 +91,14 @@ static inline const char *dev_name(const struct device *dev)
/* Return a valid device name from the alias list; NULL otherwise */
const char *dev_name_confirmed(struct device *dev, int quiet);
/* Does device contain md superblock? If so, where? */
int dev_is_md(struct device *dev, uint64_t *sb);
/* FIXME Check partition type if appropriate */
#define is_lvm_partition(a) 1
/* int is_lvm_partition(const char *name); */
/*
static inline int is_lvm_partition(const char *name)
{
return 1;
}
*/
int is_partitioned_dev(struct device *dev);
#endif

View File

@@ -317,7 +317,7 @@ void lvdisplay_colons(struct logical_volume *lv)
{
int inkernel;
struct lvinfo info;
inkernel = lv_info(lv, &info) && info.exists;
inkernel = lv_info(lv, &info, 1) && info.exists;
log_print("%s%s/%s:%s:%d:%d:-1:%d:%" PRIu64 ":%d:-1:%d:%d:%d:%d",
lv->vg->cmd->dev_dir,
@@ -348,7 +348,7 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
return 0;
}
inkernel = lv_info(lv, &info) && info.exists;
inkernel = lv_info(lv, &info, 1) && info.exists;
log_print("--- Logical volume ---");

View File

@@ -28,42 +28,24 @@
static int _ignore_md(struct dev_filter *f, struct device *dev)
{
uint64_t size, sector;
uint32_t md_magic;
if (!dev_get_size(dev, &size)) {
stack;
return 0;
}
if (size < MD_RESERVED_SECTORS * 2)
/*
* We could ignore it since it is obviously too
* small, but that's not our job.
*/
int ret;
if (!md_filtering())
return 1;
ret = dev_is_md(dev, NULL);
if (!dev_open(dev)) {
stack;
if (ret == 1) {
log_debug("%s: Skipping md component device", dev_name(dev));
return 0;
}
sector = MD_NEW_SIZE_SECTORS(size);
/* Check if it is an md component device. */
if (dev_read(dev, sector << SECTOR_SHIFT, sizeof(uint32_t), &md_magic)) {
if (md_magic == MD_SB_MAGIC) {
log_debug("%s: Skipping md component device",
dev_name(dev));
if (!dev_close(dev))
stack;
return 0;
}
if (ret < 0) {
log_debug("%s: Skipping: error in md component detection",
dev_name(dev));
return 0;
}
if (!dev_close(dev))
stack;
return 1;
}

View File

@@ -212,13 +212,10 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
sl = list_item(ah, struct str_list);
hash_insert(pf->devices, sl->str, l);
}
}
} else if (l == PF_BAD_DEVICE)
log_debug("%s: Skipping (cached)", dev_name(dev));
if (l == PF_BAD_DEVICE) {
log_debug("%s: Skipping (cached)", dev_name(dev));
return 0;
} else
return 1;
return (l == PF_BAD_DEVICE) ? 0 : 1;
}
static void _destroy(struct dev_filter *f)

View File

@@ -101,7 +101,7 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
unsigned count = 0;
int i, r = 0;
if (!(scratch = pool_create(1024))) {
if (!(scratch = pool_create("filter matcher", 1024))) {
stack;
return 0;
}
@@ -186,6 +186,9 @@ static int _accept_p(struct dev_filter *f, struct device *dev)
first = 0;
}
if (rejected)
log_debug("%s: Skipping (regex)", dev_name(dev));
/*
* pass everything that doesn't match
* anything.
@@ -201,7 +204,7 @@ static void _destroy(struct dev_filter *f)
struct dev_filter *regex_filter_create(struct config_value *patterns)
{
struct pool *mem = pool_create(10 * 1024);
struct pool *mem = pool_create("filter regex", 10 * 1024);
struct rfilter *rf;
struct dev_filter *f;

View File

@@ -194,8 +194,10 @@ static int _read_devs(struct dev_set *ds, const char *dir)
dtype = d->d_type;
if (dtype == DT_UNKNOWN) {
if (stat(path, &info) >= 0) {
if (S_ISDIR(info.st_mode))
if (lstat(path, &info) >= 0) {
if (S_ISLNK(info.st_mode))
dtype = DT_LNK;
else if (S_ISDIR(info.st_mode))
dtype = DT_DIR;
else if (S_ISREG(info.st_mode))
dtype = DT_REG;
@@ -246,7 +248,11 @@ static int _accept_p(struct dev_filter *f, struct device *dev)
if (ds->initialised != 1)
return 1;
return _set_lookup(ds, dev->dev);
if (!_set_lookup(ds, dev->dev)) {
log_debug("%s: Skipping (sysfs)", dev_name(dev));
return 0;
} else
return 1;
}
static void _destroy(struct dev_filter *f)
@@ -265,7 +271,7 @@ struct dev_filter *sysfs_filter_create(const char *proc)
if (!_locate_sysfs_blocks(proc, sys_block, sizeof(sys_block)))
return NULL;
if (!(mem = pool_create(256))) {
if (!(mem = pool_create("sysfs", 256))) {
log_error("sysfs pool creation failed");
return NULL;
}

View File

@@ -18,6 +18,7 @@
#include "filter.h"
#include "lvm-string.h"
#include "config.h"
#include "metadata.h"
#include <dirent.h>
#include <unistd.h>
@@ -27,6 +28,10 @@
#define NUMBER_OF_MAJORS 4096
/* FIXME Make this sparse */
/* 0 means LVM won't use this major number. */
static int _max_partitions_by_major[NUMBER_OF_MAJORS];
typedef struct {
const char *name;
const int max_partitions;
@@ -39,12 +44,19 @@ int md_major(void)
return _md_major;
}
/* This list can be supplemented with devices/types in the config file */
/*
* Devices are only checked for partition tables if their minor number
* is a multiple of the number corresponding to their type below
* i.e. this gives the granularity of whole-device minor numbers.
* Use 1 if the device is not partitionable.
*
* The list can be supplemented with devices/types in the config file.
*/
static const device_info_t device_info[] = {
{"ide", 16}, /* IDE disk */
{"ide", 64}, /* IDE disk */
{"sd", 16}, /* SCSI disk */
{"md", 16}, /* Multiple Disk driver (SoftRAID) */
{"loop", 16}, /* Loop device */
{"md", 1}, /* Multiple Disk driver (SoftRAID) */
{"loop", 1}, /* Loop device */
{"dasd", 4}, /* DASD disk (IBM S/390, zSeries) */
{"dac960", 8}, /* DAC960 */
{"nbd", 16}, /* Network Block Device */
@@ -53,6 +65,7 @@ static const device_info_t device_info[] = {
{"ubd", 16}, /* User-mode virtual block device */
{"ataraid", 16}, /* ATA Raid */
{"drbd", 16}, /* Distributed Replicated Block Device */
{"emcpower", 16}, /* EMC Powerpath */
{"power2", 16}, /* EMC Powerpath */
{"i2o_block", 16}, /* i2o Block Disk */
{"iseries/vd", 8}, /* iSeries disks */
@@ -62,29 +75,49 @@ static const device_info_t device_info[] = {
static int _passes_lvm_type_device_filter(struct dev_filter *f,
struct device *dev)
{
int fd;
const char *name = dev_name(dev);
int ret = 0;
uint64_t size;
/* Is this a recognised device type? */
if (!(((int *) f->private)[MAJOR(dev->dev)])) {
if (!_max_partitions_by_major[MAJOR(dev->dev)]) {
log_debug("%s: Skipping: Unrecognised LVM device type %"
PRIu64, name, (uint64_t) MAJOR(dev->dev));
return 0;
}
/* Check it's accessible */
if ((fd = open(name, O_RDONLY)) < 0) {
log_debug("%s: Skipping: open failed: %s", name,
strerror(errno));
if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
log_debug("%s: Skipping: open failed", name);
return 0;
}
/* Check it's not too small */
if (!dev_get_size(dev, &size)) {
log_debug("%s: Skipping: dev_get_size failed", name);
goto out;
}
close(fd);
if (size < PV_MIN_SIZE) {
log_debug("%s: Skipping: Too small to hold a PV", name);
goto out;
}
return 1;
if (is_partitioned_dev(dev)) {
log_debug("%s: Skipping: Partition table signature found",
name);
goto out;
}
ret = 1;
out:
dev_close(dev);
return ret;
}
static int *_scan_proc_dev(const char *proc, const struct config_node *cn)
static int _scan_proc_dev(const char *proc, const struct config_node *cn)
{
char line[80];
char proc_devices[PATH_MAX];
@@ -94,36 +127,31 @@ static int *_scan_proc_dev(const char *proc, const struct config_node *cn)
int blocksection = 0;
size_t dev_len = 0;
struct config_value *cv;
int *max_partitions_by_major;
char *name;
/* FIXME Make this sparse */
if (!(max_partitions_by_major =
dbg_malloc(sizeof(int) * NUMBER_OF_MAJORS))) {
log_error("Filter failed to allocate max_partitions_by_major");
return NULL;
}
if (!*proc) {
log_verbose("No proc filesystem found: using all block device "
"types");
for (i = 0; i < NUMBER_OF_MAJORS; i++)
max_partitions_by_major[i] = 1;
return max_partitions_by_major;
_max_partitions_by_major[i] = 1;
return 1;
}
/* All types unrecognised initially */
memset(_max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS);
if (lvm_snprintf(proc_devices, sizeof(proc_devices),
"%s/devices", proc) < 0) {
log_error("Failed to create /proc/devices string");
return NULL;
return 0;
}
if (!(pd = fopen(proc_devices, "r"))) {
log_sys_error("fopen", proc_devices);
return NULL;
return 0;
}
memset(max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS);
while (fgets(line, 80, pd) != NULL) {
i = 0;
while (line[i] == ' ' && line[i] != '\0')
@@ -158,13 +186,13 @@ static int *_scan_proc_dev(const char *proc, const struct config_node *cn)
if (dev_len <= strlen(line + i) &&
!strncmp(device_info[j].name, line + i, dev_len) &&
(line_maj < NUMBER_OF_MAJORS)) {
max_partitions_by_major[line_maj] =
_max_partitions_by_major[line_maj] =
device_info[j].max_partitions;
break;
}
}
if (max_partitions_by_major[line_maj] || !cn)
if (!cn)
continue;
/* Check devices/types for local variations */
@@ -172,7 +200,7 @@ static int *_scan_proc_dev(const char *proc, const struct config_node *cn)
if (cv->type != CFG_STRING) {
log_error("Expecting string in devices/types "
"in config file");
return NULL;
return 0;
}
dev_len = strlen(cv->v.str);
name = cv->v.str;
@@ -181,24 +209,29 @@ static int *_scan_proc_dev(const char *proc, const struct config_node *cn)
log_error("Max partition count missing for %s "
"in devices/types in config file",
name);
return NULL;
return 0;
}
if (!cv->v.i) {
log_error("Zero partition count invalid for "
"%s in devices/types in config file",
name);
return NULL;
return 0;
}
if (dev_len <= strlen(line + i) &&
!strncmp(name, line + i, dev_len) &&
(line_maj < NUMBER_OF_MAJORS)) {
max_partitions_by_major[line_maj] = cv->v.i;
_max_partitions_by_major[line_maj] = cv->v.i;
break;
}
}
}
fclose(pd);
return max_partitions_by_major;
return 1;
}
int max_partitions(int major)
{
return _max_partitions_by_major[major];
}
struct dev_filter *lvm_type_filter_create(const char *proc,
@@ -213,8 +246,9 @@ struct dev_filter *lvm_type_filter_create(const char *proc,
f->passes_filter = _passes_lvm_type_device_filter;
f->destroy = lvm_type_filter_destroy;
f->private = NULL;
if (!(f->private = _scan_proc_dev(proc, cn))) {
if (!_scan_proc_dev(proc, cn)) {
stack;
return NULL;
}
@@ -224,7 +258,6 @@ struct dev_filter *lvm_type_filter_create(const char *proc,
void lvm_type_filter_destroy(struct dev_filter *f)
{
dbg_free(f->private);
dbg_free(f);
return;
}

View File

@@ -37,4 +37,6 @@ void lvm_type_filter_destroy(struct dev_filter *f);
int md_major(void);
int max_partitions(int major);
#endif

View File

@@ -183,7 +183,7 @@ static struct volume_group *_vg_read(struct format_instance *fid,
const char *vg_name,
struct metadata_area *mda)
{
struct pool *mem = pool_create(1024 * 10);
struct pool *mem = pool_create("lvm1 vg_read", 1024 * 10);
struct list pvs;
struct volume_group *vg = NULL;
list_init(&pvs);
@@ -276,7 +276,7 @@ static int _flatten_vg(struct format_instance *fid, struct pool *mem,
static int _vg_write(struct format_instance *fid, struct volume_group *vg,
struct metadata_area *mda)
{
struct pool *mem = pool_create(1024 * 10);
struct pool *mem = pool_create("lvm1 vg_write", 1024 * 10);
struct list pvds;
int r = 0;
@@ -299,7 +299,7 @@ static int _vg_write(struct format_instance *fid, struct volume_group *vg,
static int _pv_read(const struct format_type *fmt, const char *pv_name,
struct physical_volume *pv, struct list *mdas)
{
struct pool *mem = pool_create(1024);
struct pool *mem = pool_create("lvm1 pv_read", 1024);
struct disk_list *dl;
struct device *dev;
int r = 0;
@@ -421,7 +421,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
pv->pe_size = pv->pe_count = 0;
pv->pe_start = PE_ALIGN;
if (!(mem = pool_create(1024))) {
if (!(mem = pool_create("lvm1 pv_write", 1024))) {
stack;
return 0;
}

View File

@@ -646,7 +646,7 @@ int import_snapshots(struct pool *mem, struct volume_group *vg,
continue;
/* insert the snapshot */
if (!vg_add_snapshot(org, cow, 1, NULL,
if (!vg_add_snapshot(org, cow, 1, NULL, org->le_count,
lvd->lv_chunk_size)) {
log_err("Couldn't add snapshot.");
return 0;

View File

@@ -344,7 +344,7 @@ int import_extents(struct cmd_context *cmd, struct volume_group *vg,
struct list *pvds)
{
int r = 0;
struct pool *scratch = pool_create(10 * 1024);
struct pool *scratch = pool_create("lvm1 import_extents", 10 * 1024);
struct hash_table *maps;
if (!scratch) {

View File

@@ -30,7 +30,7 @@ int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
struct list *pvh;
struct list all_pvs;
struct disk_list *dl;
struct pool *mem = pool_create(10 * 1024);
struct pool *mem = pool_create("lvm1 vg_number", 10 * 1024);
int numbers[MAX_VG], i, r = 0;
list_init(&all_pvs);

View File

@@ -259,7 +259,7 @@ static int _read_vg_pds(const struct format_type *fmt, struct pool *mem,
/* FIXME: maybe should return a different error in memory
* allocation failure */
if (!(tmpmem = pool_create(512))) {
if (!(tmpmem = pool_create("pool read_vg", 512))) {
stack;
return 0;
}

View File

@@ -181,7 +181,7 @@ static struct volume_group *_vg_read(struct format_instance *fid,
const char *vg_name,
struct metadata_area *mda)
{
struct pool *mem = pool_create(1024);
struct pool *mem = pool_create("pool vg_read", 1024);
struct list pds;
struct volume_group *vg = NULL;
@@ -227,7 +227,7 @@ static int _pv_setup(const struct format_type *fmt,
static int _pv_read(const struct format_type *fmt, const char *pv_name,
struct physical_volume *pv, struct list *mdas)
{
struct pool *mem = pool_create(1024);
struct pool *mem = pool_create("pool pv_read", 1024);
struct pool_list *pl;
struct device *dev;
int r = 0;

View File

@@ -513,7 +513,7 @@ static int _print_snapshot(struct formatter *f, struct snapshot *snap,
}
seg.le = 0;
seg.len = snap->origin->le_count;
seg.len = snap->le_count;
seg.origin = snap->origin;
seg.cow = snap->cow;
seg.chunk_size = snap->chunk_size;
@@ -652,7 +652,7 @@ static int _build_pv_names(struct formatter *f, struct volume_group *vg)
struct physical_volume *pv;
char buffer[32], *name;
if (!(f->mem = pool_create(512))) {
if (!(f->mem = pool_create("text pv_names", 512))) {
stack;
goto bad;
}

View File

@@ -139,8 +139,7 @@ static int _send_request(char *inbuf, int inlen, char **retbuf)
/* Read the returned values */
off = 1; /* we've already read the first byte */
while (off < outheader->arglen && len > 0) {
while (off <= outheader->arglen && len > 0) {
len = read(_clvmd_sock, outheader->args + off,
buflen - off - offsetof(struct clvm_header, args));
if (len > 0)
@@ -150,7 +149,7 @@ static int _send_request(char *inbuf, int inlen, char **retbuf)
/* Was it an error ? */
if (outheader->status < 0) {
errno = -outheader->status;
log_error("cluster send request failed: %s", strerror(errno));
log_error("cluster request failed: %s", strerror(errno));
return 0;
}

View File

@@ -28,6 +28,7 @@ static struct str_list _log_dev_alias;
static int _verbose_level = VERBOSE_BASE_LEVEL;
static int _test = 0;
static int _partial = 0;
static int _md_filtering = 0;
static int _pvmove = 0;
static int _debug_level = 0;
static int _syslog = 0;
@@ -138,6 +139,11 @@ void init_partial(int level)
_partial = level;
}
void init_md_filtering(int level)
{
_md_filtering = level;
}
void init_pvmove(int level)
{
_pvmove = level;
@@ -187,6 +193,11 @@ int partial_mode()
return _partial;
}
int md_filtering()
{
return _md_filtering;
}
int pvmove_mode()
{
return _pvmove;
@@ -215,7 +226,7 @@ int debug_level()
void print_log(int level, const char *file, int line, const char *format, ...)
{
va_list ap;
char buf[1024], buf2[4096];
char buf[1024], buf2[4096], locn[4096];
int bufused, n;
const char *message;
const char *trformat; /* Translated format string */
@@ -243,36 +254,46 @@ void print_log(int level, const char *file, int line, const char *format, ...)
log_it:
if (!_log_suppress) {
if (_verbose_level > _LOG_DEBUG)
lvm_snprintf(locn, sizeof(locn), "#%s:%d ",
file, line);
else
locn[0] = '\0';
va_start(ap, format);
switch (level) {
case _LOG_DEBUG:
if (!strcmp("<backtrace>", format))
if (!strcmp("<backtrace>", format) &&
_verbose_level <= _LOG_DEBUG)
break;
if (_verbose_level >= _LOG_DEBUG) {
printf("%s%s", _cmd_name, _msg_prefix);
fprintf(stderr, "%s%s%s", locn, _cmd_name,
_msg_prefix);
if (_indent)
printf(" ");
vprintf(trformat, ap);
putchar('\n');
fprintf(stderr, " ");
vfprintf(stderr, trformat, ap);
fputc('\n', stderr);
}
break;
case _LOG_INFO:
if (_verbose_level >= _LOG_INFO) {
printf("%s%s", _cmd_name, _msg_prefix);
fprintf(stderr, "%s%s%s", locn, _cmd_name,
_msg_prefix);
if (_indent)
printf(" ");
vprintf(trformat, ap);
putchar('\n');
fprintf(stderr, " ");
vfprintf(stderr, trformat, ap);
fputc('\n', stderr);
}
break;
case _LOG_NOTICE:
if (_verbose_level >= _LOG_NOTICE) {
printf("%s%s", _cmd_name, _msg_prefix);
fprintf(stderr, "%s%s%s", locn, _cmd_name,
_msg_prefix);
if (_indent)
printf(" ");
vprintf(trformat, ap);
putchar('\n');
fprintf(stderr, " ");
vfprintf(stderr, trformat, ap);
fputc('\n', stderr);
}
break;
case _LOG_WARN:
@@ -284,7 +305,8 @@ void print_log(int level, const char *file, int line, const char *format, ...)
break;
case _LOG_ERR:
if (_verbose_level >= _LOG_ERR) {
fprintf(stderr, "%s%s", _cmd_name, _msg_prefix);
fprintf(stderr, "%s%s%s", locn, _cmd_name,
_msg_prefix);
vfprintf(stderr, trformat, ap);
fputc('\n', stderr);
}
@@ -292,7 +314,8 @@ void print_log(int level, const char *file, int line, const char *format, ...)
case _LOG_FATAL:
default:
if (_verbose_level >= _LOG_FATAL) {
fprintf(stderr, "%s%s", _cmd_name, _msg_prefix);
fprintf(stderr, "%s%s%s", locn, _cmd_name,
_msg_prefix);
vfprintf(stderr, trformat, ap);
fputc('\n', stderr);
}

View File

@@ -63,6 +63,7 @@ void fin_syslog(void);
void init_verbose(int level);
void init_test(int level);
void init_partial(int level);
void init_md_filtering(int level);
void init_pvmove(int level);
void init_debug(int level);
void init_cmd_name(int status);
@@ -75,6 +76,7 @@ void set_cmd_name(const char *cmd_name);
int test_mode(void);
int partial_mode(void);
int md_filtering(void);
int pvmove_mode(void);
int debug_level(void);
int ignorelockingfailure(void);

View File

@@ -458,7 +458,7 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv,
if (segtype->flags & SEG_VIRTUAL)
return _alloc_virtual(lv, allocated, segtype);
if (!(scratch = pool_create(1024))) {
if (!(scratch = pool_create("allocation", 1024))) {
stack;
return 0;
}

View File

@@ -711,6 +711,11 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
log_error("Automatic metadata correction failed");
return NULL;
}
if (!vg_commit(correct_vg)) {
log_error("Automatic metadata correction commit "
"failed");
return NULL;
}
}
if ((correct_vg->status & PVMOVE) && !pvmove_mode()) {

View File

@@ -255,6 +255,7 @@ struct snapshot {
int persistent; /* boolean */
uint32_t chunk_size; /* in 512 byte sectors */
uint32_t le_count;
struct logical_volume *origin;
struct logical_volume *cow;
@@ -496,9 +497,9 @@ struct snapshot *find_cow(const struct logical_volume *lv);
struct snapshot *find_origin(const struct logical_volume *lv);
struct list *find_snapshots(const struct logical_volume *lv);
int vg_add_snapshot(struct logical_volume *origin,
struct logical_volume *cow,
int persistent, struct id *id, uint32_t chunk_size);
int vg_add_snapshot(struct logical_volume *origin, struct logical_volume *cow,
int persistent, struct id *id, uint32_t extent_count,
uint32_t chunk_size);
int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow);

View File

@@ -104,9 +104,9 @@ struct list *find_snapshots(const struct logical_volume *lv)
return snaplist;
}
int vg_add_snapshot(struct logical_volume *origin,
struct logical_volume *cow,
int persistent, struct id *id, uint32_t chunk_size)
int vg_add_snapshot(struct logical_volume *origin, struct logical_volume *cow,
int persistent, struct id *id, uint32_t extent_count,
uint32_t chunk_size)
{
struct snapshot *s;
struct snapshot_list *sl;
@@ -127,6 +127,7 @@ int vg_add_snapshot(struct logical_volume *origin,
s->persistent = persistent;
s->chunk_size = chunk_size;
s->le_count = extent_count;
s->origin = origin;
s->cow = cow;

View File

@@ -134,17 +134,19 @@ static void _quote_hyphens(char **out, const char *src)
char *build_dm_name(struct pool *mem, const char *vg,
const char *lv, const char *layer)
{
size_t len = 0;
int hyphens = 0;
size_t len = 1;
int hyphens = 1;
char *r, *out;
_count_hyphens(vg, &len, &hyphens);
_count_hyphens(lv, &len, &hyphens);
if (layer && *layer)
if (layer && *layer) {
_count_hyphens(layer, &len, &hyphens);
hyphens++;
}
len += hyphens + 2;
len += hyphens;
if (!(r = pool_alloc(mem, len))) {
stack;

View File

@@ -19,6 +19,8 @@
#include <stdarg.h>
#ifdef DEBUG_MEM
struct memblock {
struct memblock *prev, *next; /* All allocated blocks are linked */
size_t length; /* Size of the requested block */
@@ -47,7 +49,7 @@ void *malloc_aux(size_t s, const char *file, int line)
if (s > 50000000) {
log_error("Huge memory allocation (size %" PRIuPTR
") rejected - bug?", s);
") rejected - metadata corruption?", s);
return 0;
}
@@ -166,7 +168,6 @@ void *realloc_aux(void *p, unsigned int s, const char *file, int line)
return r;
}
#ifdef DEBUG_MEM
int dump_memory(void)
{
unsigned long tot = 0;
@@ -213,10 +214,18 @@ void bounds_check(void)
mb = mb->next;
}
}
#endif
/*
* Local variables:
* c-file-style: "linux"
* End:
*/
#else
void *malloc_aux(size_t s, const char *file, int line)
{
if (s > 50000000) {
log_error("Huge memory allocation (size %" PRIuPTR
") rejected - metadata corruption?", s);
return 0;
}
return malloc(s);
}
#endif

View File

@@ -20,22 +20,26 @@
#include <stdlib.h>
#include <string.h>
#ifdef DEBUG_MEM
void *malloc_aux(size_t s, const char *file, int line);
# define dbg_malloc(s) malloc_aux((s), __FILE__, __LINE__)
#ifdef DEBUG_MEM
void free_aux(void *p);
void *realloc_aux(void *p, unsigned int s, const char *file, int line);
int dump_memory(void);
void bounds_check(void);
# define dbg_malloc(s) malloc_aux((s), __FILE__, __LINE__)
# define dbg_free(p) free_aux(p)
# define dbg_realloc(p, s) realloc_aux(p, s, __FILE__, __LINE__)
#else
# define dbg_malloc(s) malloc(s)
# define dbg_free(p) free(p)
# define dbg_realloc(p, s) realloc(p, s)
# define dump_memory()
# define bounds_check()
#endif
static inline char *dbg_strdup(const char *str)

View File

@@ -22,38 +22,64 @@ struct block {
void *data;
};
typedef struct {
unsigned block_serialno; /* Non-decreasing serialno of block */
unsigned blocks_allocated; /* Current number of blocks allocated */
unsigned blocks_max; /* Max no of concurrently-allocated blocks */
unsigned int bytes, maxbytes;
} pool_stats;
struct pool {
const char *name;
int begun;
struct block *object;
struct block *blocks;
struct block *tail;
pool_stats stats;
};
/* by default things come out aligned for doubles */
#define DEFAULT_ALIGNMENT __alignof__ (double)
struct pool *pool_create(size_t chunk_hint)
struct pool *pool_create(const char *name, size_t chunk_hint)
{
struct pool *mem = dbg_malloc(sizeof(*mem));
if (!mem) {
log_error("Couldn't create memory pool (size %" PRIsize_t ")",
sizeof(*mem));
log_error("Couldn't create memory pool %s (size %"
PRIsize_t ")", name, sizeof(*mem));
return NULL;
}
mem->name = name;
mem->begun = 0;
mem->object = 0;
mem->blocks = mem->tail = NULL;
mem->stats.block_serialno = 0;
mem->stats.blocks_allocated = 0;
mem->stats.blocks_max = 0;
mem->stats.bytes = 0;
mem->stats.maxbytes = 0;
#ifdef DEBUG_POOL
log_debug("Created mempool %s", name);
#endif
return mem;
}
static void _free_blocks(struct block *b)
static void _free_blocks(struct pool *p, struct block *b)
{
struct block *n;
while (b) {
p->stats.bytes -= b->size;
p->stats.blocks_allocated--;
n = b->next;
dbg_free(b->data);
dbg_free(b);
@@ -61,9 +87,22 @@ static void _free_blocks(struct block *b)
}
}
static void _pool_stats(struct pool *p, const char *action)
{
#ifdef DEBUG_POOL
log_debug("%s mempool %s: %u/%u bytes, %u/%u blocks, "
"%u allocations)", action, p->name, p->stats.bytes,
p->stats.maxbytes, p->stats.blocks_allocated,
p->stats.blocks_max, p->stats.block_serialno);
#else
;
#endif
}
void pool_destroy(struct pool *p)
{
_free_blocks(p->blocks);
_pool_stats(p, "Destroying");
_free_blocks(p, p->blocks);
dbg_free(p);
}
@@ -79,6 +118,15 @@ static void _append_block(struct pool *p, struct block *b)
p->tail = b;
} else
p->blocks = p->tail = b;
p->stats.block_serialno++;
p->stats.blocks_allocated++;
if (p->stats.blocks_allocated > p->stats.blocks_max)
p->stats.blocks_max = p->stats.blocks_allocated;
p->stats.bytes += b->size;
if (p->stats.bytes > p->stats.maxbytes)
p->stats.maxbytes = p->stats.bytes;
}
static struct block *_new_block(size_t s, unsigned alignment)
@@ -121,12 +169,14 @@ void *pool_alloc_aligned(struct pool *p, size_t s, unsigned alignment)
return NULL;
_append_block(p, b);
return b->data;
}
void pool_empty(struct pool *p)
{
_free_blocks(p->blocks);
_pool_stats(p, "Emptying");
_free_blocks(p, p->blocks);
p->blocks = p->tail = NULL;
}
@@ -134,6 +184,8 @@ void pool_free(struct pool *p, void *ptr)
{
struct block *b, *prev = NULL;
_pool_stats(p, "Freeing (before)");
for (b = p->blocks; b; b = b->next) {
if (b->data == ptr)
break;
@@ -147,13 +199,15 @@ void pool_free(struct pool *p, void *ptr)
*/
assert(b);
_free_blocks(b);
_free_blocks(p, b);
if (prev) {
p->tail = prev;
prev->next = NULL;
} else
p->blocks = p->tail = NULL;
_pool_stats(p, "Freeing (after)");
}
int pool_begin_object(struct pool *p, size_t init_size)

View File

@@ -36,14 +36,14 @@ struct chunk *_new_chunk(struct pool *p, size_t s);
/* by default things come out aligned for doubles */
#define DEFAULT_ALIGNMENT __alignof__ (double)
struct pool *pool_create(size_t chunk_hint)
struct pool *pool_create(const char *name, size_t chunk_hint)
{
size_t new_size = 1024;
struct pool *p = dbg_malloc(sizeof(*p));
if (!p) {
log_error("Couldn't create memory pool (size %" PRIsize_t ")",
sizeof(*p));
log_error("Couldn't create memory pool %s (size %"
PRIsize_t ")", name, sizeof(*p));
return 0;
}
memset(p, 0, sizeof(*p));

View File

@@ -55,7 +55,7 @@
struct pool;
/* constructor and destructor */
struct pool *pool_create(size_t chunk_hint);
struct pool *pool_create(const char *name, size_t chunk_hint);
void pool_destroy(struct pool *p);
/* simple allocation/free routines */

View File

@@ -275,7 +275,7 @@ struct matcher *matcher_create(struct pool *mem, const char **patterns,
int i;
size_t len = 0;
struct rx_node *rx;
struct pool *scratch = pool_create(10 * 1024);
struct pool *scratch = pool_create("regex matcher", 10 * 1024);
struct matcher *m;
if (!scratch) {

View File

@@ -295,7 +295,7 @@ static int _lvkmaj_disp(struct report_handle *rh, struct field *field,
struct lvinfo info;
uint64_t minusone = UINT64_C(-1);
if (lv_info(lv, &info) && info.exists)
if (lv_info(lv, &info, 0) && info.exists)
return _int_disp(rh, field, &info.major);
else
return _int_disp(rh, field, &minusone);
@@ -310,7 +310,7 @@ static int _lvkmin_disp(struct report_handle *rh, struct field *field,
struct lvinfo info;
uint64_t minusone = UINT64_C(-1);
if (lv_info(lv, &info) && info.exists)
if (lv_info(lv, &info, 0) && info.exists)
return _int_disp(rh, field, &info.minor);
else
return _int_disp(rh, field, &minusone);
@@ -362,7 +362,7 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field,
else
repstr[3] = '-';
if (lv_info(lv, &info) && info.exists) {
if (lv_info(lv, &info, 1) && info.exists) {
if (info.suspended)
repstr[4] = 's'; /* Suspended */
else
@@ -774,7 +774,7 @@ static int _snpercent_disp(struct report_handle *rh, struct field *field,
}
if (!(snap = find_cow(lv)) ||
(lv_info(snap->cow, &info) && !info.exists)) {
(lv_info(snap->cow, &info, 0) && !info.exists)) {
field->report_string = "";
*sortval = UINT64_C(0);
field->sort_value = sortval;
@@ -1081,7 +1081,7 @@ void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
rh->field_prefix = "";
}
if (!(rh->mem = pool_create(10 * 1024))) {
if (!(rh->mem = pool_create("report", 10 * 1024))) {
log_error("Allocation of memory pool for report failed");
return NULL;
}

View File

@@ -31,7 +31,7 @@ static const char *_name(const struct lv_segment *seg)
static int _text_import(struct lv_segment *seg, const struct config_node *sn,
struct hash_table *pv_hash)
{
uint32_t chunk_size;
uint32_t chunk_size, extent_count;
const char *org_name, *cow_name;
struct logical_volume *org, *cow;
@@ -70,7 +70,11 @@ static int _text_import(struct lv_segment *seg, const struct config_node *sn,
return 0;
}
if (!vg_add_snapshot(org, cow, 1, &seg->lv->lvid.id[1], chunk_size)) {
if (!get_config_uint32(sn, "extent_count", &extent_count))
extent_count = org->le_count;
if (!vg_add_snapshot(org, cow, 1, &seg->lv->lvid.id[1], extent_count,
chunk_size)) {
stack;
return 0;
}
@@ -81,6 +85,8 @@ static int _text_import(struct lv_segment *seg, const struct config_node *sn,
static int _text_export(const struct lv_segment *seg, struct formatter *f)
{
outf(f, "chunk_size = %u", seg->chunk_size);
if (seg->len != seg->origin->le_count)
outf(f, "extent_count = %u", seg->len);
outf(f, "origin = \"%s\"", seg->origin->name);
outf(f, "cow_store = \"%s\"", seg->cow->name);

View File

@@ -20,6 +20,7 @@ dm_task_set_minor
dm_task_set_sector
dm_task_set_message
dm_task_add_target
dm_task_no_open_count
dm_get_next_target
dm_task_run
dm_set_dev_dir

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-2005 Red Hat, Inc. All rights reserved.
#
# This file is part of the device-mapper userspace tools.
#
@@ -17,13 +17,16 @@ top_srcdir = @top_srcdir@
VPATH = @srcdir@
interface = @interface@
SOURCES = libdm-common.c $(interface)/libdm-iface.c
SOURCES = libdm-common.c libdm-file.c $(interface)/libdm-iface.c
INCLUDES = -I$(interface)
LIB_STATIC = $(interface)/libdevmapper.a
LIB_SHARED = $(interface)/libdevmapper.so
CFLAGS += -DDEVICE_UID=@DEVICE_UID@ -DDEVICE_GID=@DEVICE_GID@ \
-DDEVICE_MODE=@DEVICE_MODE@
include ../make.tmpl
.PHONY: install_dynamic install_static \

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-2005 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
@@ -13,22 +13,17 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "libdm-targets.h"
#include "libdm-common.h"
#include "log.h"
#include "libdm-file.h"
#ifdef DM_COMPAT
# include "libdm-compat.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <limits.h>
@@ -53,6 +48,13 @@
#error The version of dm-ioctl.h included is incompatible.
#endif
/* FIXME This should be exported in device-mapper.h */
#define DM_NAME "device-mapper"
#define PROC_MISC "/proc/misc"
#define PROC_DEVICES "/proc/devices"
#define MISC_NAME "misc"
/* dm major version no for running kernel */
static int _dm_version = DM_VERSION_MAJOR;
static int _log_suppress = 0;
@@ -114,22 +116,143 @@ static void *_align(void *ptr, unsigned int a)
return (void *) (((unsigned long) ptr + agn) & ~agn);
}
static int _get_proc_number(const char *file, const char *name,
uint32_t *number)
{
FILE *fl;
char nm[256];
int c;
if (!(fl = fopen(file, "r"))) {
log_error("%s: fopen failed: %s", file, strerror(errno));
return 0;
}
while (!feof(fl)) {
if (fscanf(fl, "%d %255s\n", number, &nm[0]) == 2) {
if (!strcmp(name, nm)) {
fclose(fl);
return 1;
}
} else do {
c = fgetc(fl);
} while (c != EOF && c != '\n');
}
fclose(fl);
log_error("%s: No entry for %s found", file, name);
return 0;
}
static int _control_device_number(uint32_t *major, uint32_t *minor)
{
if (!_get_proc_number(PROC_DEVICES, MISC_NAME, major) ||
!_get_proc_number(PROC_MISC, DM_NAME, minor)) {
*major = 0;
return 0;
}
return 1;
}
/*
* Returns 1 if exists; 0 if it doesn't; -1 if it's wrong
*/
static int _control_exists(const char *control, uint32_t major, uint32_t minor)
{
struct stat buf;
if (stat(control, &buf) < 0) {
if (errno != ENOENT)
log_error("%s: stat failed: %s", control,
strerror(errno));
return 0;
}
if (!S_ISCHR(buf.st_mode)) {
log_verbose("%s: Wrong inode type", control);
if (!unlink(control))
return 0;
log_error("%s: unlink failed: %s", control,
strerror(errno));
return -1;
}
if (major && buf.st_rdev != MKDEV(major, minor)) {
log_verbose("%s: Wrong device number: (%u, %u) instead of "
"(%u, %u)", control,
MAJOR(buf.st_mode), MINOR(buf.st_mode),
major, minor);
if (!unlink(control))
return 0;
log_error("%s: unlink failed: %s", control,
strerror(errno));
return -1;
}
return 1;
}
static int _create_control(const char *control, uint32_t major, uint32_t minor)
{
int ret;
mode_t old_umask;
if (!major)
return 0;
old_umask = umask(0022);
ret = create_dir(dm_dir());
umask(old_umask);
if (!ret)
return 0;
log_verbose("Creating device %s (%u, %u)", control, major, minor);
if (mknod(control, S_IFCHR | S_IRUSR | S_IWUSR,
MKDEV(major, minor)) < 0) {
log_error("%s: mknod failed: %s", control, strerror(errno));
return 0;
}
#ifdef HAVE_SELINUX
if (!set_selinux_context(control)) {
stack;
return 0;
}
#endif
return 1;
}
static int _open_control(void)
{
char control[PATH_MAX];
uint32_t major = 0, minor;
if (_control_fd != -1)
return 1;
snprintf(control, sizeof(control), "%s/control", dm_dir());
if (!_control_device_number(&major, &minor))
log_error("Is device-mapper driver missing from kernel?");
if (!_control_exists(control, major, minor) &&
!_create_control(control, major, minor))
goto error;
if ((_control_fd = open(control, O_RDWR)) < 0) {
log_error("%s: open failed: %s", control, strerror(errno));
log_error("Is device-mapper driver missing from kernel?");
return 0;
goto error;
}
return 1;
error:
log_error("Failure to communicate with kernel device-mapper driver.");
return 0;
}
void dm_task_destroy(struct dm_task *dmt)
@@ -495,9 +618,14 @@ static int _dm_task_run_v1(struct dm_task *dmt)
goto bad;
}
if (dmi->flags & DM_BUFFER_FULL_FLAG)
/* FIXME Increase buffer size and retry operation (if query) */
log_error("Warning: libdevmapper buffer too small for data");
switch (dmt->type) {
case DM_DEVICE_CREATE:
add_dev_node(dmt->dev_name, MAJOR(dmi->dev), MINOR(dmi->dev));
add_dev_node(dmt->dev_name, MAJOR(dmi->dev), MINOR(dmi->dev),
dmt->uid, dmt->gid, dmt->mode);
break;
case DM_DEVICE_REMOVE:
@@ -511,7 +639,8 @@ static int _dm_task_run_v1(struct dm_task *dmt)
case DM_DEVICE_MKNODES:
if (dmi->flags & DM_EXISTS_FLAG)
add_dev_node(dmt->dev_name, MAJOR(dmi->dev),
MINOR(dmi->dev));
MINOR(dmi->dev),
dmt->uid, dmt->gid, dmt->mode);
else
rm_dev_node(dmt->dev_name);
break;
@@ -800,6 +929,13 @@ int dm_task_set_sector(struct dm_task *dmt, uint64_t sector)
return 1;
}
int dm_task_no_open_count(struct dm_task *dmt)
{
dmt->no_open_count = 1;
return 1;
}
int dm_task_set_event_nr(struct dm_task *dmt, uint32_t event_nr)
{
dmt->event_nr = event_nr;
@@ -1152,7 +1288,8 @@ int dm_task_run(struct dm_task *dmt)
if (dmt->type == DM_DEVICE_CREATE && dmt->head)
return _create_and_load_v4(dmt);
if (dmt->type == DM_DEVICE_MKNODES && !dmt->dev_name)
if (dmt->type == DM_DEVICE_MKNODES && !dmt->dev_name &&
!dmt->uuid && dmt->major <= 0)
return _mknodes_v4(dmt);
if (!_open_control())
@@ -1168,8 +1305,13 @@ int dm_task_run(struct dm_task *dmt)
dmi->flags |= DM_STATUS_TABLE_FLAG;
dmi->flags |= DM_EXISTS_FLAG; /* FIXME */
log_debug("dm %s %s %s %s%.0llu %s", _cmd_data_v4[dmt->type].name,
if (dmt->no_open_count)
dmi->flags |= DM_SKIP_BDGET_FLAG;
log_debug("dm %s %s %s %s%c %.0llu %s", _cmd_data_v4[dmt->type].name,
dmi->name, dmi->uuid, dmt->newname ? dmt->newname : "",
dmt->no_open_count ? 'N' : 'O',
dmt->sector, dmt->message ? dmt->message : "");
if (ioctl(_control_fd, command, dmi) < 0) {
if (errno == ENXIO && ((dmt->type == DM_DEVICE_INFO) ||
@@ -1189,22 +1331,28 @@ int dm_task_run(struct dm_task *dmt)
ignore_error:
switch (dmt->type) {
case DM_DEVICE_CREATE:
add_dev_node(dmt->dev_name, MAJOR(dmi->dev), MINOR(dmi->dev));
add_dev_node(dmt->dev_name, MAJOR(dmi->dev), MINOR(dmi->dev),
dmt->uid, dmt->gid, dmt->mode);
break;
case DM_DEVICE_REMOVE:
rm_dev_node(dmt->dev_name);
/* FIXME Kernel needs to fill in dmi->name */
if (dmt->dev_name)
rm_dev_node(dmt->dev_name);
break;
case DM_DEVICE_RENAME:
rename_dev_node(dmt->dev_name, dmt->newname);
/* FIXME Kernel needs to fill in dmi->name */
if (dmt->dev_name)
rename_dev_node(dmt->dev_name, dmt->newname);
break;
case DM_DEVICE_MKNODES:
if (dmi->flags & DM_EXISTS_FLAG)
add_dev_node(dmt->dev_name, MAJOR(dmi->dev),
MINOR(dmi->dev));
else
add_dev_node(dmi->name, MAJOR(dmi->dev),
MINOR(dmi->dev),
dmt->uid, dmt->gid, dmt->mode);
else if (dmt->dev_name)
rm_dev_node(dmt->dev_name);
break;

View File

@@ -17,6 +17,7 @@
#define LIB_DMTARGETS_H
#include <inttypes.h>
#include <sys/types.h>
struct dm_ioctl;
struct dm_ioctl_v1;
@@ -40,6 +41,9 @@ struct dm_task {
uint32_t event_nr;
int major;
int minor;
uid_t uid;
gid_t gid;
mode_t mode;
union {
struct dm_ioctl *v4;
struct dm_ioctl_v1 *v1;
@@ -47,6 +51,7 @@ struct dm_task {
char *newname;
char *message;
uint64_t sector;
int no_open_count;
char *uuid;
};

View File

@@ -134,6 +134,7 @@ int dm_task_set_major(struct dm_task *dmt, int major);
int dm_task_set_event_nr(struct dm_task *dmt, uint32_t event_nr);
int dm_task_set_message(struct dm_task *dmt, const char *message);
int dm_task_set_sector(struct dm_task *dmt, uint64_t sector);
int dm_task_no_open_count(struct dm_task *dmt);
/*
* Use these to prepare for a create or reload.

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-2005 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
@@ -13,20 +13,14 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "libdm-targets.h"
#include "libdm-common.h"
#include "list.h"
#include "log.h"
#include "kdev_t.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <linux/dm-ioctl.h>
#ifdef HAVE_SELINUX
@@ -63,7 +57,7 @@ static void _default_log(int level, const char *file, int line,
if (level < _LOG_WARN)
fprintf(stderr, "\n");
else
printf("\n");
fprintf(stdout, "\n");
}
dm_log_fn _log = _default_log;
@@ -100,19 +94,22 @@ struct dm_task *dm_task_create(int type)
{
struct dm_task *dmt = malloc(sizeof(*dmt));
if (!dm_check_version())
return NULL;
if (!dmt) {
log_error("dm_task_create: malloc(%d) failed", sizeof(*dmt));
return NULL;
}
if (!dm_check_version())
return NULL;
memset(dmt, 0, sizeof(*dmt));
dmt->type = type;
dmt->minor = -1;
dmt->major = -1;
dmt->uid = DEVICE_UID;
dmt->gid = DEVICE_GID;
dmt->mode = DEVICE_MODE;
return dmt;
}
@@ -202,7 +199,7 @@ int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size,
}
#ifdef HAVE_SELINUX
static int _set_selinux_context(const char *path)
int set_selinux_context(const char *path)
{
security_context_t scontext;
@@ -226,11 +223,13 @@ static int _set_selinux_context(const char *path)
}
#endif
static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor)
static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
uid_t uid, gid_t gid, mode_t mode)
{
char path[PATH_MAX];
struct stat info;
dev_t dev = MKDEV(major, minor);
mode_t old_mask;
_build_dev_path(path, sizeof(path), dev_name);
@@ -241,6 +240,7 @@ static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor)
return 0;
}
/* If right inode already exists we don't touch uid etc. */
if (info.st_rdev == dev)
return 1;
@@ -251,12 +251,20 @@ static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor)
}
}
if (mknod(path, S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, dev) < 0) {
old_mask = umask(0);
if (mknod(path, S_IFBLK | mode, dev) < 0) {
log_error("Unable to make device node for '%s'", dev_name);
return 0;
}
umask(old_mask);
if (chown(path, uid, gid) < 0) {
log_error("%s: chown failed: %s", path, strerror(errno));
return 0;
}
#ifdef HAVE_SELINUX
if (!_set_selinux_context(path))
if (!set_selinux_context(path))
return 0;
#endif
@@ -324,11 +332,12 @@ typedef enum {
} node_op_t;
static int _do_node_op(node_op_t type, const char *dev_name, uint32_t major,
uint32_t minor, const char *old_name)
uint32_t minor, uid_t uid, gid_t gid, mode_t mode,
const char *old_name)
{
switch (type) {
case NODE_ADD:
return _add_dev_node(dev_name, major, minor);
return _add_dev_node(dev_name, major, minor, uid, gid, mode);
case NODE_DEL:
return _rm_dev_node(dev_name);
case NODE_RENAME:
@@ -346,6 +355,9 @@ struct node_op_parms {
char *dev_name;
uint32_t major;
uint32_t minor;
uid_t uid;
gid_t gid;
mode_t mode;
char *old_name;
char names[0];
};
@@ -358,7 +370,8 @@ static void _store_str(char **pos, char **ptr, const char *str)
}
static int _stack_node_op(node_op_t type, const char *dev_name, uint32_t major,
uint32_t minor, const char *old_name)
uint32_t minor, uid_t uid, gid_t gid, mode_t mode,
const char *old_name)
{
struct node_op_parms *nop;
size_t len = strlen(dev_name) + strlen(old_name) + 2;
@@ -373,6 +386,9 @@ static int _stack_node_op(node_op_t type, const char *dev_name, uint32_t major,
nop->type = type;
nop->major = major;
nop->minor = minor;
nop->uid = uid;
nop->gid = gid;
nop->mode = mode;
_store_str(&pos, &nop->dev_name, dev_name);
_store_str(&pos, &nop->old_name, old_name);
@@ -390,25 +406,27 @@ static void _pop_node_ops(void)
list_iterate_safe(noph, nopht, &_node_ops) {
nop = list_item(noph, struct node_op_parms);
_do_node_op(nop->type, nop->dev_name, nop->major, nop->minor,
nop->old_name);
nop->uid, nop->gid, nop->mode, nop->old_name);
list_del(&nop->list);
free(nop);
}
}
int add_dev_node(const char *dev_name, uint32_t major, uint32_t minor)
int add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
uid_t uid, gid_t gid, mode_t mode)
{
return _stack_node_op(NODE_ADD, dev_name, major, minor, "");
return _stack_node_op(NODE_ADD, dev_name, major, minor, uid, gid, mode,
"");
}
int rename_dev_node(const char *old_name, const char *new_name)
{
return _stack_node_op(NODE_RENAME, new_name, 0, 0, old_name);
return _stack_node_op(NODE_RENAME, new_name, 0, 0, 0, 0, 0, old_name);
}
int rm_dev_node(const char *dev_name)
{
return _stack_node_op(NODE_DEL, dev_name, 0, 0, "");
return _stack_node_op(NODE_DEL, dev_name, 0, 0, 0, 0, 0, "");
}
void update_devs(void)

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-2005 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
@@ -22,11 +22,14 @@ struct target *create_target(uint64_t start,
uint64_t len,
const char *type, const char *params);
int add_dev_node(const char *dev_name, uint32_t minor, uint32_t major);
int add_dev_node(const char *dev_name, uint32_t minor, uint32_t major,
uid_t uid, gid_t gid, mode_t mode);
int rm_dev_node(const char *dev_name);
int rename_dev_node(const char *old_name, const char *new_name);
void update_devs(void);
int set_selinux_context(const char *path);
#define DM_LIB_VERSION @DM_LIB_VERSION@
#endif

73
libdm/libdm-file.c Normal file
View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License v.2.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "libdm-file.h"
#include <sys/file.h>
#include <fcntl.h>
#include <dirent.h>
#include <malloc.h>
static int _create_dir_recursive(const char *dir)
{
char *orig, *s;
int rc;
log_verbose("Creating directory \"%s\"", dir);
/* Create parent directories */
orig = s = strdup(dir);
while ((s = strchr(s, '/')) != NULL) {
*s = '\0';
if (*orig) {
rc = mkdir(orig, 0777);
if (rc < 0 && errno != EEXIST) {
log_error("%s: mkdir failed: %s", orig,
strerror(errno));
free(orig);
return 0;
}
}
*s++ = '/';
}
free(orig);
/* Create final directory */
rc = mkdir(dir, 0777);
if (rc < 0 && errno != EEXIST) {
log_error("%s: mkdir failed: %s", orig,
strerror(errno));
return 0;
}
return 1;
}
int create_dir(const char *dir)
{
struct stat info;
if (!*dir)
return 1;
if (stat(dir, &info) < 0)
return _create_dir_recursive(dir);
if (S_ISDIR(info.st_mode))
return 1;
log_error("Directory \"%s\" not found", dir);
return 0;
}

25
libdm/libdm-file.h Normal file
View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU 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
*/
#ifndef LIB_DMFILE_H
#define LIB_DMFILE_H
/*
* Create directory (recursively) if necessary. Return 1
* if directory was successfully created (or already exists), else 0.
*/
int create_dir(const char *dir);
#endif

View File

@@ -30,7 +30,7 @@ MAN8DIR=${mandir}/man8
include $(top_srcdir)/make.tmpl
ifeq ("@CLVMD@", "yes")
ifneq ("@CLVMD@", "none")
install: install_cluster
endif

View File

@@ -4,26 +4,34 @@ lvchange \- change attributes of a logical volume
.SH SYNOPSIS
.B lvchange
[\-\-addtag Tag]
[\-A/\-\-autobackup y/n] [\-a/\-\-available y/n]
[\-A/\-\-autobackup y/n] [\-a/\-\-available y/n/ey/en/ly/ln]
[\-\-alloc AllocationPolicy]
[\-C/\-\-contiguous y/n] [\-d/\-\-debug] [\-\-deltag Tag]
[\-h/\-?/\-\-help]
[\-\-ignorelockingfailure]
[\-M/\-\-persistent y/n] [\-\-minor minor]
[\-P/\-\-partial y/n]
[\-p/\-\-permission r/w] [\-r/\-\-readahead ReadAheadSectors]
[\-\-refresh]
[\-t/\-\-test]
[\-v/\-\-verbose] LogicalVolumePath [LogicalVolumePath...]
.SH DESCRIPTION
lvchange allows you to change the attributes of a logical volume.
lvchange allows you to change the attributes of a logical volume
including making them known to the kernel ready for use.
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
.I \-a, \-\-available y/n
.I \-a, \-\-available y/n/ey/en/ly/ln
Controls the availability of the logical volumes for use.
This is (among others) useful for changing the logical volume's name
( see
.B lvrename(8)
) safely.
Communicates with the kernel device-mapper driver via
libdevmapper to activate (-ay) or deactivate (-an) the
logical volumes.
.IP
If clustered locking is enabled, -ae will activate exclusively
on one node and -aly will activate only on the local node.
To deactivate only on the local node use -aln.
Logical volumes with single-host snapshots are always activated
exclusively because they can only be used on one node at once.
.TP
.I \-C, \-\-contiguous y/n
Tries to set or reset the contiguous allocation policy for
@@ -42,11 +50,18 @@ Change access permission to read-only or read/write.
.TP
.I \-r, \-\-readahead ReadAheadSectors
Change read ahead sector count per logical between 2 and 120.
Not used by device-mapper.
For compatability with LVM1 only. Ignored by LVM2.
.TP
.I \-\-refresh
If the logical volume is active, reload its metadata.
This is not necessary in normal operation, but may be useful
if something has gone wrong or if you're doing clustering
manually without a clustered lock manager.
.SH Examples
"lvchange -p r vg00/lvol1" changes the permission on
"lvchange -pr vg00/lvol1" changes the permission on
volume lvol1 in volume group vg00 to be read-only.
.SH SEE ALSO
.BR lvm (8),
.BR lvcreate (8)
.BR lvcreate (8),
.BR vgchange (8)

View File

@@ -4,6 +4,7 @@ lvcreate \- create a logical volume in an existing volume group
.SH SYNOPSIS
.B lvcreate
[\-\-addtag Tag]
[\-\-alloc AllocationPolicy]
[\-A/\-\-autobackup y/n] [\-C/\-\-contiguous y/n] [\-d/\-\-debug]
[\-h/\-?/\-\-help]
[\-i/\-\-stripes Stripes [\-I/\-\-stripesize StripeSize]]

View File

@@ -10,12 +10,15 @@ lvdisplay \- display attributes of a logical volume
.SH DESCRIPTION
lvdisplay allows you to see the attributes of a logical volume
like size, read/write status, snapshot information etc.
.P
\fBlvs\fP (8) is an alternative that provides the same information
in the style of \fBps\fP (1).
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
.I \-c, \-\-colon
Deprecated. To be replaced with a more-powerful reporting tool.
Generate colon separated output for easier parsing in scripts or programs.
N.B. \fBlvs\fP (8) provides considerably more control over the output.
.nf
The values are:

View File

@@ -3,6 +3,7 @@
lvextend \- extend the size of a logical volume
.SH SYNOPSIS
.B lvextend
[\-\-alloc AllocationPolicy]
[\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help]
[\-i/\-\-stripes Stripes [\-I/\-\-stripesize StripeSize]]
{\-l/\-\-extents [+]LogicalExtentsNumber |

View File

@@ -18,23 +18,44 @@ If \fBlvm\fP is invoked with argv[0] set to the name of a specific
LVM command (for example by using a hard or soft link) it acts as
that command.
.LP
Where commands take VG or LV names as arguments, the full path name is
optional. An LV called "lvol0" in a VG called "vg0" can be specified
as "vg0/lvol0". Where a list of VGs is required but is left empty,
a list of all VGs will be substituted. Where a list of LVs is required
but a VG is given, a list of all the LVs in that VG will be substituted.
So "lvdisplay vg0" will display all the LVs in "vg0".
Tags can also be used - see \fBaddtag\fP below.
.LP
One advantage of using the built-in shell is that configuration
information is cached internally between commands.
information gets cached internally between commands.
.LP
A file containing a simple script with one command per line
can also be given on the command line. The script can also be
executed directly if the first line is #! followed by the absolute
path of \fBlvm\fP.
.SH BUILT-IN COMMANDS
The following commands are built into lvm without links normally
being created in the filesystem for them.
.TP
\fBdumpconfig\fP \(em Display the configuration information after
loading \fBlvm.conf\fP (8) and any other configuration files.
.TP
\fBformats\fP \(em Display recognised metadata formats.
.TP
\fBhelp\fP \(em Display the help text.
.TP
\fBpvdata\fP \(em Not implemented in LVM2.
.TP
\fBsegtypes\fP \(em Display recognised logical volume segment types.
.TP
\fBversion\fP \(em Display version information.
.LP
Where commands take VG or LV names as arguments, the full path name is
optional. An LV called "lvol0" in a VG called "vg0" can be specified
as "vg0/lvol0". If a list of VGs is required but is left empty, a list of
all VGs will be substituted. If a list of LVs is required
but a VG is given, a list of all the LVs in that VG will be substituted.
So "lvdisplay vg0" will display all the LVs in "vg0".
The following commands are not implemented in LVM2 but might be
in future: lvmsadc, lvmsar, pvdata, pvresize.
.SH OPTIONS
The following options are available for many of the commands and are
not documented on individual manual pages.
The following options are available for many of the commands.
They are implemented generically and documented here rather
than repeated on individual manual pages.
.TP
\fB-h | --help\fP \(em Display the help text.
.TP
@@ -54,6 +75,10 @@ Overrides -d and -v.
.TP
\fB-t | --test\fP \(em Run in test mode.
Commands will not update metadata.
This is implemented by disabling all metadata writing but nevertheless
returning success to the calling function. This may lead to unusual
error messages in multi-stage operations if a tool relies on reading
back metadata it believes has changed but hasn't.
.TP
\fB--driverloaded\fP { \fBy\fP | \fBn\fP }
Whether or not the device-mapper kernel driver is loaded.
@@ -109,6 +134,27 @@ Characters allowed in tags are: A-Z a-z 0-9 _ + . -
.TP
\fB--deltag tag\fP
Delete the tag \fBtag\fP from a PV, VG or LV, if it's present.
.TP
\fB--alloc AllocationPolicy\fP
The allocation policy to use: \fBcontiguous\fP, \fBnormal\fP, \fBanywhere\fP or \fBinherit\fP.
When a command needs to allocate physical extents from the volume group,
the allocation policy controls how they are chosen.
Each volume group and logical volume has an allocation policy.
The default for a volume group is \fBnormal\fP which applies
common-sense rules such as not placing parallel stripes on the same
physical volume. The default for a logical volume is \fBinherit\fP
which applies the same policy as for the volume group. These policies can
be changed using \fBlvchange\fP (8) and \fBvgchange\fP (8) or over-ridden
on the command line of any command that performs allocation.
The \fBcontiguous\fP policy requires that new extents are adjacent to
existing extents. If there are sufficient free extents to satisfy
an allocation request but \fBnormal\fP doesn't use them,
\fBanywhere\fP will - even if that reduces performance by
placing two stripes on the same physical volume.
.IP
N.B. The policies described above are not implemented fully yet.
In particular, \fBcontiguous\fP does not place new extents adjacent to existing
extents and \fBanywhere\fP is not implemented at all.
.SH ENVIRONMENT VARIABLES
.TP
\fBLVM_SYSTEM_DIR\fP
@@ -131,31 +177,42 @@ All tools return a status code of zero on success or non-zero on failure.
.br
.I $HOME/.lvm_history
.SH SEE ALSO
.BR clvmd (8),
.BR lvchange (8),
.BR lvcreate (8),
.BR lvdisplay (8),
.BR lvextend (8),
.BR lvmchange (8),
.BR lvmdiskscan (8),
.BR lvreduce (8),
.BR lvremove (8),
.BR lvrename (8),
.BR lvresize (8),
.BR lvs (8),
.BR lvscan (8),
.BR pvchange (8),
.BR pvcreate (8),
.BR pvdisplay (8),
.BR pvmove (8),
.BR pvremove (8),
.BR pvs (8),
.BR pvscan (8),
.BR vgcfgbackup (8),
.BR vgchange (8),
.BR vgck (8),
.BR vgconvert (8),
.BR vgcreate (8),
.BR vgdisplay (8),
.BR vgextend (8),
.BR vgimport (8),
.BR vgmerge (8),
.BR vgmknodes (8),
.BR vgreduce (8),
.BR vgremove (8),
.BR vgrename (8),
.BR vgs (8),
.BR vgscan (8),
.BR vgsplit (8),
.BR readline (3),
.BR lvm.conf (5)

View File

@@ -4,9 +4,13 @@ lvm.conf \- Configuration file for LVM2
.SH SYNOPSIS
.B /etc/lvm/lvm.conf
.SH DESCRIPTION
lvm.conf is loaded once, during the initialisation phase of
\fBlvm\fP.
lvm.conf is loaded during the initialisation phase of
\fBlvm\fP (8). This file can in turn lead to other files
being loaded - settings read in later override earlier
settings. File timestamps are checked between commands and if
any have changed, all the files are reloaded.
.LP
Use \fBlvm dumpconfig\fP to check what settings are in use.
.SH SYNTAX
.LP
This section describes the configuration file syntax.
@@ -69,7 +73,8 @@ The sections that may be present in the file are:
\fBdevices\fP \(em Device settings
.IP
\fBdir\fP \(em Directory in which to create volume group device nodes.
Defaults to "/dev".
Defaults to "/dev". Commands also accept this as a prefix on volume
group names.
.IP
\fBscan\fP \(em List of directories to scan recursively for
LVM physical volumes.
@@ -81,8 +86,13 @@ Patterns are regular expressions delimited by any character and preceded
by \fBa\fP (for accept) or \fBr\fP (for reject). The list is traversed
in order, and the first regex that matches determines if the device
will be accepted or rejected (ignored). Devices that don't match
any patterns are accepted.
For example, to ignore /dev/cdrom you could use:
any patterns are accepted. If you want to reject patterns that
don't match, end the list with "r/.*/".
If there are several names for the same device (e.g. symbolic links
in /dev), if any name matches any \fBa\fP pattern, the
device is accepted; otherwise if any name matches any \fBr\fP
pattern it is rejected; otherwise it is accepted.
As an example, to ignore /dev/cdrom you could use:
\fBdevices { filter=["r|cdrom|"] }\fP
.IP
\fBcache\fP \(em Persistent filter cache file.
@@ -95,9 +105,24 @@ Defaults to 1.
\fBtypes\fP \(em List of pairs of additional acceptable block device types
found in /proc/devices together with maximum (non-zero) number of
partitions (normally 16). By default, LVM2 supports ide, sd, md, loop,
dasd, dac960, nbd, ida, cciss, ubd and ataraid. Block devices with major
numbers of different types are ignored by LVM2. Example:
\fBtypes = ["fd", 16]\fP
dasd, dac960, nbd, ida, cciss, ubd, ataraid, drbd, power2, i2o_block
and iseries/vd. Block devices with major
numbers of different types are ignored by LVM2.
Example: \fBtypes = ["fd", 16]\fP.
To create physical volumes on device-mapper volumes
created outside LVM2, perhaps encrypted ones from \fBcryptsetup\fP,
you'll need \fBtypes = ["device-mapper", 16]\fP. But if you do this,
be careful to avoid recursion within LVM2. The figure for number
of partitions is not currently used in LVM2 - and might never be.
.IP
\fBsysfs_scan\fP (em If set to 1 and your kernel supports sysfs and
it is mounted, sysfs will be used as a quick way of filtering out
block devices that are not present.
.IP
\fBmd_component_detection\fP (em If set to 1, LVM2 will ignore devices
used as components of software RAID (md) devices by looking for md
superblocks. This doesn't always work satisfactorily e.g. if a device
has been reused without wiping the md superblocks first.
.TP
\fBlog\fP \(em Default log settings
.IP
@@ -120,7 +145,8 @@ See /usr/include/sys/syslog.h for safe facility values to use.
For example, LOG_LOCAL0 might be 128.
.IP
\fBindent\fP \(em When set to 1 (the default) messages are indented
according to their severity. Set to 0 to turn off indentation.
according to their severity, two spaces per level.
Set to 0 to turn off indentation.
.IP
\fBcommand_names\fP \(em When set to 1, the command name is used as a
prefix for each message.
@@ -128,6 +154,11 @@ Default is 0 (off).
.IP
\fBprefix\fP \(em Prefix used for all messages (after the command name).
Default is two spaces.
.IP
\fBactivation\fP \(em Set to 1 to log messages while
devices are suspended during activation.
Only set this temporarily while debugging a problem because
in low memory situations this setting can cause your machine to lock up.
.TP
\fBbackup\fP \(em Configuration for metadata backups.
.IP
@@ -165,8 +196,13 @@ Defaults to 30.
.TP
\fBglobal\fP \(em Global settings
.IP
\fBtest\fP \(em If set to 1, run tools in test mode i.e. no metadata
gets updated.
\fBtest\fP \(em If set to 1, run tools in test mode i.e. no changes to
the on-disk metadata will get made. It's equivalent to having the
-t option on every command.
.IP
\fBactivation\fP \(em Set to 0 to turn off all communication with
the device-mapper driver. Useful if you want to manipulate logical
volumes while device-mapper is not present in your kernel.
.IP
\fBproc\fP \(em Mount point of proc filesystem.
Defaults to /proc.
@@ -175,12 +211,167 @@ Defaults to /proc.
Interpreted as octal if the first digit is zero.
Defaults to 077.
Use 022 to allow other users to read the files by default.
.IP
\fBformat\fP \(em The default value of \fB--metadatatype\fP used
to determine which format of metadata to use when creating new
physical volumes and volume groups. \fBlvm1\fP or \fBlvm2\fP.
.IP
\fBfallback_to_lvm1\fP \(em Set this to 1 if you need to
be able to switch between 2.4 kernels using LVM1 and kernels
including device-mapper.
The LVM2 tools should be installed as normal and
the LVM1 tools should be installed with a .lvm1 suffix e.g.
vgscan.lvm1.
If an LVM2 tool is then run but unable to communicate
with device-mapper, it will automatically invoke the equivalent LVM1
version of the tool. Note that for LVM1 tools to
manipulate physical volumes and volume groups created by LVM2 you
must use \fB--metadataformat lvm1\fP when creating them.
.IP
\fBlibrary_dir\fP \(em A directory searched for LVM2's shared libraries
ahead of the places \fBdlopen\fP (3) searches.
.IP
\fBformat_libraries\fP \(em A list of shared libraries to load that contain
code to process different formats of metadata. For example, liblvm2formatpool.so
is needed to read GFS pool metadata if LVM2 was configured \fB--with-pool=shared\fP.
.IP
\fBlocking_type\fP \(em What type of locking to use.
1 is the default, which use flocks on files in \fBlocking_dir\fP
(see below) to
avoid conflicting LVM2 commands running concurrently on a single
machine. 0 disables locking and risks corrupting your metadata.
If set to 2, the tools will load the external \fBlocking_library\fP
(see below).
If the tools were configured \fB--with-cluster=internal\fP
(the default) then 3 means to use built-in cluster-wide locking.
All changes to logical volumes and their states are communicated
using locks.
.IP
\fBlocking_dir\fP \(em The directory LVM2 places its file locks
if \fBlocking_type\fP is set to 1. The default is \fB/var/lock/lvm\fP.
.IP
\fBlocking_library\fP \(em The name of the external locking
library to load if \fBlocking_type\fP is set to 2.
The default is \fBlvm2_locking.so\fP. If you need to write
such a library, look at the lib/locking source code directory.
.TP
\fBtags\fP \(em Host tag settings
.IP
\fBhosttags\fP \(em If set to 1, create a host tag with the machine name.
Setting this to 0 does nothing, neither creating nor destroying any tag.
The machine name used is the nodename as returned by \fBuname\fP (2).
.IP
Additional host tags to be set can be listed here as subsections.
The @ prefix for tags is optional.
Each of these host tag subsections can contain a \fBhost_list\fP
array of host names. If any one of these entries matches the machine
name exactly then the host tag gets defined on this particular host,
otherwise it doesn't.
.IP
After lvm.conf has been processed, LVM2 works through each host
tag that has been defined in turn, and if there is a configuration
file called lvm_\fB<host_tag>\fP.conf it attempts to load it.
Any settings read in override settings found in earlier files.
Any additional host tags defined get appended to the search list,
so in turn they can lead to further configuration files being processed.
Use \fBlvm dumpconfig\fP to check the result of config
file processing.
.IP
The following example always sets host tags \fBtag1\fP and
sets \fBtag2\fP on machines fs1 and fs2:
.IP
tags { tag1 { } tag2 { host_list = [ "fs1", "fs2" ] } }
.IP
These options are useful if you are replicating configuration files
around a cluster. Use of \fBhosttags = 1\fP means every machine
can have static and identical local configuration files yet use
different settings and activate different logical volumes by
default. See also \fBvolume_list\fP below and \fB--addtag\fP
in \fBlvm\fP (8).
.TP
\fBactivation\fP \(em Settings affecting device-mapper activation
.IP
\fBmissing_stripe_filler\fP \(em When activating an incomplete
logical volume in partial mode, this missing data is replaced
with this device. It could perhaps be a block device that always
returns an error when it is accessed, or one that always
returns zeros. See \fBlvcreate\fP (8) for how to create
such devices.
.IP
\fBmirror_region_size\fP \(em Unit size in KB for copy operations
when mirroring.
.IP
\fBreserved_memory\fP, \fBreserved_stack\fP \(em How many KB to reserve
for LVM2 to use while logical volumes are suspended. If insufficient
memory is reserved before suspension, there is a risk of machine deadlock.
.IP
\fBprocess_priority\fP \(em The nice value to use while devices are
suspended. This is set to a high priority so that logical volumes
are suspended (with I/O generated by other processes to those
logical volumes getting queued) for the shortest possible time.
.IP
\fBvolume_list\fP \(em This acts as a filter through which
all requests to activate a logical volume on this machine
are passed. A logical volume is only activated if it matches
an item in the list. Tags must be preceded by @ and are checked
against all tags defined in the logical volume and volume group
metadata for a match.
@* is short-hand to check every tag set on the host machine (see
\fBtags\fP above).
Logical volume and volume groups can also be included in the list
by name e.g. vg00, vg00/lvol1.
.TP
\fBmetadata\fP \(em Advanced metadata settings
.IP
\fBpvmetadatacopies\fP \(em When creating a physical volume using the
LVM2 metadata format, this is the default number of copies of metadata
to store on each physical volume.
Currently it can be set to 0, 1 or 2. The default is 1.
If set to 2, one copy is placed at the beginning of the disk
and the other is placed at the end.
It can be overridden on the command line with \fB--metadatacopies\fP.
If creating a volume group with just one physical volume, it's a
good idea to have 2 copies. If creating a large volume group with
many physical volumes, you may decide that 3 copies of the metadata
is sufficient, i.e. setting it to 1 on three of the physical volumes,
and 0 on the rest. Every volume group must contain at least one
physical volume with at least 1 copy of the metadata (unless using
the text files described below). The disadvantage of having lots
of copies is that every time the tools access the volume group, every
copy of the metadata has to be accessed, and this slows down the
tools.
.IP
\fBpvmetadatasize\fP \(em Approximate number of sectors to set aside
for each copy of the metadata. Volume groups with large numbers of
physical or logical volumes, or volumes groups containing complex
logical volume structures will need additional space for their metadata.
The metadata areas are treated as circular buffers, so
unused space becomes filled with an archive of the most recent
previous versions of the metadata.
.IP
\fBdirs\fP \(em List of directories holding live copies of LVM2
metadata as text files. These directories must not be on logical
volumes. It is possible to use LVM2 with a couple of directories
here, preferably on different (non-logical-volume) filesystems
and with no other on-disk metadata, \fBpvmetadatacopies = 0\fP.
Alternatively these directories can be in addition to the
on-disk metadata areas. This feature was created during the
development of the LVM2 metadata before the new on-disk metadata
areas were designed and no longer gets tested.
It is not supported under low-memory conditions, and it is
important never to edit these metadata files unless you fully
understand how things work: to make changes you should always use
the tools as normal, or else vgcfgbackup, edit backup, vgcfgrestore.
.SH FILES
.I /etc/lvm/lvm.conf
.br
.I $HOME/.lvm_history
.I /etc/lvm/.cache
.I /etc/lvm/archive
.I /etc/lvm/backup
.I /var/lock/lvm
.SH SEE ALSO
.BR lvm (8)
.BR umask (2)
.BR syslog (3)
.BR lvm (8),
.BR umask (2),
.BR uname (2),
.BR dlopen (3),
.BR syslog (3),
.BR syslog.conf (5)

View File

@@ -15,12 +15,16 @@ reduced part is lost!!!
.br
You should therefore ensure that any filesystem on the volume is
resized
.i before
.I before
running lvreduce so that the extents that are to be removed are not in use.
.br.
.br
Shrinking snapshot logical volumes (see
.B lvcreate(8)
for information to create snapshots) is supported as well.
.br
Sizes will be rounded if necessary - for example, the volume size must
be an exact number of extents and the size of a striped segment must
be a multiple of the number of stripes.
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
@@ -41,11 +45,12 @@ 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.
.SH Example
"lvreduce -l -3 /dev/vg00/lvol1" reduces the size of logical volume lvol1
"lvreduce -l -3 vg00/lvol1" reduces the size of logical volume lvol1
in volume group vg00 by 3 logical extents.
.SH SEE ALSO
.BR lvm (8),
.BR lvchange (8),
.BR lvcreate (8),
.BR lvextend (8),
.BR lvresize (8),
.BR lvchange (8)
.BR lvm (8),
.BR lvresize (8),
.BR vgreduce (8)

View File

@@ -8,17 +8,28 @@ lvremove \- remove a logical volume
[\-t/\-\-test]
[\-v/\-\-verbose] LogicalVolumePath [LogicalVolumePath...]
.SH DESCRIPTION
lvremove allows you to remove one or more inactive logical volumes.
\fBlvremove\fP removes one or more logical volumes.
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).
.SH OPTIONS
See \fBlvm\fP for common options.
See \fBlvm\fP(8) for common options.
.TP
.I \-f, \-\-force
Force remove without confirmation.
.SH Example
"lvremove -f /dev/vg00/lvol1" removes that inactive logical volume
unconditionally.
Remove active logical volumes without confirmation.
.SH EXAMPLES
Remove the active logical volume lvol1 in volume group vg00
without asking for confirmation:
.sp
\ \fBlvremove -f vg00/lvol1\fP
.sp
Remove all logical volumes in volume group vg00:
.sp
\ \fBlvremove vg00\fP
.SH SEE ALSO
.BR lvm (8),
.BR lvcreate (8),
.BR lvdisplay (8),
.BR lvscan (8)
.BR lvm (8),
.BR lvs (8),
.BR lvscan (8),
.BR vgremove (8)

View File

@@ -3,6 +3,7 @@
lvresize \- resize a logical volume
.SH SYNOPSIS
.B lvresize
[\-\-alloc AllocationPolicy]
[\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help]
[\-i/\-\-stripes Stripes [\-I/\-\-stripesize StripeSize]]
{\-l/\-\-extents [+]LogicalExtentsNumber |
@@ -27,7 +28,7 @@ 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
.I \-L, \-\-size [+/-]LogicalVolumeSize[kKmMgGtT]
Change or set the logical volume size in units in units of megabytes.
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
the actual size of the logical volume and without it, the value is taken as an

View File

@@ -13,7 +13,7 @@ lvs \- report information about logical volumes
[\-v/\-\-verbose]
[\-\-version] [VolumeGroupName [VolumeGroupName...]]
.SH DESCRIPTION
vgs produces formatted output about volume groups
lvs produces formatted output about logical volumes.
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
@@ -30,16 +30,35 @@ if processing the output.
.TP
.I \-o, \-\-options
Comma-separated ordered list of columns. Precede the list with '+' to append
to the default selection of columns. Column names are:
lv_uuid, lv_name, lv_attr, lv_minor, lv_size, seg_count, origin,
snap_percent (suppressed if no kernel driver), segtype, stripes,
stripesize, chunksize, seg_start, seg_size.
to the default selection of columns instead of replacing it. Column names are:
lv_uuid, lv_name, lv_attr, lv_major, lv_minor, lv_kernel_major, lv_kernel_minor,
lv_size, seg_count, origin, snap_percent,
copy_percent, move_pv, lv_tags,
segtype, stripes,
stripesize, chunksize, seg_start, seg_size, seg_tags, devices.
.IP
With \-\-segments, any "seg_" prefixes are optional; otherwise any "lv_"
prefixes are optional. Columns mentioned in \fBvgs (8)\fP
can also be chosen
The lv_attr bits are: (o)rigin, (s)napshot, (w)riteable, (r)eadonly,
(c)ontiguous allocation, (n)ext free allocation, fixed (m)inor, (s)uspended,
(a)ctive, device (o)pen.
can also be chosen.
.IP
The lv_attr bits are:
.RS
.IP 1 3
Volume type: (m)irrored, (o)rigin, (p)vmove, (s)napshot,
invalid (S)napshot, (v)irtual
.IP 2 3
Permissions: (w)riteable, (r)ead-only
.IP 3 3
Allocation policy: (c)ontiguous, (n)ormal, (a)nywhere, (i)nherited
This is capitalised if the volume is currently locked against allocation
changes, for example during \fBpvmove\fP (8).
.IP 4 3
fixed (m)inor
.IP 5 3
State: (a)ctive, (s)uspended, (I)nvalid snapshot, invalid (S)uspended snapshot
.IP 6 3
device (o)pen
.RE
.TP
.I \-\-segments
Use default columns that emphasize segment information.
@@ -60,5 +79,6 @@ All sizes are output in these units: (h)uman-readable, (s)ectors, (b)ytes,
of 1000 (S.I.) instead of 1024. Can also specify custom (u)nits e.g.
\-\-units 3M
.SH SEE ALSO
.BR lvdisplay (8),
.BR pvs (8),
.BR vgs (8)

View File

@@ -16,6 +16,7 @@ pvcreate \- initialize a disk or partition for use by LVM
.RB [ \-\-restorefile file ]
.RB [ \-\-setphysicalvolumesize size ]
.RB [ \-\-version ]
.RB [ \-Z | \-\-zero y/n ]
.IR PhysicalVolume " [" PhysicalVolume ...]
.SH DESCRIPTION
.B pvcreate
@@ -59,6 +60,13 @@ onto a replacement device - see \fBvgcfgrestore\fP(8).
.TP
.BR \-y ", " \-\-yes
Answer yes to all questions.
.TP
.BR \-Z ", " \-\-zero " y/n"
Whether or not the first 4 sectors (2048 bytes) of the device should be
wiped.
If this option is not given, the
default is to wipe these sectors unless either or both of the --restorefile
or --uuid options were specified.
.SH NEW METADATA OPTIONS
LVM2 introduces a new format for storing metadata on disk.
This new format is more efficient and resilient than the format the

View File

@@ -10,11 +10,15 @@ PhysicalVolumePath [PhysicalVolumePath...]
pvdisplay allows you to see the attributes of one or more physical volumes
like size, physical extent size, space used for the volume group descriptor
area and so on.
.P
\fBpvs\fP (8) is an alternative that provides the same information
in the style of \fBps\fP (1).
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
.I \-c, \-\-colon
Generate colon separated output for easier parsing in scripts or programs.
N.B. \fBpvs\fP (8) provides considerably more control over the output.
.nf
The values are:

View File

@@ -3,7 +3,9 @@
pvmove \- move physical extents
.SH SYNOPSIS
.B pvmove
[\-\-abort] [\-\-background]
[\-\-abort]
[\-\-alloc AllocationPolicy]
[\-\-background]
[\-d/\-\-debug] [\-h/\-\-help] [\-i/\-\-interval Seconds] [\-v/\-\-verbose]
[\-n/\-\-name LogicalVolume]
[SourcePhysicalVolume[:PE[-PE]...] [DestinationPhysicalVolume[:PE[-PE]...]...]]

View File

@@ -12,7 +12,7 @@ pvs \- report information about physical volumes
[\-v/\-\-verbose]
[\-\-version] [PhysicalVolume [PhysicalVolume...]]
.SH DESCRIPTION
pvs produces formatted output about physical volumes
pvs produces formatted output about physical volumes.
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
@@ -30,7 +30,8 @@ if processing the output.
.I \-o, \-\-options
Comma-separated ordered list of columns. Precede the list with '+' to append
to the default selection of columns. Column names are: pv_fmt, pv_uuid,
pv_size, pv_free, pv_used, pv_name, pv_attr, pv_pe_count, pv_pe_alloc_count.
pv_size, dev_size, pv_free, pv_used, pv_name, pv_attr, pv_pe_count,
pv_pe_alloc_count, pv_tags.
The "pv_" prefix is optional. Columns mentioned in \fBvgs (8)\fP can also
be chosen. The pv_attr bits are: (a)llocatable and e(x)ported.
.TP
@@ -50,5 +51,6 @@ All sizes are output in these units: (h)uman-readable, (s)ectors, (b)ytes,
of 1000 (S.I.) instead of 1024. Can also specify custom (u)nits e.g.
\-\-units 3M
.SH SEE ALSO
.BR pvdisplay (8),
.BR lvs (8),
.BR vgs (8)

View File

@@ -3,22 +3,24 @@
vgchange \- change attributes of a volume group
.SH SYNOPSIS
.B vgchange
.RB [\-\-addtag
.RB [ \-\-addtag
.IR Tag ]
.RB [\-A | \-\-autobackup " {" y | n }]
.RB [\-a | \-\-available " {" y | n }]
.RB [\-d | \-\-debug]
.RB [\-\-deltag
.RB [ \-\-alloc
.IR AllocationPolicy ]
.RB [ \-A | \-\-autobackup " {" y | n }]
.RB [ \-a | \-\-available " [e|l] {" y | n }]
.RB [ \-d | \-\-debug]
.RB [ \-\-deltag
.IR Tag ]
.RB [\-h | \-\-help]
.RB [\-\-ignorelockingfailure]
.RB [\-l | \-\-logicalvolume
.RB [ \-h | \-\-help]
.RB [ \-\-ignorelockingfailure]
.RB [ \-l | \-\-logicalvolume
.IR MaxLogicalVolumes ]
.RB [\-P | \-\-partial]
.RB [-t | \-\-test]
.RB [\-v | \-\-verbose]
.RB [\-\-version ]
.RB [\-x | \-\-resizeable " {" y | n }]
.RB [ \-P | \-\-partial]
.RB [ -t | \-\-test]
.RB [ \-v | \-\-verbose]
.RB [ \-\-version ]
.RB [ \-x | \-\-resizeable " {" y | n }]
.RI [ VolumeGroupName ...]
.SH DESCRIPTION
.B vgchange
@@ -42,9 +44,16 @@ Controls automatic backup of metadata after the change. See
.B vgcfgbackup (8).
Default is yes.
.TP
.BR \-a ", " \-\-available { y | n }
Controls the availability of the volume group for input/output.
In other words: makes a volume group known/unknown to the kernel.
.BR \-a ", " \-\-available [e|l] { y | n }
Controls the availability of the logical volumes in the volume
group for input/output.
In other words, makes the logical volumes known/unknown to the kernel.
.IP
If clustered locking is enabled, add 'e' to activate/deactivate
exclusively on one node or 'l' to activate/deactivate only
on the local node.
Logical volumes with single-host snapshots are always activated
exclusively because they can only be used on one node at once.
.TP
.BR \-l ", " \-\-logicalvolume " " \fIMaxLogicalVolumes\fR
Changes the maximum logical volume number of an existing inactive
@@ -69,5 +78,6 @@ to 128.
.fi
.SH SEE ALSO
.BR lvchange (8),
.BR lvm (8),
.BR vgcreate (8)

View File

@@ -5,6 +5,8 @@ vgcreate \- create a volume group
.B vgcreate
.RB [ \-\-addtag
.IR Tag ]
.RB [ \-\-alloc
.IR AllocationPolicy ]
.RB [ \-A | \-\-autobackup " {" y | n }]
.RB [ \-d | \-\-debug ]
.RB [ \-h | \-\-help ]
@@ -31,45 +33,55 @@ previously configured for LVM with
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
.BR \-A ", " \-\-autobackup " {" y | n }
Controls automatic backup of VG metadata after the change (see
.BR vgcfgbackup (8)).
Default is yes.
.TP
.BR \-l ", " \-\-maxlogicalvolumes " " \fIMaxLogicalVolumes\fR
Sets the maximum possible logical volume count.
More logical volumes can't be created in this volume group.
Absolute maximum is 256.
Sets the maximum number of logical volumes allowed in this
volume group.
The setting can be changed with \fBvgchange\fP.
For volume groups with metadata in lvm1 format, the limit
and default value is 255.
If the metadata uses lvm2 format, the default value is 0
which removes this restriction: there is then no limit.
.TP
.BR \-p ", " \-\-maxphysicalvolumes " " \fIMaxPhysicalVolumes\fR
Sets the maximum possible physical volume count.
More physical volumes can't be included in this volume group.
Absolute maximum is 256.
Sets the maximum number of physical volumes that can belong
to this volume group.
The setting can be changed with \fBvgchange\fP.
For volume groups with metadata in lvm1 format, the limit
and default value is 255.
If the metadata uses lvm2 format, the default value is 0
which removes this restriction: there is then no limit.
If you have a large number of physical volumes in
a volume group with metadata in lvm2 format,
for tool performance reasons, you should consider
some use of \fB--metadatacopies 0\fP
as described in \fBpvcreate(8)\fP.
.TP
.BR \-s ", " \-\-physicalextentsize " " \fIPhysicalExtentSize\fR[\fBkKmMgGtT\fR]
Sets the physical extent size on physical volumes of this volume group.
A size suffix (k for kilobytes up to t for terabytes) is optional, megabytes
is the default if no suffix is present. Values can be from 8 KB to 16 GB in
powers of 2. The default of 4 MB causes maximum LV sizes of ~256GB because as
many as ~64k extents are supported per LV. In case larger maximum LV sizes are
needed (later), you need to set the PE size to a larger value as well. Later
changes of the PE size in an existing VG are not supported.
powers of 2. The default is 4 MB.
Once this value has been set, it is difficult to change it without recreating
the volume group which would involve backing up and restoring data on any
logical volumes.
If the volume group metadata uses lvm1 format, there is a limit of 65534
extents in each logical volume, so the default of 4 MB leads to a maximum
logical volume size of around 256GB.
If the volume group metadata uses lvm2 format there is no such restriction,
although having a large number of extents will slow down
the tools but have no impact on I/O performance to the logical volume.
The 2.4 kernel has a limitation of 2TB per block device.
.SH EXAMPLES
To create a volume group named
.B test_vg
using physical volumes
.BR /dev/hdk1 ", " /dev/hdl1 ", and " /dev/hdm1
.BR /dev/hdk1 ", and " /dev/hdl1
with default physical extent size of 4MB:
.nf
\ vgcreate test_vg /dev/sd[k-m]1
\ vgcreate test_vg /dev/sdk1 /dev/sdl1
.fi
To limit kernel memory usage, there is a limit of 65536 physical extents
(PE) per logical volume, so the PE size determines the maximum logical volume
size. The default PE size of 4MB limits a single logical volume to 256GB (see
the -s option to raise that limit).
There is also (as of Linux 2.4) a kernel limitation of 2TB per block device.
.SH SEE ALSO
.BR lvm (8),
.BR pvdisplay (8),

View File

@@ -19,6 +19,9 @@ allows you to see the attributes of
.I VolumeGroupName
(or all volume groups if none is given) with it's physical and logical
volumes and their sizes etc.
.P
\fBvgs\fP (8) is an alternative that provides the same information
in the style of \fBps\fP (1).
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
@@ -27,6 +30,7 @@ Only select the active volume groups.
.TP
.BR \-c ", " \-\-colon
Generate colon separated output for easier parsing in scripts or programs.
N.B. \fBvgs\fP (8) provides considerably more control over the output.
.nf
The values are:
@@ -63,6 +67,7 @@ information of vgdisplay's activities.
Display version and exit successfully.
.SH SEE ALSO
.BR lvm (8),
.BR vgs (8),
.BR pvcreate (8),
.BR vgcreate (8),
.BR lvcreate (8)

View File

@@ -7,13 +7,15 @@ vgremove \- remove a volume group
VolumeGroupName [VolumeGroupName...]
.SH DESCRIPTION
vgremove allows you to remove one or more volume groups.
The volume group(s) must not have any logical volumes allocated
and must also be inactive (see
.B vgchange(8)
).
The volume group(s) must not have any logical volumes allocated:
Remove them first with \fBlvremove\fP. If one or more physical
volumes in the volume group are lost, consider
\fBvgreduce --removemissing\fP to make the volume group
metadata consistent again.
.SH OPTIONS
See \fBlvm\fP for common options.
.SH SEE ALSO
.BR lvm (8),
.BR lvremove (8),
.BR vgcreate (8),
.BR vgreduce (8)

View File

@@ -13,7 +13,7 @@ vgs \- report information about volume groups
[\-v/\-\-verbose]
[\-\-version] [VolumeGroupName [VolumeGroupName...]]
.SH DESCRIPTION
vgs produces formatted output about volume groups
vgs produces formatted output about volume groups.
.SH OPTIONS
See \fBlvm\fP for common options.
.TP
@@ -32,7 +32,8 @@ if processing the output.
Comma-separated ordered list of columns. Precede the list with '+' to append
to the default selection of columns. Column names are: vg_fmt, vg_uuid,
vg_name, vg_attr, vg_size, vg_free, vg_sysid, vg_extent_size, vg_extent_count,
vg_free_count, max_lv, max_pv, pv_count, lv_count, snap_count, vg_seqno.
vg_free_count, max_lv, max_pv, pv_count, lv_count, snap_count, vg_seqno,
vg_tags.
Any "vg_" prefixes are optional. Columns mentioned in either \fBpvs (8)\fP
or \fBlvs (8)\fP can also be chosen, but columns cannot be taken from both
at the same time. The vg_attr bits are: (w)riteable, (r)eadonly,
@@ -54,5 +55,6 @@ All sizes are output in these units: (h)uman-readable, (s)ectors, (b)ytes,
of 1000 (S.I.) instead of 1024. Can also specify custom (u)nits e.g.
\-\-units 3M
.SH SEE ALSO
.BR vgdisplay (8),
.BR pvs (8),
.BR lvs (8)

View File

@@ -1,4 +1,4 @@
.TH VGMERGE 8 "LVM TOOLS" "Sistina Software UK" \" -*- nroff -*-
.TH VGSPLIT 8 "LVM TOOLS" "Sistina Software UK" \" -*- nroff -*-
.SH NAME
vgsplit \- split a volume group into two
.SH SYNOPSIS

1375
po/lvm2.po

File diff suppressed because it is too large Load Diff

View File

@@ -15,9 +15,10 @@ if [ -z "$PREFIX" ]
then
echo "usage: $0 <prefix> [<config file>] [<library>]"
echo ""
echo "<prefix> location of the cluster locking shared library. (no default)"
echo "<config file> name of the LVM config file (default: /etc/lvm/lvm.conf)"
echo "<library> name of the shared library (default: liblvm2clusterlock.so)"
echo "<prefix>|UNDO location of the cluster locking shared library. (no default)"
echo " UNDO will reset the locking back to local"
echo "<config file> name of the LVM config file (default: /etc/lvm/lvm.conf)"
echo "<library> name of the shared library (default: liblvm2clusterlock.so)"
echo ""
exit 0
fi
@@ -25,10 +26,23 @@ fi
[ -z "$LVMCONF" ] && LVMCONF="/etc/lvm/lvm.conf"
[ -z "$LIB" ] && LIB="liblvm2clusterlock.so"
if [ "${PREFIX:0:1}" != "/" ]
if [ "$PREFIX" = "UNDO" ]
then
echo "Prefix must be an absolute path name (starting with a /)"
exit 12
locking_type="1"
else
locking_type="2"
if [ "${PREFIX:0:1}" != "/" ]
then
echo "Prefix must be an absolute path name (starting with a /)"
exit 12
fi
if [ ! -f "$PREFIX/$LIB" ]
then
echo "$PREFIX/$LIB does not exist, did you do a \"make install\" ?"
exit 11
fi
fi
if [ ! -f "$LVMCONF" ]
@@ -37,12 +51,6 @@ then
exit 10
fi
if [ ! -f "$PREFIX/$LIB" ]
then
echo "$PREFIX/$LIB does not exist, did you do a \"make install\" ?"
exit 11
fi
SCRIPTFILE=`mktemp -t lvmscript.XXXXXXXXXX`
TMPFILE=`mktemp -t lvmtmp.XXXXXXXXXX`
@@ -87,7 +95,7 @@ then
cat $LVMCONF - <<EOF > $TMPFILE
global {
# Enable locking for cluster LVM
locking_type = 2
locking_type = $locking_type
library_dir = "$PREFIX"
locking_library = "$LIB"
}
@@ -105,7 +113,7 @@ else
if [ "$have_type" = "0" ]
then
SEDCMD=" s/^[[:blank:]]*locking_type[[:blank:]]*=.*/\ \ \ \ locking_type = 2/g"
SEDCMD=" s/^[[:blank:]]*locking_type[[:blank:]]*=.*/\ \ \ \ locking_type = $locking_type/g"
else
SEDCMD=" /global[[:blank:]]*{/a\ \ \ \ locking_type = 2"
fi

166
scripts/clvmd_init_rhel4 Normal file
View File

@@ -0,0 +1,166 @@
#!/bin/bash
#
# chkconfig: 345 24 76
# description: Starts and stops clvmd
#
#
### BEGIN INIT INFO
# Provides:
### END INIT INFO
. /etc/init.d/functions
[ -f /etc/sysconfig/cluster ] && . /etc/sysconfig/cluster
LOCK_FILE="/var/lock/subsys/clvmd"
#
# FIXME -- the lvm2-cluster rpms put the lvm tools in a different location
#
lvdisplay=/usr/sbin/cluster/lvdisplay
vgchange=/usr/sbin/cluster/vgchange
start()
{
modprobe dlm
for rtrn in 0
do
if ! pidof clvmd > /dev/null
then
echo -n "Starting clvmd:"
clvmd > /dev/null 2>&1
rtrn=$?
if [ $rtrn -eq 0 ]
then
success
echo
else
failure
echo
break
fi
fi
if [ -n "$LVM_VGS" ]
then
for vg in $LVM_VGS
do
echo -n "Activating lvm $vg:"
if $vgchange -ayl $vg > /dev/null 2>&1
then
success
echo
else
rtrn=$?
failure
echo
fi
done
else
echo -n "Activating lvms:"
if $vgchange -ayl > /dev/null 2>&1
then
success
echo
else
rtrn=$?
failure
echo
fi
fi
done
return $rtrn
}
stop()
{
for rtrn in 0
do
if [ -n "$LVM_VGS" ]
then
for vg in $LVM_VGS
do
echo -n "Deactivating lvm $vg:"
if $vgchange -anl $vg > /dev/null 2>&1
then
success
echo
else
rtrn=$?
failure
echo
fi
done
else
echo -n "Deactivating lvms:"
if $vgchange -anl > /dev/null 2>&1
then
success
echo
else
rtrn=$?
failure
echo
fi
fi
[ $rtrn -ne 0 ] && break
echo -n "Stopping clvm:"
pid=$(pidof clvmd)
if [ -n "$pid" ]
then
while kill $pid > /dev/null 2>&1
do
sleep 1
done
fi
if [ $rtrn -eq 0 ]
then
success
echo
else
failure
echo
fi
done
modprobe -r dlm > /dev/null 2>&1
return $rtrn
}
rtrn=1
# See how we were called.
case "$1" in
start)
start
rtrn=$?
[ $rtrn = 0 ] && touch $LOCK_FILE
;;
stop)
stop
rtrn=$?
[ $rtrn = 0 ] && rm -f $LOCK_FILE
;;
restart)
$0 stop
$0 start
rtrn=$?
;;
status)
status clvmd
vols=$( $lvdisplay -C --nohead 2> /dev/null | awk '($3 ~ /....a./) {print $1}' )
echo active volumes: ${vols:-"(none)"}
rtrn=0
;;
*)
echo $"Usage: $0 {start|stop|restart|status}"
;;
esac
exit $rtrn

View File

@@ -43,6 +43,7 @@ arg(mknodes_ARG, '\0', "mknodes", NULL)
arg(minor_ARG, '\0', "minor", minor_arg)
arg(type_ARG, '\0', "type", segtype_arg)
arg(alloc_ARG, '\0', "alloc", alloc_arg)
arg(separator_ARG, '\0', "separator", string_arg)
/* Allow some variations */
arg(resizable_ARG, '\0', "resizable", yes_no_arg)
@@ -99,7 +100,6 @@ arg(readahead_ARG, 'r', "readahead", int_arg)
arg(resizefs_ARG, 'r', "resizefs", NULL)
arg(reset_ARG, 'R', "reset", NULL)
arg(physicalextentsize_ARG, 's', "physicalextentsize", size_mb_arg)
arg(separator_ARG, 's', "separator", string_arg)
arg(stdin_ARG, 's', "stdin", NULL)
arg(snapshot_ARG, 's', "snapshot", NULL)
arg(short_ARG, 's', "short", NULL)

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