mirror of
git://sourceware.org/git/lvm2.git
synced 2025-10-04 05:44:18 +03:00
Compare commits
235 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ab8bdc18bb | ||
|
c9dcd7442a | ||
|
34c8f13346 | ||
|
7a8ccda95c | ||
|
44a1448542 | ||
|
c87d89ffaf | ||
|
0868749d42 | ||
|
1d40ee23f0 | ||
|
8893f32603 | ||
|
adcf7e8dc3 | ||
|
901f7c5c36 | ||
|
775bb413b3 | ||
|
64cd5b5a46 | ||
|
ae356609b1 | ||
|
6102a5d2b0 | ||
|
f8782ee2d7 | ||
|
6181ec4c77 | ||
|
e0e7a685ef | ||
|
ae1f8cdad2 | ||
|
a4cf792e6d | ||
|
89109ded53 | ||
|
e20e52a4b2 | ||
|
20c4b1cbec | ||
|
5238b0241d | ||
|
9cdf6c203d | ||
|
839335cae6 | ||
|
a99b2ce167 | ||
|
b695141d87 | ||
|
92d5c9f866 | ||
|
7f18a1ffe0 | ||
|
8c3fdaaa62 | ||
|
5ac1c69710 | ||
|
de2d5fba63 | ||
|
33d516748f | ||
|
de17f6f0fd | ||
|
756731fc02 | ||
|
e46be0415f | ||
|
aa02fb50bf | ||
|
8b6cd9c772 | ||
|
cdd0d3351a | ||
|
8b6d584529 | ||
|
f49fdd4141 | ||
|
b26e1be81a | ||
|
bacab38d7f | ||
|
701c05ce96 | ||
|
438c452585 | ||
|
0a7a1eff3f | ||
|
87e743e381 | ||
|
a03f1b3d55 | ||
|
2d8dc3d243 | ||
|
b982232cc5 | ||
|
61c8d728ac | ||
|
851a2bf855 | ||
|
e0bdde3630 | ||
|
6a0dcd7f0e | ||
|
75f0b4c879 | ||
|
db536a9504 | ||
|
0fb114dede | ||
|
e703342179 | ||
|
35c8f4a611 | ||
|
7c89ae44a9 | ||
|
84fe06da22 | ||
|
806318c8b3 | ||
|
3aac2e1822 | ||
|
168baef433 | ||
|
6dba6cd78d | ||
|
502250d08f | ||
|
7395f0e680 | ||
|
494d3fdaca | ||
|
7b86a157de | ||
|
0988c41785 | ||
|
522db1bf01 | ||
|
06f066f90d | ||
|
f37b20677b | ||
|
cd2eac1032 | ||
|
8ac38d58d7 | ||
|
4c80cc313a | ||
|
1c65fee9b4 | ||
|
90dda7edc1 | ||
|
da054fae20 | ||
|
bdb6611e30 | ||
|
9284f973f1 | ||
|
2bfd64c3c9 | ||
|
939d24cce5 | ||
|
27b0183c46 | ||
|
d14efacac7 | ||
|
150a002c40 | ||
|
ce0def3bd8 | ||
|
ee20fa97c2 | ||
|
7403b7d700 | ||
|
87ef173e0a | ||
|
52a3fb6bc7 | ||
|
92e2a257a6 | ||
|
32e175752c | ||
|
d43f7180dc | ||
|
0129c2b0fc | ||
|
4ed1990001 | ||
|
5bd6ab27ae | ||
|
f3593b89fa | ||
|
23d84b2310 | ||
|
fdc49402ec | ||
|
5457c133e1 | ||
|
292e588ee3 | ||
|
243494c25e | ||
|
e4365f3706 | ||
|
310f3038d3 | ||
|
4e6033273d | ||
|
73718586d3 | ||
|
011abe61e8 | ||
|
fe3a37f89d | ||
|
8aea44e77b | ||
|
5529aec0d6 | ||
|
369549d23f | ||
|
181ea9a381 | ||
|
76b8f2854e | ||
|
320e5198f9 | ||
|
e522539e2d | ||
|
7c996b83d2 | ||
|
3dd354d7aa | ||
|
f4ad6e2157 | ||
|
8b170dc2bf | ||
|
dcb9d779bf | ||
|
80f736d670 | ||
|
8502c6da3c | ||
|
b131449422 | ||
|
6eebc4a620 | ||
|
4661ab1179 | ||
|
86046445ed | ||
|
baea9bf944 | ||
|
0951ee9e63 | ||
|
5492528287 | ||
|
14dbd220c2 | ||
|
babc890c59 | ||
|
6f7b47ff40 | ||
|
3991f03202 | ||
|
27271d5da7 | ||
|
627312e1de | ||
|
bfc9550e4e | ||
|
2b9c21268b | ||
|
3dce4ed6f1 | ||
|
0f16c2ea87 | ||
|
9a635f0686 | ||
|
6a0d4b2baa | ||
|
ac017098ad | ||
|
98fef2640d | ||
|
8bb66e133a | ||
|
68a582901d | ||
|
c094f4c06e | ||
|
f7ca545544 | ||
|
69b4716894 | ||
|
7e44dcc5bf | ||
|
ab9843e183 | ||
|
01af706ade | ||
|
9ebdb08e99 | ||
|
a74ffe25d9 | ||
|
7f95e27707 | ||
|
1facf5bba3 | ||
|
03d77009eb | ||
|
8afd6812b5 | ||
|
ec9ad78fcf | ||
|
6f4e93dc90 | ||
|
a38e43862d | ||
|
39294bb037 | ||
|
edc5e59b78 | ||
|
c00fd9fd37 | ||
|
b3e621dd9f | ||
|
6e8c49b978 | ||
|
398d57133d | ||
|
16521a6feb | ||
|
3ca0b37a3e | ||
|
cf2ec1229d | ||
|
fe9b1e5f9b | ||
|
f5b96ddf01 | ||
|
2fe076fb27 | ||
|
99249cff04 | ||
|
0cdf7b0613 | ||
|
90bcf4f157 | ||
|
03c3ec4e12 | ||
|
ca9bb20d64 | ||
|
c6bc078fd9 | ||
|
2f4bd6e52c | ||
|
2affe53727 | ||
|
09654d7dd8 | ||
|
90a4e37815 | ||
|
60889c0c79 | ||
|
20f3408d96 | ||
|
e9d86789db | ||
|
5152b7c66c | ||
|
c494c4e12c | ||
|
54d58ccb7e | ||
|
714a77bfbe | ||
|
d48f8bf5cc | ||
|
99d97754a6 | ||
|
b9d437de2a | ||
|
11403f2019 | ||
|
1ca102d639 | ||
|
339ba55111 | ||
|
14ae59885a | ||
|
e3ef54f99b | ||
|
001901f9a9 | ||
|
6a98f60e2e | ||
|
6f2e24c47d | ||
|
aafa368923 | ||
|
eb783cab4c | ||
|
6533aa865a | ||
|
f1a1e1bc07 | ||
|
953f4838dd | ||
|
130b892d34 | ||
|
6ad525c77e | ||
|
d0ca74ad27 | ||
|
9806f69b4d | ||
|
34d9b5e3d7 | ||
|
3bf5189d86 | ||
|
12e5b0681b | ||
|
8c0285d608 | ||
|
36558fa3b8 | ||
|
235f940cde | ||
|
803d61fcbc | ||
|
ffbd7d8de4 | ||
|
4ed924d7c7 | ||
|
798dc9948b | ||
|
13515f7ee4 | ||
|
ef80824c26 | ||
|
c8503fd65e | ||
|
b3c454fb1c | ||
|
1d7723e873 | ||
|
77100b2365 | ||
|
259a788134 | ||
|
39511455cb | ||
|
b04c16178e | ||
|
49a959c06e | ||
|
096a8932b4 | ||
|
e39e66df93 | ||
|
513633f49a | ||
|
eb3740daaf |
0
CONTRIBUTORS
Normal file
0
CONTRIBUTORS
Normal file
212
WHATS_NEW
212
WHATS_NEW
@@ -1,3 +1,215 @@
|
||||
Version 2.01.10 -
|
||||
================================
|
||||
Tidy lv_segment interface.
|
||||
Initial pv_segment support.
|
||||
vgchange --physicalextentsize
|
||||
Internal snapshot restructuring.
|
||||
Remove unused internal non-persistent snapshot option.
|
||||
Allow offline extension of snapshot volumes.
|
||||
Move from 2-step to 3-step on-disk metadata commit.
|
||||
Scan ramdisks too and allow non-O_DIRECT fallback.
|
||||
Annotate, tidy and extend list.h.
|
||||
Alignment tidying.
|
||||
Make clvmd work around some "bugs" in gulm's node state notifications.
|
||||
Tidy clvmd's SIGHUP handler
|
||||
|
||||
Version 2.01.09 - 4th April 2005
|
||||
================================
|
||||
Add --ignorelockingfailure to vgmknodes.
|
||||
clvmd: Don't allow user operations to start until the lvm thread is fully up.
|
||||
clvmd-gulm: set KEEPALIVE on sockets.
|
||||
|
||||
Version 2.01.08 - 22nd March 2005
|
||||
=================================
|
||||
Add clustered attribute so vgchange can identify clustered VGs w/o locking.
|
||||
Improve detection of external changes affecting internal cache.
|
||||
Add 'already in device cache' debug message.
|
||||
Add -a to pvdisplay -C.
|
||||
Avoid rmdir opendir error messsages when dir was already removed.
|
||||
Tighten signal handlers.
|
||||
Avoid some compiler warnings.
|
||||
Additional rename failure error message.
|
||||
read/write may be macros.
|
||||
clvmd: don't take out lvm thread lock at startup, it only protects jobs list.
|
||||
|
||||
Version 2.01.07 - 8th March 2005
|
||||
================================
|
||||
Cope with new devices appearing by rescanning /dev if a uuid can't be found.
|
||||
Remove DESTDIR from LVM_SHARED_PATH.
|
||||
clvmd fixes: make FDs close-on-exec
|
||||
gulm unlocks VG & orphan locks at startup in case they are stale
|
||||
gulm now unlocks VG & orphan locks if client dies.
|
||||
|
||||
Version 2.01.06 - 1st March 2005
|
||||
================================
|
||||
Suppress 'open failed' error messages during scanning.
|
||||
Option to suppress warnings of file descriptors left open.
|
||||
Fix default value of metadatacopies in documentation (2->1).
|
||||
Fix clvmd-gulm locking.
|
||||
./configure --enable-debug now enables debugging code in clvmd.
|
||||
Fix clvmd-gulm node up/down code so it actually works.
|
||||
clvmd-gulm now releases locks when shut down.
|
||||
|
||||
Version 2.01.05 - 18th February 2005
|
||||
====================================
|
||||
Static binary invokes dynamic binary if appropriate.
|
||||
Make clvmd config check a little more tolerant.
|
||||
gulm clvmd can now cope with >1 message arriving in a TCP message.
|
||||
|
||||
Version 2.01.04 - 9th February 2005
|
||||
===================================
|
||||
Add fixed offset to imported pool minor numbers.
|
||||
Update binary pathnames in clvmd_init_rhel4.
|
||||
lvm2cmd.so should skip the check for open fds.
|
||||
Remove unused -f from pvmove.
|
||||
Gulm clvmd doesn't report "connection refused" errors.
|
||||
clvmd does a basic config file sanity check at startup.
|
||||
Fix potential thread shutdown race in clvmd.
|
||||
|
||||
Version 2.01.03 - 1st February 2005
|
||||
===================================
|
||||
More 64-bit display/report fixes.
|
||||
More informative startup mesg if can't create /etc/lvm.
|
||||
Fix snapshot device size bug (since 2.01.01).
|
||||
clvmd announces startup and cluster connection in syslog.
|
||||
Gulm clvmd doesn't hang trying to talk to a rebooted node.
|
||||
Gulm clvmd doesn't print cman error on startup.
|
||||
|
||||
Version 2.01.02 - 21st January 2005
|
||||
===================================
|
||||
Update clvmd_init_rhel4: use lvm.static and don't load dlm.
|
||||
Fix some size_t printing.
|
||||
Fix 64 bit xlate consts.
|
||||
Split out pool sptype_names to avoid unused const.
|
||||
Always fail if random id generation fails.
|
||||
Recognise gnbd devices.
|
||||
Fix clvmd startup bug introduced in cman/gulm amalgamation.
|
||||
Improve reporting of node-specific locking errors.
|
||||
|
||||
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.
|
||||
Rename old segtypes files to segtype.
|
||||
Some fixes to memory debugging code.
|
||||
Exclude internal commands formats & segtypes from install.
|
||||
|
||||
Version 2.00.23 - 15th September 2004
|
||||
=====================================
|
||||
Export dm name build & split functions.
|
||||
Use O_NOATIME on devices if available.
|
||||
Write log message when each segtype/format gets initialised.
|
||||
New commands 'segtypes' and 'formats'.
|
||||
Suppress pvmove abort message in test mode.
|
||||
Improve pvcreate/remove device not found error message.
|
||||
Allow pvmove to move data within the same PV.
|
||||
Describe how pvmove works on man page.
|
||||
Test for incompatible format/segtype combinations in lv_extend.
|
||||
Fix lvchange example on man page.
|
||||
|
||||
Version 2.00.22 - 3rd September 2004
|
||||
====================================
|
||||
Fix /dev/vgname perms.
|
||||
Restructure xlate.h.
|
||||
Add clvmd man page.
|
||||
|
||||
Version 2.00.21 - 19th August 2004
|
||||
==================================
|
||||
Update cnxman-socket.h from cman.
|
||||
|
27
WHATS_NEW_DM
27
WHATS_NEW_DM
@@ -1,6 +1,31 @@
|
||||
Version 1.00.20 -
|
||||
Version 1.01.02 -
|
||||
=============================
|
||||
|
||||
Version 1.01.01 - 29 Mar 2005
|
||||
=============================
|
||||
Update dmsetup man page.
|
||||
Drop-in devmap_name replacement.
|
||||
Add option to compile without ioctl for testing.
|
||||
Fix DM_LIB_VERSION sed.
|
||||
|
||||
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.
|
||||
|
16
configure.in
16
configure.in
@@ -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
|
||||
|
@@ -15,7 +15,7 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
ifeq ("@CLVMD@", "yes")
|
||||
ifneq ("@CLVMD@", "none")
|
||||
SUBDIRS = clvmd
|
||||
endif
|
||||
|
||||
|
@@ -16,26 +16,53 @@ 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 ("@DEBUG@", "yes")
|
||||
CFLAGS += -DDEBUG
|
||||
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
|
||||
|
||||
|
@@ -43,6 +43,7 @@ struct clvm_header {
|
||||
/* Flags */
|
||||
#define CLVMD_FLAG_LOCAL 1 /* Only do this on the local node */
|
||||
#define CLVMD_FLAG_SYSTEMLV 2 /* Data in system LV under my node name */
|
||||
#define CLVMD_FLAG_NODEERRS 4 /* Reply has errors in node-specific portion */
|
||||
|
||||
/* Name of the local socket to communicate between libclvm and clvmd */
|
||||
//static const char CLVMD_SOCKNAME[]="/var/run/clvmd";
|
||||
|
@@ -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,9 +74,11 @@ 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");
|
||||
/* Don't print an error here because we could be just probing for CMAN */
|
||||
return -1;
|
||||
}
|
||||
/* Set Close-on-exec */
|
||||
fcntl(cluster_sock, F_SETFD, 1);
|
||||
|
||||
/* Bind to our port number on the cluster.
|
||||
Writes to this will block if the cluster loses quorum */
|
||||
@@ -87,7 +88,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 +99,31 @@ 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 void _cluster_init_completed(void)
|
||||
{
|
||||
clvmd_cluster_init_completed();
|
||||
}
|
||||
|
||||
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 +143,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 +159,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 +210,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 +254,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 +315,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 +331,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 +343,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 +374,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 +388,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 +404,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 +424,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 +443,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 +453,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 +479,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 +513,28 @@ int sync_unlock(const char *resource /* UNUSED */, int lockid)
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static struct cluster_ops _cluster_cman_ops = {
|
||||
.cluster_init_completed = _cluster_init_completed,
|
||||
.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;
|
||||
}
|
||||
|
@@ -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,26 @@ 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);
|
||||
char *lockname = hash_get_key(lock_hash, v);
|
||||
|
||||
DEBUGLOG("cleanup: Unlocking lock %s %x\n", lockname, lkid);
|
||||
sync_unlock(lockname, lkid);
|
||||
}
|
||||
|
||||
hash_destroy(lock_hash);
|
||||
client->bits.localsock.private = 0;
|
||||
}
|
||||
}
|
||||
|
@@ -22,33 +22,48 @@
|
||||
|
||||
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 (*reread_config) (void);
|
||||
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
|
||||
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 2002-2003 All rights reserved.
|
||||
** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
@@ -46,6 +47,7 @@
|
||||
#include "log.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "lvm-functions.h"
|
||||
#include "clvmd.h"
|
||||
#include "hash.h"
|
||||
#include "clvmd-gulm.h"
|
||||
@@ -58,13 +60,15 @@ static struct hash_table *node_hash;
|
||||
/* hash list of outstanding lock requests */
|
||||
static struct hash_table *lock_hash;
|
||||
|
||||
/* Copy of the current core state */
|
||||
static uint8_t current_corestate;
|
||||
/* Copy of the current quorate state */
|
||||
static uint8_t gulm_quorate = 0;
|
||||
static enum {INIT_NOTDONE, INIT_DONE, INIT_WAITQUORATE} init_state = INIT_NOTDONE;
|
||||
|
||||
/* Number of active nodes */
|
||||
static int num_nodes;
|
||||
|
||||
static char *cluster_name;
|
||||
static int in_shutdown = 0;
|
||||
|
||||
static pthread_mutex_t lock_start_mutex;
|
||||
static volatile int lock_start_flag;
|
||||
@@ -72,7 +76,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 +92,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;
|
||||
@@ -112,6 +118,9 @@ static int add_internal_client(int fd, fd_callback_t callback)
|
||||
client->callback = callback;
|
||||
add_client(client);
|
||||
|
||||
/* Set Close-on-exec */
|
||||
fcntl(fd, F_SETFD, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -123,27 +132,45 @@ 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);
|
||||
}
|
||||
|
||||
static void sighup_handler(int sig)
|
||||
static void _reread_config(void)
|
||||
{
|
||||
DEBUGLOG("got SIGHUP\n");
|
||||
|
||||
/* Re-read CCS node list */
|
||||
get_all_cluster_nodes();
|
||||
/* Re-read CCS node list */
|
||||
DEBUGLOG("Re-reading CCS config\n");
|
||||
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 +182,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 +202,7 @@ int init_cluster()
|
||||
}
|
||||
|
||||
/* Initialise the inter-node comms */
|
||||
status = init_comms();
|
||||
status = init_comms(port);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
@@ -202,7 +230,7 @@ int init_cluster()
|
||||
exit(status);
|
||||
}
|
||||
|
||||
/* Request a list of nodes, we can;t really do anything until
|
||||
/* Request a list of nodes, we can't really do anything until
|
||||
this comes back */
|
||||
status = lg_core_nodelist(gulm_if);
|
||||
if (status)
|
||||
@@ -215,18 +243,16 @@ int init_cluster()
|
||||
signal(SIGINT, badsig_handler);
|
||||
signal(SIGTERM, badsig_handler);
|
||||
|
||||
/* Re-read the node list on SIGHUP */
|
||||
signal(SIGHUP, sighup_handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cluster_closedown()
|
||||
static void _cluster_closedown(void)
|
||||
{
|
||||
DEBUGLOG("cluster_closedown\n");
|
||||
in_shutdown = 1;
|
||||
unlock_all();
|
||||
lg_lock_logout(gulm_if);
|
||||
lg_core_logout(gulm_if);
|
||||
lg_core_shutdown(gulm_if);
|
||||
lg_release(gulm_if);
|
||||
}
|
||||
|
||||
@@ -237,6 +263,7 @@ static void drop_expired_locks(char *nodename)
|
||||
struct utsname nodeinfo;
|
||||
uint8_t mask[GIO_KEY_SIZE];
|
||||
|
||||
DEBUGLOG("Dropping expired locks for %s\n", nodename?nodename:"(null)");
|
||||
memset(mask, 0xff, GIO_KEY_SIZE);
|
||||
|
||||
if (!nodename)
|
||||
@@ -282,12 +309,16 @@ static int core_login_reply(void *misc, uint64_t gen, uint32_t error, uint32_t r
|
||||
if (error)
|
||||
exit(error);
|
||||
|
||||
current_corestate = corestate;
|
||||
/* Get the current core state (for quorum) */
|
||||
lg_core_corestate(gulm_if);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_node_state(struct node_info *ninfo, char *csid, uint8_t nodestate)
|
||||
{
|
||||
int oldstate = ninfo->state;
|
||||
|
||||
if (nodestate == lg_core_Logged_in)
|
||||
{
|
||||
/* Don't clobber NODE_CLVMD state */
|
||||
@@ -309,18 +340,24 @@ static void set_node_state(struct node_info *ninfo, char *csid, uint8_t nodestat
|
||||
if (ninfo->state != NODE_DOWN)
|
||||
num_nodes--;
|
||||
ninfo->state = NODE_DOWN;
|
||||
tcp_remove_client(csid);
|
||||
}
|
||||
}
|
||||
DEBUGLOG("set_node_state, '%s' state = %d, num_nodes=%d\n",
|
||||
ninfo->name, ninfo->state, num_nodes);
|
||||
/* Gulm doesn't always send node DOWN events, so even if this a a node UP we must
|
||||
* assume (ahem) that it prevously went down at some time. So we close
|
||||
* the sockets here to make sure that we don't have any dead connections
|
||||
* to that node.
|
||||
*/
|
||||
tcp_remove_client(csid);
|
||||
|
||||
DEBUGLOG("set_node_state, '%s' state = %d (oldstate=%d), num_nodes=%d\n",
|
||||
ninfo->name, ninfo->state, oldstate, 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 +366,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);
|
||||
@@ -337,12 +374,17 @@ static struct node_info *add_or_set_node(char *name, uint32_t ip, uint8_t state)
|
||||
}
|
||||
}
|
||||
|
||||
set_node_state(ninfo, (char *)&ip, state);
|
||||
set_node_state(ninfo, (char *)ip, 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 +396,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 +404,23 @@ 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();
|
||||
if (gulm_quorate)
|
||||
{
|
||||
clvmd_cluster_init_completed();
|
||||
init_state = INIT_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (init_state == INIT_NOTDONE)
|
||||
init_state = INIT_WAITQUORATE;
|
||||
}
|
||||
|
||||
/* Mark ourself as up */
|
||||
get_our_csid(ourcsid);
|
||||
add_up_node(ourcsid);
|
||||
_get_our_csid(ourcsid);
|
||||
gulm_add_up_node(ourcsid);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -381,24 +432,29 @@ 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. quorate:%d, corestate:%x mastername:%s\n",
|
||||
quorate, corestate, mastername);
|
||||
|
||||
current_corestate = corestate;
|
||||
gulm_quorate = quorate;
|
||||
if (quorate && init_state == INIT_WAITQUORATE)
|
||||
{
|
||||
clvmd_cluster_init_completed();
|
||||
init_state = INIT_DONE;
|
||||
}
|
||||
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,13 +499,19 @@ 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;
|
||||
|
||||
DEBUGLOG("LOCK lock state: %s, error = %d\n", key, error);
|
||||
|
||||
/* No waiting process to wake up when we are shutting down */
|
||||
if (in_shutdown)
|
||||
return 0;
|
||||
|
||||
lwait = hash_lookup(lock_hash, key);
|
||||
if (!lwait)
|
||||
{
|
||||
@@ -519,19 +581,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 +601,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,29 +611,36 @@ 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);
|
||||
if (!ninfo)
|
||||
ninfo = hash_lookup_binary(node_hash, csid, GULM_MAX_CSID_LEN);
|
||||
if (!ninfo) {
|
||||
DEBUGLOG("gulm_add_up_node no node_hash entry for csid %s\n", print_csid(csid));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUGLOG("gulm_add_up_node %s\n", ninfo->name);
|
||||
|
||||
if (ninfo->state == NODE_DOWN)
|
||||
num_nodes++;
|
||||
ninfo->state = NODE_CLVMD;
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
@@ -581,7 +649,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;
|
||||
|
||||
@@ -589,30 +657,42 @@ void add_down_node(char *csid)
|
||||
running clvmd - gulm may set it DOWN quite soon */
|
||||
if (ninfo->state == NODE_CLVMD)
|
||||
ninfo->state = NODE_UP;
|
||||
drop_expired_locks(ninfo->name);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* 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,
|
||||
void (*callback)(struct local_client *, char *csid, int node_up))
|
||||
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;
|
||||
struct node_info *ninfo;
|
||||
|
||||
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);
|
||||
if (client)
|
||||
callback(master_client, csid, ninfo->state == NODE_CLVMD);
|
||||
client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
|
||||
if (!client)
|
||||
{
|
||||
/* If it's up but not connected, try to make contact */
|
||||
if (ninfo->state == NODE_UP)
|
||||
gulm_connect_csid(csid, &client);
|
||||
|
||||
client = hash_lookup_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
|
||||
|
||||
}
|
||||
if (ninfo->state != NODE_DOWN)
|
||||
callback(master_client, csid, ninfo->state == NODE_CLVMD);
|
||||
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -623,15 +703,13 @@ static int gulm_to_errno(int gulm_ret)
|
||||
switch (gulm_ret)
|
||||
{
|
||||
case lg_err_TryFailed:
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
|
||||
case lg_err_AlreadyPend:
|
||||
errno = EBUSY;
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
|
||||
/* More?? */
|
||||
default:
|
||||
errno = EINVAL;
|
||||
errno = EINVAL;
|
||||
}
|
||||
|
||||
return gulm_ret ? -1 : 0;
|
||||
@@ -661,6 +739,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 +771,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)
|
||||
@@ -700,6 +780,11 @@ static int _unlock_resource(char *resource, int lockid)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* When we are shutting down, don't wait for unlocks
|
||||
to be acknowledged, just do it. */
|
||||
if (in_shutdown)
|
||||
return status;
|
||||
|
||||
/* Wait for it to complete */
|
||||
|
||||
pthread_cond_wait(&lwait.cond, &lwait.mutex);
|
||||
@@ -720,7 +805,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];
|
||||
@@ -736,7 +821,7 @@ int sync_lock(const char *resource, int mode, int flags, int *lockid)
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
/* If we can't get this lock then bail out */
|
||||
/* If we can't get this lock too then bail out */
|
||||
status = _lock_resource(lock2, lg_lock_state_Exclusive, LCK_NONBLOCK, lockid);
|
||||
if (status == lg_err_TryFailed)
|
||||
{
|
||||
@@ -748,10 +833,16 @@ int sync_lock(const char *resource, int mode, int flags, int *lockid)
|
||||
|
||||
case LCK_READ:
|
||||
status = _lock_resource(lock1, lg_lock_state_Shared, flags, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
status = _unlock_resource(lock2, *lockid);
|
||||
break;
|
||||
|
||||
case LCK_WRITE:
|
||||
status = _lock_resource(lock2, lg_lock_state_Exclusive, flags, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
status = _unlock_resource(lock1, *lockid);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -764,7 +855,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];
|
||||
@@ -778,36 +869,16 @@ int sync_unlock(const char *resource, int lockid)
|
||||
lockid == LCK_READ ||
|
||||
lockid == LCK_WRITE);
|
||||
|
||||
switch (lockid)
|
||||
{
|
||||
case LCK_EXCL:
|
||||
status = _unlock_resource(lock1, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
status = _unlock_resource(lock2, lockid);
|
||||
break;
|
||||
status = _unlock_resource(lock1, lockid);
|
||||
if (!status)
|
||||
status = _unlock_resource(lock2, lockid);
|
||||
|
||||
case LCK_READ:
|
||||
status = _unlock_resource(lock1, lockid);
|
||||
break;
|
||||
|
||||
case LCK_WRITE:
|
||||
status = _unlock_resource(lock2, lockid);
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
int is_quorate()
|
||||
static int _is_quorate()
|
||||
{
|
||||
if (current_corestate == lg_core_Slave ||
|
||||
current_corestate == lg_core_Master ||
|
||||
current_corestate == lg_core_Client)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
return gulm_quorate;
|
||||
}
|
||||
|
||||
/* Get all the cluster node names & IPs from CCS and
|
||||
@@ -819,31 +890,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 +939,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 +955,43 @@ static int get_all_cluster_nodes()
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gulm_fd(void)
|
||||
static int _get_main_cluster_fd(void)
|
||||
{
|
||||
return lg_core_selector(gulm_if);
|
||||
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 = NULL,
|
||||
.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,
|
||||
.reread_config = _reread_config,
|
||||
.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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -34,11 +34,13 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
|
||||
#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 +56,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 +66,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 {
|
||||
@@ -80,11 +87,22 @@ struct lvm_thread_cmd {
|
||||
static pthread_t lvm_thread;
|
||||
static pthread_mutex_t lvm_thread_mutex;
|
||||
static pthread_cond_t lvm_thread_cond;
|
||||
static pthread_mutex_t lvm_start_mutex;
|
||||
static struct list lvm_cmd_head;
|
||||
static int quit = 0;
|
||||
static volatile sig_atomic_t quit = 0;
|
||||
static volatile sig_atomic_t reread_config = 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);
|
||||
static void sighup_handler(int sig);
|
||||
static void sigterm_handler(int sig);
|
||||
static void send_local_reply(struct local_client *client, int status,
|
||||
int clientid);
|
||||
@@ -129,6 +147,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;
|
||||
@@ -138,6 +168,7 @@ int main(int argc, char *argv[])
|
||||
int debug = 0;
|
||||
int cmd_timeout = DEFAULT_CMD_TIMEOUT;
|
||||
sigset_t ss;
|
||||
int using_gulm = 0;
|
||||
|
||||
/* Deal with command-line arguments */
|
||||
opterr = 0;
|
||||
@@ -166,7 +197,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 +220,14 @@ 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.
|
||||
HUP causes gulm version to re-read nodes list from CCS.
|
||||
PIPE should be ignored */
|
||||
signal(SIGUSR2, sigusr2_handler);
|
||||
signal(SIGTERM, sigterm_handler);
|
||||
signal(SIGINT, sigterm_handler);
|
||||
signal(SIGHUP, sighup_handler);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
/* Block SIGUSR2 in the main process */
|
||||
@@ -207,31 +239,52 @@ int main(int argc, char *argv[])
|
||||
list_init(&lvm_cmd_head);
|
||||
pthread_mutex_init(&lvm_thread_mutex, NULL);
|
||||
pthread_cond_init(&lvm_thread_cond, NULL);
|
||||
pthread_mutex_init(&lvm_start_mutex, NULL);
|
||||
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;
|
||||
syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to CMAN");
|
||||
}
|
||||
#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;
|
||||
using_gulm = 1;
|
||||
syslog(LOG_NOTICE, "Cluster LVM daemon started - connected to GULM");
|
||||
}
|
||||
#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->removeme = 0;
|
||||
newfd->type = LOCAL_RENDEZVOUS;
|
||||
newfd->callback = local_rendezvous_callback;
|
||||
newfd->next = local_client_head.next;
|
||||
@@ -240,17 +293,21 @@ int main(int argc, char *argv[])
|
||||
/* This needs to be started after cluster initialisation
|
||||
as it may need to take out locks */
|
||||
DEBUGLOG("starting LVM thread\n");
|
||||
pthread_create(&lvm_thread, NULL, lvm_thread_fn, nodeinfo.nodename);
|
||||
pthread_create(&lvm_thread, NULL, lvm_thread_fn, (void *)using_gulm);
|
||||
|
||||
#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);
|
||||
@@ -294,6 +351,7 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
|
||||
newfd->fd = client_fd;
|
||||
newfd->type = LOCAL_SOCK;
|
||||
newfd->xid = 0;
|
||||
newfd->removeme = 0;
|
||||
newfd->callback = local_sock_callback;
|
||||
newfd->bits.localsock.replies = NULL;
|
||||
newfd->bits.localsock.expected_replies = 0;
|
||||
@@ -303,6 +361,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 +450,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 +481,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 +506,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);
|
||||
@@ -459,14 +518,38 @@ static void main_loop(int local_sock, int cmd_timeout)
|
||||
FD_SET(thisfd->fd, &in);
|
||||
}
|
||||
|
||||
if ((select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv)) > 0) {
|
||||
select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv);
|
||||
|
||||
if (reread_config) {
|
||||
int saved_errno = errno;
|
||||
|
||||
reread_config = 0;
|
||||
if (clops->reread_config)
|
||||
clops->reread_config();
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
if (select_status > 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) {
|
||||
|
||||
if (thisfd->removeme) {
|
||||
struct local_client *free_fd;
|
||||
lastfd->next = thisfd->next;
|
||||
free_fd = thisfd;
|
||||
thisfd = lastfd;
|
||||
|
||||
DEBUGLOG("removeme set for fd %d\n", free_fd->fd);
|
||||
|
||||
/* Queue cleanup, this also frees the client struct */
|
||||
add_to_lvmqueue(free_fd, NULL, 0, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(thisfd->fd, &in)) {
|
||||
struct local_client *newfd;
|
||||
int ret;
|
||||
@@ -490,13 +573,14 @@ 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;
|
||||
free(free_fd);
|
||||
|
||||
/* Queue cleanup, this also frees the client struct */
|
||||
add_to_lvmqueue(free_fd, NULL, 0, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -506,33 +590,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 +632,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 */
|
||||
@@ -659,7 +755,7 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
if (thisfd->bits.localsock.threadid) {
|
||||
DEBUGLOG("Waiting for child thread\n");
|
||||
pthread_mutex_lock(&thisfd->bits.localsock.mutex);
|
||||
thisfd->bits.localsock.state = POST_COMMAND;
|
||||
thisfd->bits.localsock.state = PRE_COMMAND;
|
||||
pthread_cond_signal(&thisfd->bits.localsock.cond);
|
||||
pthread_mutex_unlock(&thisfd->bits.localsock.mutex);
|
||||
pthread_kill(thisfd->bits.localsock.threadid, SIGUSR2);
|
||||
@@ -717,6 +813,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;
|
||||
|
||||
@@ -727,7 +824,7 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
if (thisfd->bits.localsock.in_progress) {
|
||||
struct clvm_header reply;
|
||||
reply.cmd = CLVMD_CMD_REPLY;
|
||||
reply.status = -EBUSY;
|
||||
reply.status = EBUSY;
|
||||
reply.arglen = 0;
|
||||
reply.flags = 0;
|
||||
send_message(&reply, sizeof(reply), our_csid,
|
||||
@@ -750,7 +847,7 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
if (!thisfd->bits.localsock.cmd) {
|
||||
struct clvm_header reply;
|
||||
reply.cmd = CLVMD_CMD_REPLY;
|
||||
reply.status = -ENOMEM;
|
||||
reply.status = ENOMEM;
|
||||
reply.arglen = 0;
|
||||
reply.flags = 0;
|
||||
send_message(&reply, sizeof(reply), our_csid,
|
||||
@@ -791,13 +888,13 @@ 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);
|
||||
|
||||
reply.cmd = CLVMD_CMD_REPLY;
|
||||
reply.status = -ENOENT;
|
||||
reply.status = ENOENT;
|
||||
reply.flags = 0;
|
||||
reply.arglen = 0;
|
||||
send_message(&reply, sizeof(reply), our_csid,
|
||||
@@ -828,7 +925,7 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
close(comms_pipe[1]);
|
||||
|
||||
reply.cmd = CLVMD_CMD_REPLY;
|
||||
reply.status = -ENOMEM;
|
||||
reply.status = ENOMEM;
|
||||
reply.arglen = 0;
|
||||
reply.flags = 0;
|
||||
send_message(&reply, sizeof(reply), our_csid,
|
||||
@@ -839,6 +936,7 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
DEBUGLOG("creating pipe, [%d, %d]\n", comms_pipe[0],
|
||||
comms_pipe[1]);
|
||||
newfd->fd = comms_pipe[0];
|
||||
newfd->removeme = 0;
|
||||
newfd->type = THREAD_PIPE;
|
||||
newfd->callback = local_pipe_callback;
|
||||
newfd->next = thisfd->next;
|
||||
@@ -863,8 +961,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 +1021,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 +1042,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 +1052,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,17 +1084,17 @@ 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);
|
||||
DEBUGLOG("process_remote_command %d for clientid 0x%x XID %d on node %s\n",
|
||||
msg->cmd, msg->clientid, msg->xid, nodename);
|
||||
|
||||
/* Is the data to be found in the system LV ? */
|
||||
if (msg->flags & CLVMD_FLAG_SYSTEMLV) {
|
||||
@@ -1016,7 +1116,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
|
||||
/* Return a failure response */
|
||||
head.cmd = CLVMD_CMD_REPLY;
|
||||
head.status = -EFBIG;
|
||||
head.status = EFBIG;
|
||||
head.flags = 0;
|
||||
head.clientid = msg->clientid;
|
||||
head.arglen = 0;
|
||||
@@ -1033,7 +1133,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
msg->arglen);
|
||||
/* Return a failure response */
|
||||
head.cmd = CLVMD_CMD_REPLY;
|
||||
head.status = -ENOMEM;
|
||||
head.status = ENOMEM;
|
||||
head.flags = 0;
|
||||
head.clientid = msg->clientid;
|
||||
head.arglen = 0;
|
||||
@@ -1057,7 +1157,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 +1178,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 */
|
||||
@@ -1096,7 +1196,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
do_command(NULL, msg, msglen, &replyargs, buflen,
|
||||
&replylen);
|
||||
} else {
|
||||
status = -ENOMEM;
|
||||
status = ENOMEM;
|
||||
}
|
||||
|
||||
/* If it wasn't a reply, then reply */
|
||||
@@ -1127,11 +1227,10 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
|
||||
/* If System LV operation failed then report it as EFBIG but only do it
|
||||
if the data buffer has something in it. */
|
||||
if (system_lv_write_data
|
||||
(aggreply,
|
||||
replylen + sizeof(struct clvm_header)) < 0
|
||||
if (system_lv_write_data(aggreply,
|
||||
replylen + sizeof(struct clvm_header)) < 0
|
||||
&& replylen > 0)
|
||||
agghead->status = -EFBIG;
|
||||
agghead->status = EFBIG;
|
||||
|
||||
send_message(agghead,
|
||||
sizeof(struct clvm_header), csid,
|
||||
@@ -1147,7 +1246,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
agghead->node[0] = '\0';
|
||||
send_message(aggreply,
|
||||
sizeof(struct clvm_header) +
|
||||
replylen + 2, csid, fd,
|
||||
replylen, csid, fd,
|
||||
"Error sending command reply");
|
||||
}
|
||||
} else {
|
||||
@@ -1156,7 +1255,7 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
DEBUGLOG("Error attempting to realloc return buffer\n");
|
||||
/* Return a failure response */
|
||||
head.cmd = CLVMD_CMD_REPLY;
|
||||
head.status = -ENOMEM;
|
||||
head.status = ENOMEM;
|
||||
head.flags = 0;
|
||||
head.clientid = msg->clientid;
|
||||
head.arglen = 0;
|
||||
@@ -1188,13 +1287,13 @@ 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) {
|
||||
reply->replymsg = malloc(len);
|
||||
if (!reply->replymsg) {
|
||||
reply->status = -ENOMEM;
|
||||
reply->status = ENOMEM;
|
||||
} else {
|
||||
memcpy(reply->replymsg, buf, len);
|
||||
}
|
||||
@@ -1238,6 +1337,11 @@ static void *pre_and_post_thread(void *arg)
|
||||
|
||||
DEBUGLOG("in sub thread: client = %p\n", client);
|
||||
|
||||
/* Don't start until the LVM thread is ready */
|
||||
pthread_mutex_lock(&lvm_start_mutex);
|
||||
pthread_mutex_unlock(&lvm_start_mutex);
|
||||
DEBUGLOG("Sub thread ready for work.\n");
|
||||
|
||||
/* Ignore SIGUSR1 (handled by master process) but enable
|
||||
SIGUSR2 (kills subthreads) */
|
||||
sigemptyset(&ss);
|
||||
@@ -1273,13 +1377,12 @@ static void *pre_and_post_thread(void *arg)
|
||||
|
||||
DEBUGLOG("Got post command condition...\n");
|
||||
|
||||
/* POST function must always run, even if the client aborts */
|
||||
status = 0;
|
||||
do_post_command(client);
|
||||
|
||||
write(pipe_fd, &status, sizeof(int));
|
||||
|
||||
if (client->bits.localsock.finished)
|
||||
break;
|
||||
|
||||
DEBUGLOG("Waiting for next pre command\n");
|
||||
|
||||
pthread_mutex_lock(&client->bits.localsock.mutex);
|
||||
@@ -1292,7 +1395,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 +1404,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;
|
||||
|
||||
@@ -1383,9 +1487,10 @@ static void send_local_reply(struct local_client *client, int status, int fd)
|
||||
replybuf = malloc(message_len);
|
||||
|
||||
clientreply = (struct clvm_header *) replybuf;
|
||||
clientreply->status = -status;
|
||||
clientreply->status = status;
|
||||
clientreply->cmd = CLVMD_CMD_REPLY;
|
||||
clientreply->node[0] = '\0';
|
||||
clientreply->flags = 0;
|
||||
|
||||
ptr = clientreply->args;
|
||||
|
||||
@@ -1397,6 +1502,9 @@ static void send_local_reply(struct local_client *client, int status, int fd)
|
||||
strcpy(ptr, thisreply->node);
|
||||
ptr += strlen(thisreply->node) + 1;
|
||||
|
||||
if (thisreply->status)
|
||||
clientreply->flags |= CLVMD_FLAG_NODEERRS;
|
||||
|
||||
*(int *) ptr = thisreply->status;
|
||||
ptr += sizeof(int);
|
||||
|
||||
@@ -1465,7 +1573,8 @@ 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,
|
||||
hton_clvm(msg);
|
||||
clops->cluster_send_message(message, sizeof(message), NULL,
|
||||
"Error Sending version number");
|
||||
}
|
||||
|
||||
@@ -1477,8 +1586,8 @@ 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);
|
||||
hton_clvm((struct clvm_header *) buf);
|
||||
return clops->cluster_send_message(buf, msglen, csid, errtext);
|
||||
} else {
|
||||
int ptr = 0;
|
||||
|
||||
@@ -1498,6 +1607,15 @@ static int send_message(void *buf, int msglen, char *csid, int fd,
|
||||
|
||||
static int process_work_item(struct lvm_thread_cmd *cmd)
|
||||
{
|
||||
/* If msg is NULL then this is a cleanup request */
|
||||
if (cmd->msg == NULL) {
|
||||
DEBUGLOG("process_work_item: free fd %d\n", cmd->client->fd);
|
||||
close(cmd->client->fd);
|
||||
cmd_client_cleanup(cmd->client);
|
||||
free(cmd->client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!cmd->remote) {
|
||||
DEBUGLOG("process_work_item: local\n");
|
||||
process_local_command(cmd->msg, cmd->msglen, cmd->client,
|
||||
@@ -1517,9 +1635,12 @@ static void *lvm_thread_fn(void *arg)
|
||||
{
|
||||
struct list *cmdl, *tmp;
|
||||
sigset_t ss;
|
||||
int using_gulm = (int)arg;
|
||||
|
||||
/* Don't let anyone else to do work until we are started */
|
||||
pthread_mutex_lock(&lvm_start_mutex);
|
||||
|
||||
DEBUGLOG("LVM thread function started\n");
|
||||
pthread_mutex_lock(&lvm_thread_mutex);
|
||||
|
||||
/* Ignore SIGUSR1 & 2 */
|
||||
sigemptyset(&ss);
|
||||
@@ -1528,8 +1649,10 @@ static void *lvm_thread_fn(void *arg)
|
||||
pthread_sigmask(SIG_BLOCK, &ss, NULL);
|
||||
|
||||
/* Initialise the interface to liblvm */
|
||||
init_lvm();
|
||||
pthread_mutex_unlock(&lvm_thread_mutex);
|
||||
init_lvm(using_gulm);
|
||||
|
||||
/* Allow others to get moving */
|
||||
pthread_mutex_unlock(&lvm_start_mutex);
|
||||
|
||||
/* Now wait for some actual work */
|
||||
for (;;) {
|
||||
@@ -1548,7 +1671,8 @@ static void *lvm_thread_fn(void *arg)
|
||||
pthread_mutex_unlock(&lvm_thread_mutex);
|
||||
|
||||
process_work_item(cmd);
|
||||
free(cmd->msg);
|
||||
if (cmd->msg)
|
||||
free(cmd->msg);
|
||||
free(cmd);
|
||||
|
||||
pthread_mutex_lock(&lvm_thread_mutex);
|
||||
@@ -1565,21 +1689,26 @@ static int add_to_lvmqueue(struct local_client *client, struct clvm_header *msg,
|
||||
|
||||
cmd = malloc(sizeof(struct lvm_thread_cmd));
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
return ENOMEM;
|
||||
|
||||
cmd->msg = malloc(msglen);
|
||||
if (!cmd->msg) {
|
||||
log_error("Unable to allocate buffer space\n");
|
||||
free(cmd);
|
||||
return -1;
|
||||
if (msglen) {
|
||||
cmd->msg = malloc(msglen);
|
||||
if (!cmd->msg) {
|
||||
log_error("Unable to allocate buffer space\n");
|
||||
free(cmd);
|
||||
return -1;
|
||||
}
|
||||
memcpy(cmd->msg, msg, msglen);
|
||||
}
|
||||
else {
|
||||
cmd->msg = NULL;
|
||||
}
|
||||
|
||||
cmd->client = client;
|
||||
cmd->msglen = msglen;
|
||||
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;
|
||||
@@ -1610,6 +1739,8 @@ static int open_local_sock()
|
||||
log_error("Can't create local socket: %m");
|
||||
return -1;
|
||||
}
|
||||
/* Set Close-on-exec */
|
||||
fcntl(local_socket, F_SETFD, 1);
|
||||
|
||||
memset(&sockaddr, 0, sizeof(sockaddr));
|
||||
memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME));
|
||||
@@ -1630,11 +1761,24 @@ 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)
|
||||
{
|
||||
if (!node_up)
|
||||
add_reply_to_list(client, -EHOSTDOWN, csid, "CLVMD not running",
|
||||
add_reply_to_list(client, EHOSTDOWN, csid, "CLVMD not running",
|
||||
18);
|
||||
}
|
||||
|
||||
@@ -1644,7 +1788,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 +1825,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 +1834,20 @@ static void sigterm_handler(int sig)
|
||||
quit = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
static void sighup_handler(int sig)
|
||||
{
|
||||
DEBUGLOG("got SIGHUP\n");
|
||||
reread_config = 1;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@@ -86,6 +86,7 @@ struct local_client {
|
||||
struct local_client *next;
|
||||
unsigned short xid;
|
||||
fd_callback_t callback;
|
||||
uint8_t removeme;
|
||||
|
||||
union {
|
||||
struct localsock_bits localsock;
|
||||
@@ -95,7 +96,7 @@ struct local_client {
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUGLOG(fmt, args...) fprintf(stderr, "CLVMD[%d]: %ld ", getpid(), time(NULL) ); fprintf(stderr, fmt, ## args)
|
||||
#define DEBUGLOG(fmt, args...) {time_t P; time(&P); fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime(&P)+4 ); fprintf(stderr, fmt, ## args);}
|
||||
#else
|
||||
#define DEBUGLOG(fmt, args...)
|
||||
#endif
|
||||
@@ -111,9 +112,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
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
|
@@ -1,446 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved.
|
||||
* 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 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
|
||||
*/
|
||||
|
||||
/* library functions for Cluster LVM Daemon */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <syslog.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <search.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "clvm.h"
|
||||
#include "libclvm.h"
|
||||
|
||||
/* CLVM in hex! */
|
||||
#define LVM_SIGNATURE 0x434C564D
|
||||
|
||||
#define MAX_CLUSTER_MEMBER_NAME_LEN 255
|
||||
|
||||
/* NOTE: the LVMD uses the socket FD as the client ID, this means
|
||||
that any client that calls fork() will inherit the context of
|
||||
it's parent. */
|
||||
static int clvmd_sock = -1;
|
||||
|
||||
static int open_local_sock(void)
|
||||
{
|
||||
int local_socket;
|
||||
struct sockaddr_un sockaddr;
|
||||
|
||||
/* Open local socket */
|
||||
local_socket = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (local_socket < 0) {
|
||||
perror("Can't create local socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fcntl(local_socket, F_SETFD, !FD_CLOEXEC);
|
||||
|
||||
strcpy(sockaddr.sun_path, CLVMD_SOCKNAME);
|
||||
sockaddr.sun_family = AF_UNIX;
|
||||
if (connect
|
||||
(local_socket, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) {
|
||||
int saved_errno = errno;
|
||||
|
||||
close(local_socket);
|
||||
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
return local_socket;
|
||||
}
|
||||
|
||||
/* Send a request and return the status */
|
||||
static int send_request(char *inbuf, int inlen, char **retbuf)
|
||||
{
|
||||
char outbuf[PIPE_BUF];
|
||||
struct clvm_header *outheader = (struct clvm_header *) outbuf;
|
||||
int len;
|
||||
int off;
|
||||
fd_set fds;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(clvmd_sock, &fds);
|
||||
|
||||
/* Send it to CLVMD */
|
||||
if (write(clvmd_sock, inbuf, inlen) != inlen) {
|
||||
perror("Error writing to CLVMD");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the response */
|
||||
if ((len = read(clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) {
|
||||
perror("Error reading CLVMD");
|
||||
return -1;
|
||||
}
|
||||
if (len == 0) {
|
||||
fprintf(stderr, "EOF reading CLVMD");
|
||||
errno = ENOTCONN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allocate buffer */
|
||||
*retbuf = malloc(len + outheader->arglen);
|
||||
if (!*retbuf) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy the header */
|
||||
memcpy(*retbuf, outbuf, len);
|
||||
outheader = (struct clvm_header *) *retbuf;
|
||||
|
||||
/* Read the returned values */
|
||||
off = 1; /* we've already read the first byte */
|
||||
|
||||
while (off < outheader->arglen && len > 0) {
|
||||
len = read(clvmd_sock, outheader->args + off, PIPE_BUF);
|
||||
if (len > 0)
|
||||
off += len;
|
||||
}
|
||||
|
||||
/* Was it an error ? */
|
||||
if (outheader->status < 0) {
|
||||
errno = -outheader->status;
|
||||
return -2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Build the structure header and parse-out wildcard node names */
|
||||
static void build_header(struct clvm_header *head, int cmd, const char *node,
|
||||
void *data, int len)
|
||||
{
|
||||
head->cmd = cmd;
|
||||
head->status = 0;
|
||||
head->flags = 0;
|
||||
head->clientid = 0;
|
||||
head->arglen = len;
|
||||
if (node) {
|
||||
/* Allow a couple of special node names:
|
||||
"*" for all nodes,
|
||||
"." for the local node only
|
||||
*/
|
||||
if (strcmp(node, "*") == 0) {
|
||||
head->node[0] = '\0';
|
||||
} else if (strcmp(node, ".") == 0) {
|
||||
head->node[0] = '\0';
|
||||
head->flags = CLVMD_FLAG_LOCAL;
|
||||
} else {
|
||||
strcpy(head->node, node);
|
||||
}
|
||||
} else {
|
||||
head->node[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Send a message to a(or all) node(s) in the cluster */
|
||||
int lvm_cluster_write(char cmd, char *node, void *data, int len)
|
||||
{
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
|
||||
char *retbuf = NULL;
|
||||
int status;
|
||||
struct clvm_header *head = (struct clvm_header *) outbuf;
|
||||
|
||||
if (clvmd_sock == -1)
|
||||
clvmd_sock = open_local_sock();
|
||||
if (clvmd_sock == -1)
|
||||
return -1;
|
||||
|
||||
build_header(head, cmd, node, data, len);
|
||||
memcpy(head->node + strlen(head->node) + 1, data, len);
|
||||
|
||||
status =
|
||||
send_request(outbuf,
|
||||
sizeof(struct clvm_header) + strlen(head->node) + len,
|
||||
&retbuf);
|
||||
if (retbuf)
|
||||
free(retbuf);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* API: Send a message to a(or all) node(s) in the cluster
|
||||
and wait for replies */
|
||||
int lvm_cluster_request(char cmd, const char *node, void *data, int len,
|
||||
lvm_response_t ** response, int *num)
|
||||
{
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
|
||||
int *outptr;
|
||||
char *inptr;
|
||||
char *retbuf = NULL;
|
||||
int status;
|
||||
int i;
|
||||
int num_responses = 0;
|
||||
struct clvm_header *head = (struct clvm_header *) outbuf;
|
||||
lvm_response_t *rarray;
|
||||
|
||||
*num = 0;
|
||||
|
||||
if (clvmd_sock == -1)
|
||||
clvmd_sock = open_local_sock();
|
||||
if (clvmd_sock == -1)
|
||||
return -1;
|
||||
|
||||
build_header(head, cmd, node, data, len);
|
||||
memcpy(head->node + strlen(head->node) + 1, data, len);
|
||||
|
||||
status =
|
||||
send_request(outbuf,
|
||||
sizeof(struct clvm_header) + strlen(head->node) + len,
|
||||
&retbuf);
|
||||
if (status == 0 || status == -2) {
|
||||
/* Count the number of responses we got */
|
||||
head = (struct clvm_header *) retbuf;
|
||||
inptr = head->args;
|
||||
while (inptr[0]) {
|
||||
num_responses++;
|
||||
inptr += strlen(inptr) + 1;
|
||||
inptr += sizeof(int);
|
||||
inptr += strlen(inptr) + 1;
|
||||
}
|
||||
|
||||
/* Allocate response array. With an extra pair of INTs on the front to sanity
|
||||
check the pointer when we are given it back to free */
|
||||
outptr =
|
||||
malloc(sizeof(lvm_response_t) * num_responses +
|
||||
sizeof(int) * 2);
|
||||
if (!outptr) {
|
||||
if (retbuf)
|
||||
free(retbuf);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*response = (lvm_response_t *) (outptr + 2);
|
||||
outptr[0] = LVM_SIGNATURE;
|
||||
outptr[1] = num_responses;
|
||||
rarray = *response;
|
||||
|
||||
/* Unpack the response into an lvm_response_t array */
|
||||
inptr = head->args;
|
||||
i = 0;
|
||||
while (inptr[0]) {
|
||||
strcpy(rarray[i].node, inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
|
||||
rarray[i].status = *(int *) inptr;
|
||||
inptr += sizeof(int);
|
||||
|
||||
rarray[i].response = malloc(strlen(inptr) + 1);
|
||||
if (rarray[i].response == NULL) {
|
||||
/* Free up everything else and return error */
|
||||
int j;
|
||||
for (j = 0; j < i; j++)
|
||||
free(rarray[i].response);
|
||||
free(outptr);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(rarray[i].response, inptr);
|
||||
rarray[i].len = strlen(inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
i++;
|
||||
}
|
||||
*num = num_responses;
|
||||
*response = rarray;
|
||||
}
|
||||
|
||||
if (retbuf)
|
||||
free(retbuf);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* API: Free reply array */
|
||||
int lvm_cluster_free_request(lvm_response_t * response)
|
||||
{
|
||||
int *ptr = (int *) response - 2;
|
||||
int i;
|
||||
int num;
|
||||
|
||||
/* Check it's ours to free */
|
||||
if (response == NULL || *ptr != LVM_SIGNATURE) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
num = ptr[1];
|
||||
for (i = 0; i < num; i++) {
|
||||
free(response[i].response);
|
||||
}
|
||||
free(ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* These are a "higher-level" API providing black-box lock/unlock
|
||||
functions for cluster LVM...maybe */
|
||||
|
||||
/* Set by lock(), used by unlock() */
|
||||
static int num_responses;
|
||||
static lvm_response_t *response;
|
||||
|
||||
int lvm_lock_for_cluster(char scope, char *name, int verbosity)
|
||||
{
|
||||
int status;
|
||||
int i;
|
||||
char *args;
|
||||
int len;
|
||||
|
||||
if (name) {
|
||||
len = strlen(name) + 2;
|
||||
args = alloca(len);
|
||||
strcpy(args + 1, name);
|
||||
} else {
|
||||
len = 2;
|
||||
args = alloca(len);
|
||||
args[1] = '\0';
|
||||
}
|
||||
args[0] = scope;
|
||||
|
||||
status = lvm_cluster_request(CLVMD_CMD_LOCK,
|
||||
"", args, len, &response, &num_responses);
|
||||
|
||||
/* If any nodes were down then display them and return an error */
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
if (response[i].status == -EHOSTDOWN) {
|
||||
if (verbosity)
|
||||
fprintf(stderr,
|
||||
"clvmd not running on node %s\n",
|
||||
response[i].node);
|
||||
status = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there was an error then free the memory now as the caller won't
|
||||
want to do the unlock */
|
||||
if (status) {
|
||||
int saved_errno = errno;
|
||||
lvm_cluster_free_request(response);
|
||||
num_responses = 0;
|
||||
errno = saved_errno;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int lvm_unlock_for_cluster(char scope, char *name, int verbosity)
|
||||
{
|
||||
int status;
|
||||
int i;
|
||||
int len;
|
||||
int failed;
|
||||
int num_unlock_responses;
|
||||
char *args;
|
||||
lvm_response_t *unlock_response;
|
||||
|
||||
/* We failed - this should not have been called */
|
||||
if (num_responses == 0)
|
||||
return 0;
|
||||
|
||||
if (name) {
|
||||
len = strlen(name) + 2;
|
||||
args = alloca(len);
|
||||
strcpy(args + 1, name);
|
||||
} else {
|
||||
len = 2;
|
||||
args = alloca(len);
|
||||
args[1] = '\0';
|
||||
}
|
||||
args[0] = scope;
|
||||
|
||||
/* See if it failed anywhere */
|
||||
failed = 0;
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
if (response[i].status != 0)
|
||||
failed++;
|
||||
}
|
||||
|
||||
/* If it failed on any nodes then we only unlock on
|
||||
the nodes that succeeded */
|
||||
if (failed) {
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
/* Unlock the ones that succeeded */
|
||||
if (response[i].status == 0) {
|
||||
status = lvm_cluster_request(CLVMD_CMD_UNLOCK,
|
||||
response[i].node,
|
||||
args, len,
|
||||
&unlock_response,
|
||||
&num_unlock_responses);
|
||||
if (status) {
|
||||
if (verbosity)
|
||||
fprintf(stderr,
|
||||
"cluster command to node %s failed: %s\n",
|
||||
response[i].node,
|
||||
strerror(errno));
|
||||
} else if (unlock_response[0].status != 0) {
|
||||
if (verbosity > 1)
|
||||
fprintf(stderr,
|
||||
"unlock on node %s failed: %s\n",
|
||||
response[i].node,
|
||||
strerror(unlock_response
|
||||
[0].status));
|
||||
}
|
||||
lvm_cluster_free_request(unlock_response);
|
||||
} else {
|
||||
if (verbosity)
|
||||
fprintf(stderr,
|
||||
"command on node %s failed: '%s' - will be left locked\n",
|
||||
response[i].node,
|
||||
strerror(response[i].status));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* All OK, we can do a full cluster unlock */
|
||||
status = lvm_cluster_request(CLVMD_CMD_UNLOCK,
|
||||
"",
|
||||
args, len,
|
||||
&unlock_response,
|
||||
&num_unlock_responses);
|
||||
if (status) {
|
||||
if (verbosity > 1)
|
||||
fprintf(stderr, "cluster command failed: %s\n",
|
||||
strerror(errno));
|
||||
} else {
|
||||
for (i = 0; i < num_unlock_responses; i++) {
|
||||
if (unlock_response[i].status != 0) {
|
||||
if (verbosity > 1)
|
||||
fprintf(stderr,
|
||||
"unlock on node %s failed: %s\n",
|
||||
response[i].node,
|
||||
strerror(unlock_response
|
||||
[0].status));
|
||||
}
|
||||
}
|
||||
}
|
||||
lvm_cluster_free_request(unlock_response);
|
||||
}
|
||||
lvm_cluster_free_request(response);
|
||||
|
||||
return 0;
|
||||
}
|
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved.
|
||||
* 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 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 _LIBCLVM_H
|
||||
#define _LIBCLVM_H
|
||||
|
||||
typedef struct lvm_response {
|
||||
char node[255];
|
||||
char *response;
|
||||
int status;
|
||||
int len;
|
||||
|
||||
} lvm_response_t;
|
||||
|
||||
extern int lvm_cluster_request(char cmd, const char *node, void *data, int len,
|
||||
lvm_response_t ** response, int *num);
|
||||
extern int lvm_cluster_write(char cmd, char *node, void *data, int len);
|
||||
extern int lvm_cluster_free_request(lvm_response_t * response);
|
||||
|
||||
/* The "high-level" API */
|
||||
extern int lvm_lock_for_cluster(char scope, char *name, int verbosity);
|
||||
extern int lvm_unlock_for_cluster(char scope, char *name, int verbosity);
|
||||
|
||||
#endif
|
@@ -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) {
|
||||
@@ -375,6 +388,44 @@ int do_check_lvm1(char *vgname)
|
||||
return status == 1 ? 0 : EBUSY;
|
||||
}
|
||||
|
||||
|
||||
/* Only called at gulm startup. Drop any leftover VG or P_orphan locks
|
||||
that might be hanging around if we died for any reason
|
||||
*/
|
||||
static void drop_vg_locks()
|
||||
{
|
||||
char vg[128];
|
||||
char line[255];
|
||||
FILE *vgs =
|
||||
popen
|
||||
("lvm pvs --nolocking --noheadings -o vg_name", "r");
|
||||
|
||||
sync_unlock("P_orphans", LCK_EXCL);
|
||||
|
||||
if (!vgs)
|
||||
return;
|
||||
|
||||
while (fgets(line, sizeof(line), vgs)) {
|
||||
char *vgend;
|
||||
char *vgstart;
|
||||
|
||||
if (line[strlen(line)-1] == '\n')
|
||||
line[strlen(line)-1] = '\0';
|
||||
|
||||
vgstart = line + strspn(line, " ");
|
||||
vgend = vgstart + strcspn(vgstart, " ");
|
||||
*vgend = '\0';
|
||||
|
||||
if (strncmp(vgstart, "WARNING:", 8) == 0)
|
||||
continue;
|
||||
|
||||
sprintf(vg, "V_%s", vgstart);
|
||||
sync_unlock(vg, LCK_EXCL);
|
||||
|
||||
}
|
||||
fclose(vgs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ideally, clvmd should be started before any LVs are active
|
||||
* but this may not be the case...
|
||||
@@ -387,16 +438,18 @@ static void *get_initial_state()
|
||||
char line[255];
|
||||
FILE *lvs =
|
||||
popen
|
||||
("/sbin/lvm lvs --nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr",
|
||||
("lvm lvs --nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr",
|
||||
"r");
|
||||
|
||||
if (!lvs)
|
||||
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);
|
||||
@@ -423,14 +476,39 @@ static void *get_initial_state()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This checks some basic cluster-LVM configuration stuff */
|
||||
static void check_config()
|
||||
{
|
||||
int locking_type;
|
||||
|
||||
locking_type = find_config_int(cmd->cft->root, "global/locking_type", 1);
|
||||
|
||||
if (locking_type == 3) /* compiled-in cluster support */
|
||||
return;
|
||||
|
||||
if (locking_type == 2) { /* External library, check name */
|
||||
const char *libname;
|
||||
|
||||
libname = find_config_str(cmd->cft->root, "global/locking_library",
|
||||
"");
|
||||
if (strstr(libname, "liblvm2clusterlock.so"))
|
||||
return;
|
||||
|
||||
log_error("Incorrect LVM locking library specified in lvm.conf, cluster operations may not work.");
|
||||
return;
|
||||
}
|
||||
log_error("locking_type not set correctly in lvm.conf, cluster operations will not work.");
|
||||
}
|
||||
|
||||
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 */
|
||||
int init_lvm(void)
|
||||
int init_lvm(int using_gulm)
|
||||
{
|
||||
if (!(cmd = create_toolcontext(NULL))) {
|
||||
log_error("Failed to allocate command context");
|
||||
@@ -441,6 +519,13 @@ int init_lvm(void)
|
||||
init_syslog(LOG_DAEMON);
|
||||
init_debug(_LOG_ERR);
|
||||
|
||||
/* Check lvm.conf is setup for cluster-LVM */
|
||||
check_config();
|
||||
|
||||
/* Remove any non-LV locks that may have been left around */
|
||||
if (using_gulm)
|
||||
drop_vg_locks();
|
||||
|
||||
get_initial_state();
|
||||
|
||||
return 1;
|
||||
|
@@ -25,7 +25,7 @@ extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern int do_check_lvm1(char *vgname);
|
||||
extern int init_lvm(void);
|
||||
extern int init_lvm(int using_gulm);
|
||||
extern void init_lvhash(void);
|
||||
|
||||
extern int hold_unlock(char *resource);
|
||||
|
@@ -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
|
||||
|
@@ -2,6 +2,7 @@
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 2002-2003 All rights reserved.
|
||||
** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
@@ -34,7 +35,6 @@
|
||||
#include <netdb.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "ccs.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
@@ -47,43 +47,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)
|
||||
{
|
||||
@@ -93,13 +69,16 @@ int init_comms()
|
||||
{
|
||||
int one = 1;
|
||||
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
|
||||
setsockopt(listen_fd, SOL_SOCKET, SO_KEEPALIVE, &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;
|
||||
@@ -107,6 +86,9 @@ int init_comms()
|
||||
|
||||
listen(listen_fd, 5);
|
||||
|
||||
/* Set Close-on-exec */
|
||||
fcntl(listen_fd, F_SETFD, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -119,19 +101,21 @@ 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);
|
||||
client->removeme = 1;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
client->removeme = 1;
|
||||
}
|
||||
|
||||
/* Put it back as we found it */
|
||||
@@ -142,7 +126,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 +144,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 +157,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 +167,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 +202,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,18 +232,39 @@ 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);
|
||||
struct clvm_header *header = (struct clvm_header *)buf;
|
||||
int status;
|
||||
uint32_t arglen;
|
||||
|
||||
DEBUGLOG("read_from_tcpsock fd %d\n", client->fd);
|
||||
*new_client = NULL;
|
||||
|
||||
/* 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);
|
||||
/* Read just the header first, then get the rest if there is any.
|
||||
* Stream sockets, sigh.
|
||||
*/
|
||||
status = read(client->fd, buf, sizeof(struct clvm_header));
|
||||
if (status > 0)
|
||||
{
|
||||
int status2;
|
||||
|
||||
arglen = ntohl(header->arglen);
|
||||
|
||||
/* Get the rest */
|
||||
if (arglen && arglen < GULM_MAX_CLUSTER_MESSAGE)
|
||||
{
|
||||
status2 = read(client->fd, buf+status, arglen);
|
||||
if (status2 > 0)
|
||||
status += status2;
|
||||
else
|
||||
status = status2;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUGLOG("read_from_tcpsock, status = %d(errno = %d)\n", status, errno);
|
||||
|
||||
@@ -270,30 +273,36 @@ 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 {
|
||||
gulm_add_up_node(csid);
|
||||
/* Send it back to clvmd */
|
||||
process_message(client, buf, status, csid);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int connect_csid(char *csid, struct local_client **newclient)
|
||||
int gulm_connect_csid(char *csid, struct local_client **newclient)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in addr;
|
||||
struct sockaddr_in6 addr;
|
||||
int status;
|
||||
int one = 1;
|
||||
|
||||
DEBUGLOG("Connecting socket\n");
|
||||
fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
fd = socket(PF_INET6, SOCK_STREAM, 0);
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
@@ -301,19 +310,29 @@ 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");
|
||||
/* "Connection refused" is "normal" because clvmd may not yet be running
|
||||
* on that node.
|
||||
*/
|
||||
if (errno != ECONNREFUSED)
|
||||
{
|
||||
syslog(LOG_ERR, "Unable to connect to remote node: %m");
|
||||
}
|
||||
DEBUGLOG("Unable to connect to remote node: %s\n", strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set Close-on-exec */
|
||||
fcntl(fd, F_SETFD, 1);
|
||||
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(int));
|
||||
|
||||
status = alloc_client(fd, csid, newclient);
|
||||
if (status)
|
||||
close(fd);
|
||||
@@ -321,7 +340,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,21 +349,21 @@ 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);
|
||||
status = gulm_connect_csid(csid, &client);
|
||||
if (status)
|
||||
return -1;
|
||||
}
|
||||
@@ -354,7 +373,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 +383,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 +402,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 +432,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 +448,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 +456,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;
|
||||
}
|
||||
|
@@ -1,7 +1,13 @@
|
||||
#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);
|
||||
int gulm_connect_csid(char *csid, struct local_client **newclient);
|
||||
|
3
daemons/dmeventd/.exported_symbols
Normal file
3
daemons/dmeventd/.exported_symbols
Normal file
@@ -0,0 +1,3 @@
|
||||
process_event
|
||||
register_device
|
||||
unregister_device
|
51
daemons/dmeventd/Makefile.in
Normal file
51
daemons/dmeventd/Makefile.in
Normal file
@@ -0,0 +1,51 @@
|
||||
#
|
||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
# Copyright (C) 2004 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
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
TARGETS = dmevent dmeventd
|
||||
INSTALL_TYPE = install_dynamic
|
||||
|
||||
SOURCES = noop.c
|
||||
CLEAN_TARGETS = dmevent
|
||||
|
||||
ifeq ("@LIB_SUFFIX@","dylib")
|
||||
LIB_SHARED = libdmeventnoop.dylib
|
||||
else
|
||||
LIB_SHARED = libdmeventnoop.so
|
||||
endif
|
||||
|
||||
LDFLAGS += -ldl -ldevmapper -lpthread
|
||||
|
||||
include ../make.tmpl
|
||||
|
||||
libdmeventnoop.so: noop.o
|
||||
|
||||
dmevent: dmevent.o $(interfacedir)/libdevmapper.$(LIB_SUFFIX) $(top_srcdir)/lib/event/libdmevent.$(LIB_SUFFIX)
|
||||
$(CC) -o $@ dmevent.o $(LDFLAGS) \
|
||||
-L$(interfacedir) -L$(DESTDIR)/lib -L$(top_srcdir)/lib/event -L$(top_srcdir)/multilog -lmultilog -ldmevent $(LIBS)
|
||||
|
||||
dmeventd: dmeventd.o $(interfacedir)/libdevmapper.$(LIB_SUFFIX) $(top_srcdir)/lib/event/libdmevent.$(LIB_SUFFIX)
|
||||
$(CC) -o $@ dmeventd.o $(LDFLAGS) \
|
||||
-L$(interfacedir) -L$(DESTDIR)/lib -L$(top_srcdir)/lib/event -L$(top_srcdir)/multilog -ldmevent -lmultilog $(LIBS)
|
||||
|
||||
install: $(INSTALL_TYPE)
|
||||
|
||||
.PHONY: install_dynamic
|
||||
|
||||
install_dynamic: dmeventd
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) dmeventd $(sbindir)/dmeventd
|
||||
|
137
daemons/dmeventd/dmevent.c
Normal file
137
daemons/dmeventd/dmevent.c
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "libdm-event.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static enum event_type events = ALL_ERRORS; /* All until we can distinguish. */
|
||||
static char *default_dso_name = "noop"; /* default DSO is noop */
|
||||
static int default_reg = 1; /* default action is register */
|
||||
|
||||
/* Display help. */
|
||||
static void print_usage(char *name)
|
||||
{
|
||||
char *cmd = strrchr(name, '/');
|
||||
|
||||
cmd = cmd ? cmd + 1 : name;
|
||||
printf("Usage::\n"
|
||||
"%s [options] <device>\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -d <dso> Specify the DSO to use.\n"
|
||||
" -h Print this usage.\n"
|
||||
" -l List registered devices.\n"
|
||||
" -r Register for event (default).\n"
|
||||
" -u Unregister for event.\n"
|
||||
"\n", cmd);
|
||||
}
|
||||
|
||||
/* Parse command line arguments. */
|
||||
static int parse_argv(int argc, char **argv,
|
||||
char **dso_name, char **device, int *reg, int *list)
|
||||
{
|
||||
int c;
|
||||
const char *options = "d:hlru";
|
||||
|
||||
while ((c = getopt(argc, argv, options)) != -1) {
|
||||
switch (c) {
|
||||
case 'd':
|
||||
*dso_name = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
print_usage(argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'l':
|
||||
*list = 1;
|
||||
break;
|
||||
case 'r':
|
||||
*reg = 1;
|
||||
break;
|
||||
case 'u':
|
||||
*reg = 0;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown option '%c'.\n"
|
||||
"Try '-h' for help.\n", c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!*list) {
|
||||
if (optind >= argc) {
|
||||
fprintf(stderr, "You need to specify a device.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
*device = argv[optind];
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int list = 0, ret, reg = default_reg;
|
||||
char *device, *dso_name = default_dso_name;
|
||||
|
||||
if (!parse_argv(argc, argv, &dso_name, &device, ®, &list))
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (list) {
|
||||
do {
|
||||
ret = dm_get_next_registered_device(&dso_name, &device, &events);
|
||||
if (!ret) {
|
||||
printf("%s %s 0x%x\n", dso_name, device, events);
|
||||
free(dso_name);
|
||||
free(device);
|
||||
}
|
||||
} while (ret);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
if ((ret = reg ? dm_register_for_event(dso_name, device, events) :
|
||||
dm_unregister_for_event(dso_name, device, events))) {
|
||||
fprintf(stderr, "Failed to %sregister %s: %s\n",
|
||||
reg ? "": "un", device, strerror(-ret));
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("%s %sregistered successfully.\n", device, reg ? "" : "un");
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
1021
daemons/dmeventd/dmeventd.c
Normal file
1021
daemons/dmeventd/dmeventd.c
Normal file
File diff suppressed because it is too large
Load Diff
12
daemons/dmeventd/mktestdevices
Normal file
12
daemons/dmeventd/mktestdevices
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Create test devices for dmeventd
|
||||
#
|
||||
|
||||
trap "rm -f /tmp/tmp.$$" 0 1 2 3 15
|
||||
|
||||
echo "0 1024 zero" > /tmp/tmp.$$
|
||||
dmsetup create test /tmp/tmp.$$
|
||||
dmsetup create test1 /tmp/tmp.$$
|
||||
|
||||
kill -15 $$
|
39
daemons/dmeventd/noop.c
Normal file
39
daemons/dmeventd/noop.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "libdm-event.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void process_event(char *device, enum event_type event)
|
||||
{
|
||||
fprintf(stderr, "[%s] %s(%d) - Device: %s, Event %d\n",
|
||||
__FILE__, __func__, __LINE__, device, event);
|
||||
}
|
||||
|
||||
int register_device(char *device)
|
||||
{
|
||||
fprintf(stderr, "[%s] %s(%d) - Device: %s\n",
|
||||
__FILE__, __func__, __LINE__, device);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int unregister_device(char *device)
|
||||
{
|
||||
fprintf(stderr, "[%s] %s(%d) - Device: %s\n",
|
||||
__FILE__, __func__, __LINE__, device);
|
||||
|
||||
return 1;
|
||||
}
|
@@ -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).
|
||||
|
||||
@@ -252,11 +258,10 @@ activation {
|
||||
#
|
||||
# metadata {
|
||||
# Default number of copies of metadata to hold on each PV. 0, 1 or 2.
|
||||
# It's best to leave this at 2.
|
||||
# You might want to override it from the command line with 0 or 1
|
||||
# You might want to override it from the command line with 0
|
||||
# when running pvcreate on new PVs which are to be added to large VGs.
|
||||
|
||||
# pvmetadatacopies = 2
|
||||
# pvmetadatacopies = 1
|
||||
|
||||
# Approximate default size of on-disk metadata areas in sectors.
|
||||
# You should increase this if you have large volume groups or
|
||||
|
165
doc/tagging.txt
Normal file
165
doc/tagging.txt
Normal 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'
|
||||
|
@@ -31,7 +31,8 @@
|
||||
../lib/log/log.h
|
||||
../lib/metadata/lv_alloc.h
|
||||
../lib/metadata/metadata.h
|
||||
../lib/metadata/segtypes.h
|
||||
../lib/metadata/pv_alloc.h
|
||||
../lib/metadata/segtype.h
|
||||
../lib/mm/dbg_malloc.h
|
||||
../lib/mm/memlock.h
|
||||
../lib/mm/pool.h
|
||||
@@ -47,3 +48,4 @@
|
||||
../lib/report/report.h
|
||||
../lib/uuid/uuid.h
|
||||
../po/pogen.h
|
||||
../tools/version.h
|
||||
|
@@ -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 \
|
||||
@@ -69,12 +70,14 @@ SOURCES =\
|
||||
metadata/merge.c \
|
||||
metadata/metadata.c \
|
||||
metadata/mirror.c \
|
||||
metadata/pv_manip.c \
|
||||
metadata/pv_map.c \
|
||||
metadata/segtypes.c \
|
||||
metadata/segtype.c \
|
||||
metadata/snapshot_manip.c \
|
||||
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 +123,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 \
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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.
|
||||
|
@@ -21,7 +21,7 @@
|
||||
#include "lvm-string.h"
|
||||
#include "fs.h"
|
||||
#include "defaults.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
#include "display.h"
|
||||
#include "toolcontext.h"
|
||||
#include "targets.h"
|
||||
@@ -165,89 +165,6 @@ static inline void _clear_flag(struct dev_layer *dl, int bit)
|
||||
dl->flags &= ~(1 << bit);
|
||||
}
|
||||
|
||||
/*
|
||||
* Device layer names are all of the form <vg>-<lv>-<layer>, any
|
||||
* other hyphens that appear in these names are quoted with yet
|
||||
* another hyphen. The top layer of any device has no layer
|
||||
* name. eg, vg0-lvol0.
|
||||
*/
|
||||
static void _count_hyphens(const char *str, size_t *len, int *hyphens)
|
||||
{
|
||||
const char *ptr;
|
||||
|
||||
for (ptr = str; *ptr; ptr++, (*len)++)
|
||||
if (*ptr == '-')
|
||||
(*hyphens)++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copies a string, quoting hyphens with hyphens.
|
||||
*/
|
||||
static void _quote_hyphens(char **out, const char *src)
|
||||
{
|
||||
while (*src) {
|
||||
if (*src == '-')
|
||||
*(*out)++ = '-';
|
||||
|
||||
*(*out)++ = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* <vg>-<lv>-<layer> or if !layer just <vg>-<lv>.
|
||||
*/
|
||||
static char *_build_name(struct pool *mem, const char *vg,
|
||||
const char *lv, const char *layer)
|
||||
{
|
||||
size_t len = 0;
|
||||
int hyphens = 0;
|
||||
char *r, *out;
|
||||
|
||||
_count_hyphens(vg, &len, &hyphens);
|
||||
_count_hyphens(lv, &len, &hyphens);
|
||||
|
||||
if (layer && *layer)
|
||||
_count_hyphens(layer, &len, &hyphens);
|
||||
|
||||
len += hyphens + 2;
|
||||
|
||||
if (!(r = pool_alloc(mem, len))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out = r;
|
||||
_quote_hyphens(&out, vg);
|
||||
*out++ = '-';
|
||||
_quote_hyphens(&out, lv);
|
||||
|
||||
if (layer && *layer) {
|
||||
*out++ = '-';
|
||||
_quote_hyphens(&out, layer);
|
||||
}
|
||||
*out = '\0';
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Find start of LV component in hyphenated name */
|
||||
static char *_find_lv_name(char *vg)
|
||||
{
|
||||
char *c = vg;
|
||||
|
||||
while (*c && *(c + 1)) {
|
||||
if (*c == '-') {
|
||||
if (*(c + 1) == '-')
|
||||
c++;
|
||||
else
|
||||
return (c + 1);
|
||||
}
|
||||
c++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *_build_dlid(struct pool *mem, const char *lvid, const char *layer)
|
||||
{
|
||||
char *dlid;
|
||||
@@ -294,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;
|
||||
@@ -308,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;
|
||||
@@ -333,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;
|
||||
}
|
||||
@@ -362,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;
|
||||
@@ -440,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;
|
||||
@@ -519,10 +450,16 @@ static int _percent(struct dev_manager *dm, const char *name, const char *uuid,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _rename(struct dev_layer *dl, char *newname)
|
||||
static int _rename(struct dev_manager *dm, struct dev_layer *dl, char *newname)
|
||||
{
|
||||
int r = 1;
|
||||
struct dm_task *dmt;
|
||||
char *vgname, *lvname, *layer;
|
||||
|
||||
if (!split_dm_name(dm->mem, dl->name, &vgname, &lvname, &layer)) {
|
||||
log_error("Couldn't split up dm layer name %s", dl->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_verbose("Renaming %s to %s", dl->name, newname);
|
||||
|
||||
@@ -537,11 +474,16 @@ static int _rename(struct dev_layer *dl, char *newname)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(r = dm_task_run(dmt)))
|
||||
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;
|
||||
}
|
||||
|
||||
if (r && _get_flag(dl, VISIBLE))
|
||||
fs_rename_lv(dl->lv, newname, _find_lv_name(dl->name));
|
||||
fs_rename_lv(dl->lv, newname, lvname);
|
||||
|
||||
dl->name = newname;
|
||||
|
||||
@@ -563,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);
|
||||
@@ -654,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) &&
|
||||
@@ -710,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);
|
||||
|
||||
@@ -776,6 +727,25 @@ static int _emit_target_line(struct dev_manager *dm, struct dm_task *dmt,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int compose_log_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
char *params, size_t paramsize, int *pos, int areas,
|
||||
uint32_t region_size)
|
||||
{
|
||||
int tw;
|
||||
|
||||
tw = lvm_snprintf(params, paramsize, "core 1 %u %u ",
|
||||
region_size, areas);
|
||||
|
||||
if (tw < 0) {
|
||||
stack;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*pos += tw;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
char *params, size_t paramsize, int *pos, int start_area,
|
||||
int areas)
|
||||
@@ -924,21 +894,23 @@ static int _populate_snapshot(struct dev_manager *dm,
|
||||
{
|
||||
char *origin, *cow;
|
||||
char params[PATH_MAX * 2 + 32];
|
||||
struct snapshot *s;
|
||||
struct lv_segment *snap_seg;
|
||||
struct dev_layer *dlo, *dlc;
|
||||
char devbufo[10], devbufc[10];
|
||||
uint64_t size;
|
||||
|
||||
if (!(s = find_cow(dl->lv))) {
|
||||
if (!(snap_seg = find_cow(dl->lv))) {
|
||||
log_error("Couldn't find snapshot for '%s'.", dl->lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(origin = _build_dlid(dm->mem, s->origin->lvid.s, "real"))) {
|
||||
if (!(origin = _build_dlid(dm->mem, snap_seg->origin->lvid.s,
|
||||
"real"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cow = _build_dlid(dm->mem, s->cow->lvid.s, "cow"))) {
|
||||
if (!(cow = _build_dlid(dm->mem, snap_seg->cow->lvid.s, "cow"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -957,27 +929,27 @@ static int _populate_snapshot(struct dev_manager *dm,
|
||||
if (!dm_format_dev(devbufo, sizeof(devbufo), dlo->info.major,
|
||||
dlo->info.minor)) {
|
||||
log_error("Couldn't create origin device parameters for '%s'.",
|
||||
s->origin->name);
|
||||
snap_seg->origin->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dm_format_dev(devbufc, sizeof(devbufc), dlc->info.major,
|
||||
dlc->info.minor)) {
|
||||
log_error("Couldn't create cow device parameters for '%s'.",
|
||||
s->cow->name);
|
||||
snap_seg->cow->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(params, sizeof(params), "%s %s P %d",
|
||||
devbufo, devbufc, s->chunk_size) == -1) {
|
||||
devbufo, devbufc, snap_seg->chunk_size) == -1) {
|
||||
stack;
|
||||
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) snap_seg->len * snap_seg->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;
|
||||
}
|
||||
@@ -994,7 +966,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;
|
||||
}
|
||||
@@ -1045,14 +1017,14 @@ 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;
|
||||
|
||||
/*
|
||||
* Build a name for the top layer.
|
||||
*/
|
||||
if (!(name = _build_name(dm->mem, lv->vg->name, lv->name, NULL))) {
|
||||
if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1061,7 +1033,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;
|
||||
}
|
||||
@@ -1077,7 +1050,7 @@ int dev_manager_snapshot_percent(struct dev_manager *dm,
|
||||
/*
|
||||
* Build a name for the top layer.
|
||||
*/
|
||||
if (!(name = _build_name(dm->mem, lv->vg->name, lv->name, NULL))) {
|
||||
if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1109,7 +1082,7 @@ int dev_manager_mirror_percent(struct dev_manager *dm,
|
||||
/*
|
||||
* Build a name for the top layer.
|
||||
*/
|
||||
if (!(name = _build_name(dm->mem, lv->vg->name, lv->name, NULL))) {
|
||||
if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1140,7 +1113,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;
|
||||
}
|
||||
@@ -1173,7 +1146,7 @@ static struct dev_layer *_create_layer(struct dev_manager *dm,
|
||||
char *name, *dlid;
|
||||
struct dev_layer *dl;
|
||||
|
||||
if (!(name = _build_name(dm->mem, lv->vg->name, lv->name, layer))) {
|
||||
if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, layer))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
@@ -1321,7 +1294,7 @@ static int _expand_origin_real(struct dev_manager *dm,
|
||||
static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv)
|
||||
{
|
||||
struct logical_volume *active;
|
||||
struct snapshot *s;
|
||||
struct lv_segment *snap_seg;
|
||||
struct list *sh;
|
||||
|
||||
/*
|
||||
@@ -1330,7 +1303,7 @@ static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv)
|
||||
*/
|
||||
list_iterate(sh, &dm->active_list) {
|
||||
active = list_item(sh, struct lv_list)->lv;
|
||||
if ((s = find_cow(active)) && (s->origin == lv))
|
||||
if ((snap_seg = find_cow(active)) && (snap_seg->origin == lv))
|
||||
return _expand_origin_real(dm, lv);
|
||||
}
|
||||
|
||||
@@ -1341,7 +1314,7 @@ static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv)
|
||||
}
|
||||
|
||||
static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv,
|
||||
struct snapshot *s)
|
||||
struct lv_segment *snap_seg)
|
||||
{
|
||||
/*
|
||||
* snapshot(org, cow)
|
||||
@@ -1378,13 +1351,15 @@ static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv,
|
||||
|
||||
/* add the dependency on the real origin device */
|
||||
if (!str_list_add(dm->mem, &dl->pre_create,
|
||||
_build_dlid(dm->mem, s->origin->lvid.s, "real"))) {
|
||||
_build_dlid(dm->mem, snap_seg->origin->lvid.s,
|
||||
"real"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* add the dependency on the visible origin device */
|
||||
if (!str_list_add(dm->mem, &dl->pre_suspend, s->origin->lvid.s)) {
|
||||
if (!str_list_add(dm->mem, &dl->pre_suspend,
|
||||
snap_seg->origin->lvid.s)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1397,13 +1372,13 @@ static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv,
|
||||
*/
|
||||
static int _expand_lv(struct dev_manager *dm, struct logical_volume *lv)
|
||||
{
|
||||
struct snapshot *s;
|
||||
struct lv_segment *snap_seg;
|
||||
|
||||
/*
|
||||
* FIXME: this doesn't cope with recursive snapshots yet.
|
||||
*/
|
||||
if ((s = find_cow(lv)))
|
||||
return _expand_snapshot(dm, lv, s);
|
||||
if ((snap_seg = find_cow(lv)))
|
||||
return _expand_snapshot(dm, lv, snap_seg);
|
||||
|
||||
else if (lv_is_origin(lv))
|
||||
return _expand_origin(dm, lv);
|
||||
@@ -1492,6 +1467,8 @@ static int _mark_lvs(struct dev_manager *dm, struct list *lvs, int flag)
|
||||
|
||||
list_iterate(lvh, lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if (lv->status & SNAPSHOT)
|
||||
continue;
|
||||
|
||||
if (!(dl = _lookup(dm, lv->lvid.s, NULL))) {
|
||||
stack;
|
||||
@@ -1618,11 +1595,11 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl)
|
||||
if (dl->info.exists) {
|
||||
if ((suffix = rindex(dl->dlid, '-')))
|
||||
suffix++;
|
||||
newname = _build_name(dm->mem, dm->vg_name, dl->lv->name,
|
||||
suffix);
|
||||
newname = build_dm_name(dm->mem, dm->vg_name, dl->lv->name,
|
||||
suffix);
|
||||
if (strcmp(newname, dl->name)) {
|
||||
if (!_suspend_parents(dm, dl) ||
|
||||
!_suspend(dl) || !_rename(dl, newname)) {
|
||||
!_suspend(dl) || !_rename(dm, dl, newname)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1653,14 +1630,16 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl)
|
||||
static int _build_all_layers(struct dev_manager *dm, struct volume_group *vg)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lvt;
|
||||
struct logical_volume *lv;
|
||||
|
||||
/*
|
||||
* Build layers for complete vg.
|
||||
*/
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lvt = list_item(lvh, struct lv_list)->lv;
|
||||
if (!_expand_lv(dm, lvt)) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if (lv->status & SNAPSHOT)
|
||||
continue;
|
||||
if (!_expand_lv(dm, lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1962,12 +1941,14 @@ static int _add_lvs(struct pool *mem,
|
||||
struct list *head, struct logical_volume *origin)
|
||||
{
|
||||
struct logical_volume *lv;
|
||||
struct snapshot *s;
|
||||
struct lv_segment *snap_seg;
|
||||
struct list *lvh;
|
||||
|
||||
list_iterate(lvh, &origin->vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if ((s = find_cow(lv)) && s->origin == origin)
|
||||
if (lv->status & SNAPSHOT)
|
||||
continue;
|
||||
if ((snap_seg = find_cow(lv)) && snap_seg->origin == origin)
|
||||
if (!_add_lv(mem, head, lv))
|
||||
return 0;
|
||||
}
|
||||
@@ -1992,7 +1973,7 @@ static void _remove_lv(struct list *head, struct logical_volume *lv)
|
||||
static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv)
|
||||
{
|
||||
struct logical_volume *active, *old_origin;
|
||||
struct snapshot *s;
|
||||
struct lv_segment *snap_seg;
|
||||
struct list *sh, *active_head;
|
||||
|
||||
active_head = &dm->active_list;
|
||||
@@ -2000,22 +1981,23 @@ static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv)
|
||||
/* Remove any snapshots with given origin */
|
||||
list_iterate(sh, active_head) {
|
||||
active = list_item(sh, struct lv_list)->lv;
|
||||
if ((s = find_cow(active)) && s->origin == lv) {
|
||||
if ((snap_seg = find_cow(active)) && snap_seg->origin == lv) {
|
||||
_remove_lv(active_head, active);
|
||||
}
|
||||
}
|
||||
|
||||
_remove_lv(active_head, lv);
|
||||
|
||||
if (!(s = find_cow(lv)))
|
||||
if (!(snap_seg = find_cow(lv)))
|
||||
return 1;
|
||||
|
||||
old_origin = s->origin;
|
||||
old_origin = snap_seg->origin;
|
||||
|
||||
/* Was this the last active snapshot with this origin? */
|
||||
list_iterate(sh, active_head) {
|
||||
active = list_item(sh, struct lv_list)->lv;
|
||||
if ((s = find_cow(active)) && s->origin == old_origin) {
|
||||
if ((snap_seg = find_cow(active)) &&
|
||||
snap_seg->origin == old_origin) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -2027,7 +2009,7 @@ static int _remove_suspended_lvs(struct dev_manager *dm,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
struct logical_volume *suspended;
|
||||
struct snapshot *s;
|
||||
struct lv_segment *snap_seg;
|
||||
struct list *sh, *suspend_head;
|
||||
|
||||
suspend_head = &dm->suspend_list;
|
||||
@@ -2035,7 +2017,8 @@ static int _remove_suspended_lvs(struct dev_manager *dm,
|
||||
/* Remove from list any snapshots with given origin */
|
||||
list_iterate(sh, suspend_head) {
|
||||
suspended = list_item(sh, struct lv_list)->lv;
|
||||
if ((s = find_cow(suspended)) && s->origin == lv) {
|
||||
if ((snap_seg = find_cow(suspended)) &&
|
||||
snap_seg->origin == lv) {
|
||||
_remove_lv(suspend_head, suspended);
|
||||
}
|
||||
}
|
||||
@@ -2121,6 +2104,8 @@ static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg)
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if (lv->status & SNAPSHOT)
|
||||
continue;
|
||||
|
||||
if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, NULL))) {
|
||||
stack;
|
||||
@@ -2227,8 +2212,8 @@ int dev_manager_lv_mknodes(const struct logical_volume *lv)
|
||||
{
|
||||
char *name;
|
||||
|
||||
if (!(name = _build_name(lv->vg->cmd->mem, lv->vg->name,
|
||||
lv->name, NULL))) {
|
||||
if (!(name = build_dm_name(lv->vg->cmd->mem, lv->vg->name,
|
||||
lv->name, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
@@ -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,
|
||||
|
@@ -46,7 +46,7 @@ static int _mk_dir(const char *dev_dir, const char *vg_name)
|
||||
return 1;
|
||||
|
||||
log_very_verbose("Creating directory %s", vg_path);
|
||||
if (mkdir(vg_path, 0555)) {
|
||||
if (mkdir(vg_path, 0777)) {
|
||||
log_sys_error("mkdir", vg_path);
|
||||
return 0;
|
||||
}
|
||||
@@ -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 (dir_exists(vg_path) && 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;
|
||||
}
|
||||
|
||||
|
@@ -19,7 +19,12 @@
|
||||
struct dev_manager;
|
||||
struct lv_segment;
|
||||
|
||||
int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg, char *params, size_t paramsize, int *pos,
|
||||
int start_area, int areas);
|
||||
int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
char *params, size_t paramsize, int *pos,
|
||||
int start_area, int areas);
|
||||
|
||||
int compose_log_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
char *params, size_t paramsize, int *pos, int areas,
|
||||
uint32_t region_size);
|
||||
|
||||
#endif
|
||||
|
29
lib/cache/lvmcache.c
vendored
29
lib/cache/lvmcache.c
vendored
@@ -104,10 +104,30 @@ struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname)
|
||||
const struct format_type *fmt_from_vgname(const char *vgname)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct label *label;
|
||||
struct list *ih, *devh, *tmp;
|
||||
struct list devs;
|
||||
struct device_list *devl;
|
||||
|
||||
if (!(vginfo = vginfo_from_vgname(vgname)))
|
||||
return NULL;
|
||||
|
||||
/* This function is normally called before reading metadata so
|
||||
* we check cached labels here. Unfortunately vginfo is volatile. */
|
||||
list_init(&devs);
|
||||
list_iterate(ih, &vginfo->infos) {
|
||||
devl = malloc(sizeof(*devl));
|
||||
devl->dev = list_item(ih, struct lvmcache_info)->dev;
|
||||
list_add(&devs, &devl->list);
|
||||
}
|
||||
|
||||
list_iterate_safe(devh, tmp, &devs) {
|
||||
devl = list_item(devh, struct device_list);
|
||||
label_read(devl->dev, &label);
|
||||
list_del(&devl->list);
|
||||
free(devl);
|
||||
}
|
||||
|
||||
return vginfo->fmt;
|
||||
}
|
||||
|
||||
@@ -188,7 +208,7 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(iter = dev_iter_create(cmd->filter))) {
|
||||
if (!(iter = dev_iter_create(cmd->filter, (full_scan == 2) ? 1: 0))) {
|
||||
log_error("dev_iter creation failed");
|
||||
goto out;
|
||||
}
|
||||
@@ -266,7 +286,7 @@ struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
|
||||
if (memlock())
|
||||
return NULL;
|
||||
|
||||
lvmcache_label_scan(cmd, 1);
|
||||
lvmcache_label_scan(cmd, 2);
|
||||
|
||||
/* Try again */
|
||||
if ((info = info_from_pvid((char *) pvid))) {
|
||||
@@ -403,6 +423,9 @@ int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
|
||||
/* FIXME Check consistency of list! */
|
||||
vginfo->fmt = info->fmt;
|
||||
|
||||
log_debug("lvmcache: %s now %s%s", dev_name(info->dev),
|
||||
*vgname ? "in VG " : "orphaned", vgname);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -551,6 +574,8 @@ static void _lvmcache_destroy_lockname(int present)
|
||||
|
||||
void lvmcache_destroy(void)
|
||||
{
|
||||
log_verbose("Wiping internal VG cache");
|
||||
|
||||
_has_scanned = 0;
|
||||
|
||||
if (_vgid_hash) {
|
||||
|
6
lib/cache/lvmcache.h
vendored
6
lib/cache/lvmcache.h
vendored
@@ -36,9 +36,10 @@ struct volume_group;
|
||||
struct lvmcache_vginfo {
|
||||
struct list list; /* Join these vginfos together */
|
||||
struct list infos; /* List head for lvmcache_infos */
|
||||
const struct format_type *fmt;
|
||||
char *vgname; /* "" == orphan */
|
||||
char vgid[ID_LEN + 1];
|
||||
const struct format_type *fmt;
|
||||
char _padding[7];
|
||||
};
|
||||
|
||||
struct lvmcache_info {
|
||||
@@ -56,7 +57,8 @@ struct lvmcache_info {
|
||||
int lvmcache_init(void);
|
||||
void lvmcache_destroy(void);
|
||||
|
||||
/* Set full_scan to 1 to reread every filtered device label */
|
||||
/* Set full_scan to 1 to reread every filtered device label or
|
||||
* 2 to rescan /dev for new devices */
|
||||
int lvmcache_label_scan(struct cmd_context *cmd, int full_scan);
|
||||
|
||||
/* Add/delete a device */
|
||||
|
@@ -33,7 +33,7 @@
|
||||
#include "display.h"
|
||||
#include "memlock.h"
|
||||
#include "str_list.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
#include "lvmcache.h"
|
||||
|
||||
#ifdef HAVE_LIBDL
|
||||
@@ -181,6 +181,12 @@ static int _process_config(struct cmd_context *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*cmd->proc_dir && !dir_exists(cmd->proc_dir)) {
|
||||
log_error("Warning: proc dir %s not found - some checks will be bypassed",
|
||||
cmd->proc_dir);
|
||||
cmd->proc_dir[0] = '\0';
|
||||
}
|
||||
|
||||
/* activation? */
|
||||
cmd->default_settings.activation = find_config_int(cmd->cft->root,
|
||||
"global/activation",
|
||||
@@ -519,8 +525,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 +543,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++;
|
||||
}
|
||||
@@ -824,10 +831,15 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
|
||||
goto error;
|
||||
|
||||
/* Create system directory if it doesn't already exist */
|
||||
if (*cmd->sys_dir && !create_dir(cmd->sys_dir))
|
||||
if (*cmd->sys_dir && !create_dir(cmd->sys_dir)) {
|
||||
log_error("Failed to create LVM2 system dir for metadata backups, config "
|
||||
"files and internal cache.");
|
||||
log_error("Set environment variable LVM_SYSTEM_DIR to alternative location "
|
||||
"or empty string.");
|
||||
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 +870,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;
|
||||
}
|
||||
|
@@ -32,17 +32,15 @@ struct config_info {
|
||||
int syslog;
|
||||
int activation;
|
||||
int suffix;
|
||||
uint64_t unit_factor;
|
||||
char unit_type;
|
||||
const char *msg_prefix;
|
||||
int cmd_name; /* Show command name? */
|
||||
|
||||
int archive; /* should we archive ? */
|
||||
int backup; /* should we backup ? */
|
||||
|
||||
const char *msg_prefix;
|
||||
struct format_type *fmt;
|
||||
|
||||
uint64_t unit_factor;
|
||||
int cmd_name; /* Show command name? */
|
||||
mode_t umask;
|
||||
char unit_type;
|
||||
char _padding[1];
|
||||
};
|
||||
|
||||
struct config_tree;
|
||||
|
@@ -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;
|
||||
|
@@ -95,15 +95,18 @@
|
||||
#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
|
||||
#define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"
|
||||
#define DEFAULT_SEGS_COLS "lv_name,vg_name,lv_attr,stripes,segtype,seg_size"
|
||||
#define DEFAULT_PVSEGS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
|
||||
|
||||
#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,origin,snap_percent,move_pv,copy_percent,lv_uuid"
|
||||
#define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid"
|
||||
#define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,dev_size,pv_uuid"
|
||||
#define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize"
|
||||
#define DEFAULT_PVSEGS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
|
||||
|
||||
#define DEFAULT_LVS_SORT "vg_name,lv_name"
|
||||
#define DEFAULT_VGS_SORT "vg_name"
|
||||
#define DEFAULT_PVS_SORT "pv_name"
|
||||
#define DEFAULT_SEGS_SORT "vg_name,lv_name,seg_start"
|
||||
#define DEFAULT_PVSEGS_SORT "pv_name,pvseg_start"
|
||||
|
||||
#endif /* _LVM_DEFAULTS_H */
|
||||
|
@@ -18,17 +18,30 @@
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* A list consists of a list head plus elements.
|
||||
* Each element has 'next' and 'previous' pointers.
|
||||
* The list head's pointers point to the first and the last element.
|
||||
*/
|
||||
|
||||
struct list {
|
||||
struct list *n, *p;
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialise a list before use.
|
||||
* The list head's next and previous pointers point back to itself.
|
||||
*/
|
||||
#define LIST_INIT(name) struct list name = { &(name), &(name) }
|
||||
|
||||
static inline void list_init(struct list *head)
|
||||
{
|
||||
head->n = head->p = head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert an element before 'head'.
|
||||
* If 'head' is the list head, this adds an element to the end of the list.
|
||||
*/
|
||||
static inline void list_add(struct list *head, struct list *elem)
|
||||
{
|
||||
assert(head->n);
|
||||
@@ -40,6 +53,10 @@ static inline void list_add(struct list *head, struct list *elem)
|
||||
head->p = elem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert an element after 'head'.
|
||||
* If 'head' is the list head, this adds an element to the front of the list.
|
||||
*/
|
||||
static inline void list_add_h(struct list *head, struct list *elem)
|
||||
{
|
||||
assert(head->n);
|
||||
@@ -51,53 +68,127 @@ static inline void list_add_h(struct list *head, struct list *elem)
|
||||
head->n = elem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete an element from its list.
|
||||
* Note that this doesn't change the element itself - it may still be safe
|
||||
* to follow its pointers.
|
||||
*/
|
||||
static inline void list_del(struct list *elem)
|
||||
{
|
||||
elem->n->p = elem->p;
|
||||
elem->p->n = elem->n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is the list empty?
|
||||
*/
|
||||
static inline int list_empty(struct list *head)
|
||||
{
|
||||
return head->n == head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this the first element of the list?
|
||||
*/
|
||||
static inline int list_start(struct list *head, struct list *elem)
|
||||
{
|
||||
return elem->p == head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this the last element of the list?
|
||||
*/
|
||||
static inline int list_end(struct list *head, struct list *elem)
|
||||
{
|
||||
return elem->n == head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the previous element of the list, or NULL if we've reached the start.
|
||||
*/
|
||||
static inline struct list *list_prev(struct list *head, struct list *elem)
|
||||
{
|
||||
return (list_start(head, elem) ? NULL : elem->p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the next element of the list, or NULL if we've reached the end.
|
||||
*/
|
||||
static inline struct list *list_next(struct list *head, struct list *elem)
|
||||
{
|
||||
return (list_end(head, elem) ? NULL : elem->n);
|
||||
}
|
||||
|
||||
#define list_item(v, t) \
|
||||
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list))
|
||||
/*
|
||||
* Given the address v of an instance of 'struct list' called 'head'
|
||||
* contained in a structure of type t, return the containing structure.
|
||||
*/
|
||||
#define list_struct_base(v, t, head) \
|
||||
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->head))
|
||||
|
||||
#define list_struct_base(v, t, h) \
|
||||
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->h))
|
||||
/*
|
||||
* Given the address v of an instance of 'struct list list' contained in
|
||||
* a structure of type t, return the containing structure.
|
||||
*/
|
||||
#define list_item(v, t) list_struct_base((v), t, list)
|
||||
|
||||
/* Given a known element in a known structure, locate another */
|
||||
/*
|
||||
* Given the address v of one known element e in a known structure of type t,
|
||||
* return another element f.
|
||||
*/
|
||||
#define struct_field(v, t, e, f) \
|
||||
(((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->f)
|
||||
|
||||
/* Given a known element in a known structure, locate the list head */
|
||||
/*
|
||||
* Given the address v of a known element e in a known structure of type t,
|
||||
* return the list head 'list'
|
||||
*/
|
||||
#define list_head(v, t, e) struct_field(v, t, e, list)
|
||||
|
||||
/*
|
||||
* Set v to each element of a list in turn.
|
||||
*/
|
||||
#define list_iterate(v, head) \
|
||||
for (v = (head)->n; v != head; v = v->n)
|
||||
|
||||
/*
|
||||
* Set v to each element in a list in turn, starting from the element
|
||||
* in front of 'start'.
|
||||
* You can use this to 'unwind' a list_iterate and back out actions on
|
||||
* already-processed elements.
|
||||
* If 'start' is 'head' it walks the list backwards.
|
||||
*/
|
||||
#define list_uniterate(v, head, start) \
|
||||
for (v = (start)->p; v != head; v = v->p)
|
||||
|
||||
/*
|
||||
* A safe way to walk a list and delete and free some elements along
|
||||
* the way.
|
||||
* t must be defined as a temporary variable of the same type as v.
|
||||
*/
|
||||
#define list_iterate_safe(v, t, head) \
|
||||
for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
|
||||
|
||||
#define list_iterate_items(v, head) \
|
||||
for (v = list_item((head)->n, typeof(*v)); &v->list != (head); \
|
||||
v = list_item(v->list.n, typeof(*v)))
|
||||
/*
|
||||
* Walk a list, setting 'v' in turn to the containing structure of each item.
|
||||
* The containing structure should be the same type as 'v'.
|
||||
* The 'struct list' variable within the containing structure is 'field'.
|
||||
*/
|
||||
#define list_iterate_items_gen(v, head, field) \
|
||||
for (v = list_struct_base((head)->n, typeof(*v), field); \
|
||||
&v->field != (head); \
|
||||
v = list_struct_base(v->field.n, typeof(*v), field))
|
||||
|
||||
/*
|
||||
* Walk a list, setting 'v' in turn to the containing structure of each item.
|
||||
* The containing structure should be the same type as 'v'.
|
||||
* The list should be 'struct list list' within the containing structure.
|
||||
*/
|
||||
#define list_iterate_items(v, head) list_iterate_items_gen(v, (head), list)
|
||||
|
||||
/*
|
||||
* Return the number of elements in a list by walking it.
|
||||
*/
|
||||
static inline unsigned int list_size(const struct list *head)
|
||||
{
|
||||
unsigned int s = 0;
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include "lvm-types.h"
|
||||
#include "btree.h"
|
||||
#include "filter.h"
|
||||
#include "filter-persistent.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
@@ -82,6 +83,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 +103,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);
|
||||
@@ -184,7 +187,7 @@ static int _add_alias(struct device *dev, const char *path)
|
||||
/* Is name already there? */
|
||||
list_iterate(ah, &dev->aliases) {
|
||||
if (!strcmp(list_item(ah, struct str_list)->str, path)) {
|
||||
stack;
|
||||
log_debug("%s: Already in device cache", path);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -353,11 +356,11 @@ static int _insert(const char *path, int rec)
|
||||
return r;
|
||||
}
|
||||
|
||||
static void _full_scan(void)
|
||||
static void _full_scan(int dev_scan)
|
||||
{
|
||||
struct list *dh;
|
||||
|
||||
if (_cache.has_scanned)
|
||||
if (_cache.has_scanned && !dev_scan)
|
||||
return;
|
||||
|
||||
list_iterate(dh, &_cache.dirs) {
|
||||
@@ -366,6 +369,7 @@ static void _full_scan(void)
|
||||
};
|
||||
|
||||
_cache.has_scanned = 1;
|
||||
init_full_scan_done(1);
|
||||
}
|
||||
|
||||
int dev_cache_has_scanned(void)
|
||||
@@ -377,17 +381,16 @@ void dev_cache_scan(int do_scan)
|
||||
{
|
||||
if (!do_scan)
|
||||
_cache.has_scanned = 1;
|
||||
else {
|
||||
_cache.has_scanned = 0;
|
||||
_full_scan();
|
||||
}
|
||||
else
|
||||
_full_scan(1);
|
||||
}
|
||||
|
||||
int dev_cache_init(void)
|
||||
{
|
||||
_cache.names = NULL;
|
||||
_cache.has_scanned = 0;
|
||||
|
||||
if (!(_cache.mem = pool_create(10 * 1024))) {
|
||||
if (!(_cache.mem = pool_create("dev_cache", 10 * 1024))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -538,7 +541,7 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
|
||||
return (d && (!f || f->passes_filter(f, d))) ? d : NULL;
|
||||
}
|
||||
|
||||
struct dev_iter *dev_iter_create(struct dev_filter *f)
|
||||
struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
|
||||
{
|
||||
struct dev_iter *di = dbg_malloc(sizeof(*di));
|
||||
|
||||
@@ -547,7 +550,14 @@ struct dev_iter *dev_iter_create(struct dev_filter *f)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_full_scan();
|
||||
|
||||
if (dev_scan) {
|
||||
/* Flag gets reset between each command */
|
||||
if (!full_scan_done())
|
||||
persistent_filter_wipe(f); /* Calls _full_scan(1) */
|
||||
} else
|
||||
_full_scan(0);
|
||||
|
||||
di->current = btree_first(_cache.devices);
|
||||
di->filter = f;
|
||||
|
||||
|
@@ -45,7 +45,7 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f);
|
||||
* Object for iterating through the cache.
|
||||
*/
|
||||
struct dev_iter;
|
||||
struct dev_iter *dev_iter_create(struct dev_filter *f);
|
||||
struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan);
|
||||
void dev_iter_destroy(struct dev_iter *iter);
|
||||
struct device *dev_iter_get(struct dev_iter *iter);
|
||||
|
||||
|
@@ -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())
|
||||
@@ -296,23 +330,57 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
|
||||
}
|
||||
|
||||
#ifdef O_DIRECT_SUPPORT
|
||||
if (direct)
|
||||
flags |= O_DIRECT;
|
||||
if (direct) {
|
||||
if (!(dev->flags & DEV_O_DIRECT_TESTED))
|
||||
dev->flags |= DEV_O_DIRECT;
|
||||
|
||||
if ((dev->flags & DEV_O_DIRECT))
|
||||
flags |= O_DIRECT;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef O_NOATIME
|
||||
/* Don't update atime on device inodes */
|
||||
if (!(dev->flags & DEV_REGULAR))
|
||||
flags |= O_NOATIME;
|
||||
#endif
|
||||
|
||||
if ((dev->fd = open(name, flags, 0777)) < 0) {
|
||||
log_sys_error("open", name);
|
||||
#ifdef O_DIRECT_SUPPORT
|
||||
if (direct && !(dev->flags & DEV_O_DIRECT_TESTED)) {
|
||||
flags &= ~O_DIRECT;
|
||||
if ((dev->fd = open(name, flags, 0777)) >= 0) {
|
||||
dev->flags &= ~DEV_O_DIRECT;
|
||||
log_debug("%s: Not using O_DIRECT", name);
|
||||
goto opened;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (quiet)
|
||||
log_sys_debug("open", name);
|
||||
else
|
||||
log_sys_error("open", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev->open_count = 1;
|
||||
#ifdef O_DIRECT_SUPPORT
|
||||
opened:
|
||||
if (direct)
|
||||
dev->flags |= DEV_O_DIRECT_TESTED;
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -321,12 +389,14 @@ 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%s", dev_name(dev),
|
||||
dev->flags & DEV_OPENED_RW ? "RW" : "RO",
|
||||
dev->flags & DEV_O_DIRECT ? " O_DIRECT" : "");
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -354,6 +424,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));
|
||||
@@ -379,8 +450,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;
|
||||
@@ -412,8 +486,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;
|
||||
@@ -431,8 +507,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;
|
||||
@@ -447,8 +525,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;
|
||||
@@ -495,6 +575,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
69
lib/device/dev-md.c
Normal 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;
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -22,6 +22,9 @@
|
||||
#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 */
|
||||
#define DEV_O_DIRECT 0x00000010 /* Use O_DIRECT */
|
||||
#define DEV_O_DIRECT_TESTED 0x00000020 /* DEV_O_DIRECT is reliable */
|
||||
|
||||
/*
|
||||
* All devices in LVM will be represented by one of these.
|
||||
@@ -34,11 +37,13 @@ struct device {
|
||||
/* private */
|
||||
int fd;
|
||||
int open_count;
|
||||
int block_size;
|
||||
uint32_t flags;
|
||||
uint64_t end;
|
||||
struct list open_list;
|
||||
|
||||
char pvid[ID_LEN + 1];
|
||||
char _padding[7];
|
||||
};
|
||||
|
||||
struct device_list {
|
||||
@@ -61,7 +66,7 @@ int dev_get_sectsize(struct device *dev, uint32_t *size);
|
||||
/* Use quiet version if device number could change e.g. when opening LV */
|
||||
int dev_open(struct device *dev);
|
||||
int dev_open_quiet(struct device *dev);
|
||||
int dev_open_flags(struct device *dev, int flags, int append, int quiet);
|
||||
int dev_open_flags(struct device *dev, int flags, int direct, int quiet);
|
||||
int dev_close(struct device *dev);
|
||||
int dev_close_immediate(struct device *dev);
|
||||
void dev_close_all(void);
|
||||
@@ -89,15 +94,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
|
||||
|
@@ -18,7 +18,7 @@
|
||||
#include "display.h"
|
||||
#include "activate.h"
|
||||
#include "toolcontext.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
|
||||
#define SIZE_BUF 128
|
||||
|
||||
@@ -258,7 +258,7 @@ void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
log_print("PV Size %s" " / not usable %s", /* [LVM: %s]", */
|
||||
size,
|
||||
display_size(cmd, (pv->size -
|
||||
pv->pe_count * pv->pe_size),
|
||||
(uint64_t) pv->pe_count * pv->pe_size),
|
||||
SIZE_SHORT));
|
||||
|
||||
} else
|
||||
@@ -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,
|
||||
@@ -337,10 +337,9 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
void *handle)
|
||||
{
|
||||
struct lvinfo info;
|
||||
int inkernel, snap_active;
|
||||
int inkernel, snap_active = 0;
|
||||
char uuid[64];
|
||||
struct snapshot *snap = NULL;
|
||||
struct list *slh, *snaplist;
|
||||
struct lv_segment *snap_seg = NULL;
|
||||
float snap_percent; /* fused, fsize; */
|
||||
|
||||
if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) {
|
||||
@@ -348,7 +347,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 ---");
|
||||
|
||||
@@ -364,27 +363,30 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
if (lv_is_origin(lv)) {
|
||||
log_print("LV snapshot status source of");
|
||||
|
||||
snaplist = find_snapshots(lv);
|
||||
list_iterate(slh, snaplist) {
|
||||
snap = list_item(slh, struct snapshot_list)->snapshot;
|
||||
snap_active = lv_snapshot_percent(snap->cow,
|
||||
&snap_percent);
|
||||
if (!snap_active || snap_percent < 0 ||
|
||||
snap_percent >= 100) snap_active = 0;
|
||||
list_iterate_items_gen(snap_seg, &lv->snapshot_segs,
|
||||
origin_list) {
|
||||
if (inkernel &&
|
||||
(snap_active = lv_snapshot_percent(snap_seg->cow,
|
||||
&snap_percent)))
|
||||
if (snap_percent < 0 || snap_percent >= 100)
|
||||
snap_active = 0;
|
||||
log_print(" %s%s/%s [%s]",
|
||||
lv->vg->cmd->dev_dir, lv->vg->name,
|
||||
snap->cow->name,
|
||||
snap_seg->cow->name,
|
||||
(snap_active > 0) ? "active" : "INACTIVE");
|
||||
}
|
||||
snap = NULL;
|
||||
} else if ((snap = find_cow(lv))) {
|
||||
snap_active = lv_snapshot_percent(lv, &snap_percent);
|
||||
if (!snap_active || snap_percent < 0 || snap_percent >= 100)
|
||||
snap_active = 0;
|
||||
snap_seg = NULL;
|
||||
} else if ((snap_seg = find_cow(lv))) {
|
||||
if (inkernel &&
|
||||
(snap_active = lv_snapshot_percent(snap_seg->cow,
|
||||
&snap_percent)))
|
||||
if (snap_percent < 0 || snap_percent >= 100)
|
||||
snap_active = 0;
|
||||
|
||||
log_print("LV snapshot status %s destination for %s%s/%s",
|
||||
(snap_active > 0) ? "active" : "INACTIVE",
|
||||
lv->vg->cmd->dev_dir, lv->vg->name,
|
||||
snap->origin->name);
|
||||
snap_seg->origin->name);
|
||||
}
|
||||
|
||||
if (inkernel && info.suspended)
|
||||
@@ -402,15 +404,24 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
|
||||
log_print("LV Size %s",
|
||||
display_size(cmd,
|
||||
snap ? snap->origin->size : lv->size,
|
||||
snap_seg ? snap_seg->origin->size : lv->size,
|
||||
SIZE_SHORT));
|
||||
|
||||
log_print("Current LE %u",
|
||||
snap ? snap->origin->le_count : lv->le_count);
|
||||
snap_seg ? snap_seg->origin->le_count : lv->le_count);
|
||||
|
||||
/********** FIXME allocation
|
||||
log_print("Allocated LE %u", lv->allocated_le);
|
||||
**********/
|
||||
if (snap_seg) {
|
||||
log_print("COW-table size %s",
|
||||
display_size(cmd, (uint64_t) lv->size, SIZE_SHORT));
|
||||
log_print("COW-table LE %u", lv->le_count);
|
||||
|
||||
if (snap_active)
|
||||
log_print("Allocated to snapshot %.2f%% ", snap_percent);
|
||||
|
||||
log_print("Snapshot chunk size %s",
|
||||
display_size(cmd, (uint64_t) snap_seg->chunk_size,
|
||||
SIZE_SHORT));
|
||||
}
|
||||
|
||||
log_print("Segments %u", list_size(&lv->segments));
|
||||
|
||||
@@ -418,31 +429,6 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
log_print("Stripe size (KByte) %u", lv->stripesize / 2);
|
||||
***********/
|
||||
|
||||
if (snap) {
|
||||
if (snap_percent == -1)
|
||||
snap_percent = 100;
|
||||
|
||||
log_print("Snapshot chunk size %s",
|
||||
display_size(cmd, (uint64_t) snap->chunk_size,
|
||||
SIZE_SHORT));
|
||||
|
||||
/*
|
||||
size = display_size(lv->size, SIZE_SHORT);
|
||||
sscanf(size, "%f", &fsize);
|
||||
fused = fsize * snap_percent / 100;
|
||||
*/
|
||||
log_print("Allocated to snapshot %.2f%% ", /* [%.2f/%s]", */
|
||||
snap_percent); /*, fused, size); */
|
||||
/* dbg_free(size); */
|
||||
}
|
||||
|
||||
/********** FIXME Snapshot
|
||||
size = ???
|
||||
log_print("Allocated to COW-table %s", size);
|
||||
dbg_free(size);
|
||||
}
|
||||
******************/
|
||||
|
||||
log_print("Allocation %s", get_alloc_string(lv->alloc));
|
||||
log_print("Read ahead sectors %u", lv->read_ahead);
|
||||
|
||||
@@ -550,7 +536,7 @@ void vgdisplay_full(struct volume_group *vg)
|
||||
vg->status & SHARED ? "yes" : "no");
|
||||
}
|
||||
log_print("MAX LV %u", vg->max_lv);
|
||||
log_print("Cur LV %u", vg->lv_count);
|
||||
log_print("Cur LV %u", vg->lv_count + vg->snapshot_count);
|
||||
log_print("Open LV %u", lvs_in_vg_opened(vg));
|
||||
/****** FIXME Max LV Size
|
||||
log_print ( "MAX LV Size %s",
|
||||
@@ -662,3 +648,22 @@ void vgdisplay_short(struct volume_group *vg)
|
||||
SIZE_SHORT));
|
||||
return;
|
||||
}
|
||||
|
||||
void display_formats(struct cmd_context *cmd)
|
||||
{
|
||||
struct format_type *fmt;
|
||||
|
||||
list_iterate_items(fmt, &cmd->formats) {
|
||||
log_print("%s", fmt->name);
|
||||
}
|
||||
}
|
||||
|
||||
void display_segtypes(struct cmd_context *cmd)
|
||||
{
|
||||
struct segment_type *segtype;
|
||||
|
||||
list_iterate_items(segtype, &cmd->segtypes) {
|
||||
log_print("%s", segtype->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -45,6 +45,9 @@ void vgdisplay_full(struct volume_group *vg);
|
||||
void vgdisplay_colons(struct volume_group *vg);
|
||||
void vgdisplay_short(struct volume_group *vg);
|
||||
|
||||
void display_formats(struct cmd_context *cmd);
|
||||
void display_segtypes(struct cmd_context *cmd);
|
||||
|
||||
/*
|
||||
* Allocation policy display conversion routines.
|
||||
*/
|
||||
|
@@ -16,7 +16,7 @@
|
||||
#include "pool.h"
|
||||
#include "list.h"
|
||||
#include "toolcontext.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
#include "display.h"
|
||||
#include "text_export.h"
|
||||
#include "text_import.h"
|
||||
@@ -97,5 +97,7 @@ struct segment_type *init_error_segtype(struct cmd_context *cmd)
|
||||
segtype->private = NULL;
|
||||
segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
return segtype;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -53,7 +53,9 @@ int persistent_filter_wipe(struct dev_filter *f)
|
||||
{
|
||||
struct pfilter *pf = (struct pfilter *) f->private;
|
||||
|
||||
log_verbose("Wiping cache of LVM-capable devices");
|
||||
hash_wipe(pf->devices);
|
||||
|
||||
/* Trigger complete device scan */
|
||||
dev_cache_scan(1);
|
||||
|
||||
@@ -212,13 +214,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)
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -172,7 +172,7 @@ static int _read_devs(struct dev_set *ds, const char *dir)
|
||||
unsigned char dtype;
|
||||
struct stat info;
|
||||
char path[PATH_MAX];
|
||||
dev_t dev;
|
||||
dev_t dev = { 0 };
|
||||
int r = 1;
|
||||
|
||||
if (!(dr = opendir(dir))) {
|
||||
@@ -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;
|
||||
}
|
||||
|
@@ -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,38 +65,61 @@ 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 */
|
||||
{"gnbd", 1}, /* Network block device */
|
||||
{"ramdisk", 1}, /* RAM disk */
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
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, 1)) {
|
||||
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 +129,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 +188,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 +202,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 +211,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 +248,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 +260,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;
|
||||
}
|
||||
|
@@ -37,4 +37,6 @@ void lvm_type_filter_destroy(struct dev_filter *f);
|
||||
|
||||
int md_major(void);
|
||||
|
||||
int max_partitions(int major);
|
||||
|
||||
#endif
|
||||
|
@@ -482,7 +482,7 @@ int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
|
||||
/* vgcache_del(vg_name); */
|
||||
}
|
||||
|
||||
if (!(iter = dev_iter_create(filter))) {
|
||||
if (!(iter = dev_iter_create(filter, 1))) {
|
||||
log_error("read_pvs_in_vg: dev_iter_create failed");
|
||||
return 0;
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include "lvmcache.h"
|
||||
#include "lvm1-label.h"
|
||||
#include "format1.h"
|
||||
#include "segtype.h"
|
||||
|
||||
#define FMT_LVM1_NAME "lvm1"
|
||||
|
||||
@@ -147,7 +148,6 @@ static struct volume_group *_build_vg(struct format_instance *fid,
|
||||
vg->seqno = 0;
|
||||
list_init(&vg->pvs);
|
||||
list_init(&vg->lvs);
|
||||
list_init(&vg->snapshots);
|
||||
list_init(&vg->tags);
|
||||
|
||||
if (!_check_vgs(pvs, &partial))
|
||||
@@ -182,7 +182,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);
|
||||
@@ -275,7 +275,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;
|
||||
|
||||
@@ -298,7 +298,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;
|
||||
@@ -420,7 +420,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;
|
||||
}
|
||||
@@ -492,6 +492,17 @@ static int _vg_setup(struct format_instance *fid, struct volume_group *vg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _segtype_supported (struct format_instance *fid,
|
||||
struct segment_type *segtype)
|
||||
{
|
||||
if (!(segtype->flags & SEG_FORMAT1_SUPPORT)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct metadata_area_ops _metadata_format1_ops = {
|
||||
vg_read:_vg_read,
|
||||
vg_write:_vg_write,
|
||||
@@ -542,6 +553,7 @@ static struct format_handler _format1_ops = {
|
||||
pv_write:_pv_write,
|
||||
lv_setup:_lv_setup,
|
||||
vg_setup:_vg_setup,
|
||||
segtype_supported:_segtype_supported,
|
||||
create_instance:_create_instance,
|
||||
destroy_instance:_destroy_instance,
|
||||
destroy:_destroy,
|
||||
@@ -578,5 +590,7 @@ struct format_type *init_format(struct cmd_context *cmd)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log_very_verbose("Initialised format: %s", fmt->name);
|
||||
|
||||
return fmt;
|
||||
}
|
||||
|
@@ -25,7 +25,8 @@
|
||||
#include "lvm-string.h"
|
||||
#include "filter.h"
|
||||
#include "toolcontext.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
#include "pv_alloc.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
@@ -89,6 +90,13 @@ int import_pv(struct pool *mem, struct device *dev,
|
||||
pv->pe_alloc_count = pvd->pe_allocated;
|
||||
|
||||
list_init(&pv->tags);
|
||||
list_init(&pv->segments);
|
||||
list_init(&pv->free_segments);
|
||||
|
||||
if (!alloc_pv_segment_whole_pv(mem, pv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -323,6 +331,8 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
|
||||
lv->size = lvd->lv_size;
|
||||
lv->le_count = lvd->lv_allocated_le;
|
||||
|
||||
lv->snapshot = NULL;
|
||||
list_init(&lv->snapshot_segs);
|
||||
list_init(&lv->segments);
|
||||
list_init(&lv->tags);
|
||||
|
||||
@@ -495,7 +505,7 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||
struct physical_volume *pv, const char *dev_dir)
|
||||
{
|
||||
int r = 0;
|
||||
struct list *lvh, *sh;
|
||||
struct list *lvh;
|
||||
struct lv_list *ll;
|
||||
struct lvd_list *lvdl;
|
||||
size_t len;
|
||||
@@ -524,6 +534,9 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
ll = list_item(lvh, struct lv_list);
|
||||
if (ll->lv->status & SNAPSHOT)
|
||||
continue;
|
||||
|
||||
if (!(lvdl = pool_alloc(dl->mem, sizeof(*lvdl)))) {
|
||||
stack;
|
||||
goto out;
|
||||
@@ -532,7 +545,6 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||
_export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
|
||||
|
||||
lv_num = lvnum_from_lvid(&ll->lv->lvid);
|
||||
|
||||
lvdl->lvd.lv_number = lv_num;
|
||||
|
||||
if (!hash_insert(lvd_hash, ll->lv->name, &lvdl->lvd)) {
|
||||
@@ -545,37 +557,20 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (lv_is_origin(ll->lv))
|
||||
lvdl->lvd.lv_access |= LV_SNAPSHOT_ORG;
|
||||
|
||||
if (lv_is_cow(ll->lv)) {
|
||||
lvdl->lvd.lv_access |= LV_SNAPSHOT;
|
||||
lvdl->lvd.lv_chunk_size = ll->lv->snapshot->chunk_size;
|
||||
lvdl->lvd.lv_snapshot_minor =
|
||||
lvnum_from_lvid(&ll->lv->snapshot->origin->lvid);
|
||||
}
|
||||
|
||||
list_add(&dl->lvds, &lvdl->list);
|
||||
dl->pvd.lv_cur++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we need to run through the snapshots, exporting
|
||||
* the SNAPSHOT_ORG flags etc.
|
||||
*/
|
||||
list_iterate(sh, &vg->snapshots) {
|
||||
struct lv_disk *org, *cow;
|
||||
struct snapshot *s = list_item(sh,
|
||||
struct snapshot_list)->snapshot;
|
||||
|
||||
if (!(org = hash_lookup(lvd_hash, s->origin->name))) {
|
||||
log_err("Couldn't find snapshot origin '%s'.",
|
||||
s->origin->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(cow = hash_lookup(lvd_hash, s->cow->name))) {
|
||||
log_err("Couldn't find snapshot cow store '%s'.",
|
||||
s->cow->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
org->lv_access |= LV_SNAPSHOT_ORG;
|
||||
cow->lv_access |= LV_SNAPSHOT;
|
||||
cow->lv_snapshot_minor = org->lv_number;
|
||||
cow->lv_chunk_size = s->chunk_size;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
@@ -646,7 +641,8 @@ 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(vg->fid, NULL, org, cow, NULL,
|
||||
org->le_count,
|
||||
lvd->lv_chunk_size)) {
|
||||
log_err("Couldn't add snapshot.");
|
||||
return 0;
|
||||
|
@@ -20,7 +20,7 @@
|
||||
#include "disk-rep.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "display.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
|
||||
/*
|
||||
* After much thought I have decided it is easier,
|
||||
@@ -60,6 +60,8 @@ static struct hash_table *_create_lv_maps(struct pool *mem,
|
||||
|
||||
list_iterate(llh, &vg->lvs) {
|
||||
ll = list_item(llh, struct lv_list);
|
||||
if (ll->lv->status & SNAPSHOT)
|
||||
continue;
|
||||
|
||||
if (!(lvm = pool_alloc(mem, sizeof(*lvm)))) {
|
||||
stack;
|
||||
@@ -205,58 +207,55 @@ static int _check_maps_are_complete(struct hash_table *maps)
|
||||
|
||||
static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
{
|
||||
uint32_t le = 0;
|
||||
uint32_t le = 0, len;
|
||||
struct lv_segment *seg;
|
||||
struct segment_type *segtype;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "striped"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (le < lvm->lv->le_count) {
|
||||
seg = alloc_lv_segment(cmd->mem, 1);
|
||||
len = 0;
|
||||
|
||||
seg->lv = lvm->lv;
|
||||
if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) {
|
||||
stack;
|
||||
do
|
||||
len++;
|
||||
while ((lvm->map[le + len].pv == lvm->map[le].pv) &&
|
||||
(lvm->map[le].pv &&
|
||||
lvm->map[le + len].pe == lvm->map[le].pe + len));
|
||||
|
||||
if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, le,
|
||||
len, 0, 0, 1, len, 0, 0))) {
|
||||
log_error("Failed to allocate linear segment.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->le = le;
|
||||
seg->len = 0;
|
||||
seg->area_len = 0;
|
||||
seg->stripe_size = 0;
|
||||
|
||||
seg->area[0].type = AREA_PV;
|
||||
seg->area[0].u.pv.pv = lvm->map[le].pv;
|
||||
seg->area[0].u.pv.pe = lvm->map[le].pe;
|
||||
|
||||
do {
|
||||
seg->len++;
|
||||
seg->area_len++;
|
||||
} while ((lvm->map[le + seg->len].pv == seg->area[0].u.pv.pv) &&
|
||||
(seg->area[0].u.pv.pv &&
|
||||
lvm->map[le + seg->len].pe == seg->area[0].u.pv.pe +
|
||||
seg->len));
|
||||
|
||||
le += seg->len;
|
||||
set_lv_segment_area_pv(seg, 0, lvm->map[le].pv, lvm->map[le].pe);
|
||||
|
||||
list_add(&lvm->lv->segments, &seg->list);
|
||||
|
||||
le += seg->len;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg,
|
||||
uint32_t base_le, uint32_t len)
|
||||
static int _check_stripe(struct lv_map *lvm, uint32_t area_count,
|
||||
uint32_t seg_len, uint32_t base_le, uint32_t len)
|
||||
{
|
||||
uint32_t le, st;
|
||||
|
||||
le = base_le + seg->len;
|
||||
uint32_t st;
|
||||
|
||||
/*
|
||||
* Is the next physical extent in every stripe adjacent to the last?
|
||||
*/
|
||||
for (st = 0; st < seg->area_count; st++)
|
||||
if ((lvm->map[le + st * len].pv != seg->area[st].u.pv.pv) ||
|
||||
(seg->area[st].u.pv.pv &&
|
||||
lvm->map[le + st * len].pe !=
|
||||
seg->area[st].u.pv.pe + seg->len)) return 0;
|
||||
for (st = 0; st < area_count; st++)
|
||||
if ((lvm->map[base_le + st * len + seg_len].pv !=
|
||||
lvm->map[base_le + st * len].pv) ||
|
||||
(lvm->map[base_le + st * len].pv &&
|
||||
lvm->map[base_le + st * len + seg_len].pe !=
|
||||
lvm->map[base_le + st * len].pe + seg_len))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -264,7 +263,9 @@ static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg,
|
||||
static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
{
|
||||
uint32_t st, le = 0, len;
|
||||
uint32_t area_len;
|
||||
struct lv_segment *seg;
|
||||
struct segment_type *segtype;
|
||||
|
||||
/*
|
||||
* Work out overall striped length
|
||||
@@ -276,43 +277,42 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
}
|
||||
len = lvm->lv->le_count / lvm->stripes;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(cmd, "striped"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (le < len) {
|
||||
if (!(seg = alloc_lv_segment(cmd->mem, lvm->stripes))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->lv = lvm->lv;
|
||||
if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
seg->stripe_size = lvm->stripe_size;
|
||||
seg->le = seg->area_count * le;
|
||||
seg->len = 1;
|
||||
seg->area_len = 1;
|
||||
|
||||
/*
|
||||
* Set up start positions of each stripe in this segment
|
||||
*/
|
||||
for (st = 0; st < seg->area_count; st++) {
|
||||
seg->area[st].u.pv.pv = lvm->map[le + st * len].pv;
|
||||
seg->area[st].u.pv.pe = lvm->map[le + st * len].pe;
|
||||
}
|
||||
area_len = 1;
|
||||
|
||||
/*
|
||||
* Find how many blocks are contiguous in all stripes
|
||||
* and so can form part of this segment
|
||||
*/
|
||||
while (_check_stripe(lvm, seg, le, len)) {
|
||||
seg->len++;
|
||||
seg->area_len++;
|
||||
while (_check_stripe(lvm, lvm->stripes,
|
||||
area_len * lvm->stripes, le, len))
|
||||
area_len++;
|
||||
|
||||
if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv,
|
||||
lvm->stripes * le,
|
||||
lvm->stripes * area_len,
|
||||
0, lvm->stripe_size, lvm->stripes,
|
||||
area_len, 0, 0))) {
|
||||
log_error("Failed to allocate striped segment.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
le += seg->len;
|
||||
seg->len *= seg->area_count;
|
||||
/*
|
||||
* Set up start positions of each stripe in this segment
|
||||
*/
|
||||
for (st = 0; st < seg->area_count; st++)
|
||||
set_lv_segment_area_pv(seg, st,
|
||||
lvm->map[le + st * len].pv,
|
||||
lvm->map[le + st * len].pe);
|
||||
|
||||
list_add(&lvm->lv->segments, &seg->list);
|
||||
|
||||
le += seg->len;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -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) {
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -20,6 +20,8 @@
|
||||
#include "metadata.h"
|
||||
#include "pool.h"
|
||||
|
||||
#define MINOR_OFFSET 65536
|
||||
|
||||
/* From NSP.cf */
|
||||
#define NSPMajorVersion 4
|
||||
#define NSPMinorVersion 1
|
||||
@@ -66,29 +68,6 @@ struct pool_list;
|
||||
struct user_subpool;
|
||||
struct user_device;
|
||||
|
||||
/* This must be kept up to date with sistina/pool/module/pool_sptypes.h */
|
||||
|
||||
/* Generic Labels */
|
||||
#define SPTYPE_DATA (0x00000000)
|
||||
|
||||
/* GFS specific labels */
|
||||
#define SPTYPE_GFS_DATA (0x68011670)
|
||||
#define SPTYPE_GFS_JOURNAL (0x69011670)
|
||||
|
||||
struct sptype_name {
|
||||
const char *name;
|
||||
uint32_t label;
|
||||
};
|
||||
|
||||
static const struct sptype_name sptype_names[] = {
|
||||
{"data", SPTYPE_DATA},
|
||||
|
||||
{"gfs_data", SPTYPE_GFS_DATA},
|
||||
{"gfs_journal", SPTYPE_GFS_JOURNAL},
|
||||
|
||||
{"", 0x0} /* This must be the last flag. */
|
||||
};
|
||||
|
||||
struct pool_disk {
|
||||
uint64_t pl_magic; /* Pool magic number */
|
||||
uint64_t pl_pool_id; /* Unique pool identifier */
|
||||
|
@@ -132,7 +132,6 @@ static struct volume_group *_build_vg_from_pds(struct format_instance
|
||||
vg->system_id = NULL;
|
||||
list_init(&vg->pvs);
|
||||
list_init(&vg->lvs);
|
||||
list_init(&vg->snapshots);
|
||||
list_init(&vg->tags);
|
||||
|
||||
if (!import_pool_vg(vg, smem, pds)) {
|
||||
@@ -181,7 +180,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 +226,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;
|
||||
@@ -357,5 +356,7 @@ struct format_type *init_format(struct cmd_context *cmd)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log_very_verbose("Initialised format: %s", fmt->name);
|
||||
|
||||
return fmt;
|
||||
}
|
||||
|
@@ -19,10 +19,12 @@
|
||||
#include "metadata.h"
|
||||
#include "lvmcache.h"
|
||||
#include "disk_rep.h"
|
||||
#include "sptype_names.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "pv_alloc.h"
|
||||
#include "str_list.h"
|
||||
#include "display.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
|
||||
/* This file contains only imports at the moment... */
|
||||
|
||||
@@ -81,6 +83,8 @@ int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls)
|
||||
lv->name = NULL;
|
||||
lv->le_count = 0;
|
||||
lv->read_ahead = 0;
|
||||
lv->snapshot = NULL;
|
||||
list_init(&lv->snapshot_segs);
|
||||
list_init(&lv->segments);
|
||||
list_init(&lv->tags);
|
||||
|
||||
@@ -107,10 +111,12 @@ int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls)
|
||||
/* for pool a minor of 0 is dynamic */
|
||||
if (pl->pd.pl_minor) {
|
||||
lv->status |= FIXED_MINOR;
|
||||
lv->minor = pl->pd.pl_minor;
|
||||
lv->minor = pl->pd.pl_minor + MINOR_OFFSET;
|
||||
} else {
|
||||
lv->minor = -1;
|
||||
}
|
||||
lv->snapshot = NULL;
|
||||
list_init(&lv->snapshot_segs);
|
||||
list_init(&lv->segments);
|
||||
list_init(&lv->tags);
|
||||
}
|
||||
@@ -177,6 +183,13 @@ int import_pool_pv(const struct format_type *fmt, struct pool *mem,
|
||||
pv->pe_alloc_count = pv->pe_count;
|
||||
|
||||
list_init(&pv->tags);
|
||||
list_init(&pv->segments);
|
||||
list_init(&pv->free_segments);
|
||||
|
||||
if (!alloc_pv_segment_whole_pv(mem, pv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -199,40 +212,41 @@ static int _add_stripe_seg(struct pool *mem,
|
||||
uint32_t *le_cur)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
struct segment_type *segtype;
|
||||
int j;
|
||||
uint32_t area_len;
|
||||
|
||||
if (!(seg = alloc_lv_segment(mem, usp->num_devs))) {
|
||||
log_error("Unable to allocate striped lv_segment structure");
|
||||
return 0;
|
||||
}
|
||||
if(usp->striping & (usp->striping - 1)) {
|
||||
if (usp->striping & (usp->striping - 1)) {
|
||||
log_error("Stripe size must be a power of 2");
|
||||
return 0;
|
||||
}
|
||||
seg->stripe_size = usp->striping;
|
||||
seg->status |= 0;
|
||||
seg->le += *le_cur;
|
||||
|
||||
area_len = (usp->devs[0].blocks) / POOL_PE_SIZE;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd,
|
||||
"striped"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur,
|
||||
area_len * usp->num_devs, 0,
|
||||
usp->striping, usp->num_devs, area_len,
|
||||
0, 0))) {
|
||||
log_error("Unable to allocate striped lv_segment structure");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (j = 0; j < usp->num_devs; j++)
|
||||
set_lv_segment_area_pv(seg, j, usp->devs[j].pv, 0);
|
||||
|
||||
/* add the subpool type to the segment tag list */
|
||||
str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
|
||||
|
||||
for (j = 0; j < usp->num_devs; j++) {
|
||||
if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd,
|
||||
"striped"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
|
||||
seg->len += seg->area_len;
|
||||
*le_cur += seg->area_len;
|
||||
seg->lv = lv;
|
||||
|
||||
seg->area[j].type = AREA_PV;
|
||||
seg->area[j].u.pv.pv = usp->devs[j].pv;
|
||||
seg->area[j].u.pv.pe = 0;
|
||||
}
|
||||
list_add(&lv->segments, &seg->list);
|
||||
|
||||
*le_cur += seg->len;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -241,37 +255,35 @@ static int _add_linear_seg(struct pool *mem,
|
||||
uint32_t *le_cur)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
struct segment_type *segtype;
|
||||
int j;
|
||||
uint32_t area_len;
|
||||
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, "striped"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (j = 0; j < usp->num_devs; j++) {
|
||||
/* linear segments only have 1 data area */
|
||||
if (!(seg = alloc_lv_segment(mem, 1))) {
|
||||
area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
|
||||
|
||||
if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur,
|
||||
area_len, 0, usp->striping,
|
||||
1, area_len, POOL_PE_SIZE, 0))) {
|
||||
log_error("Unable to allocate linear lv_segment "
|
||||
"structure");
|
||||
return 0;
|
||||
}
|
||||
seg->stripe_size = usp->striping;
|
||||
seg->le += *le_cur;
|
||||
seg->chunk_size = POOL_PE_SIZE;
|
||||
seg->status |= 0;
|
||||
if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd,
|
||||
"striped"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* add the subpool type to the segment tag list */
|
||||
str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
|
||||
|
||||
seg->lv = lv;
|
||||
|
||||
seg->area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
|
||||
seg->len = seg->area_len;
|
||||
*le_cur += seg->len;
|
||||
seg->area[0].type = AREA_PV;
|
||||
seg->area[0].u.pv.pv = usp->devs[j].pv;
|
||||
seg->area[0].u.pv.pe = 0;
|
||||
set_lv_segment_area_pv(seg, 0, usp->devs[j].pv, 0);
|
||||
list_add(&lv->segments, &seg->list);
|
||||
|
||||
*le_cur += seg->len;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -287,8 +299,11 @@ int import_pool_segments(struct list *lvs, struct pool *mem,
|
||||
|
||||
list_iterate(lvhs, lvs) {
|
||||
lvl = list_item(lvhs, struct lv_list);
|
||||
|
||||
lv = lvl->lv;
|
||||
|
||||
if (lv->status & SNAPSHOT)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < subpools; i++) {
|
||||
if (usp[i].striping) {
|
||||
if (!_add_stripe_seg(mem, &usp[i], lv, &le_cur)) {
|
||||
|
42
lib/format_pool/sptype_names.h
Normal file
42
lib/format_pool/sptype_names.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU 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 SPTYPE_NAMES_H
|
||||
#define SPTYPE_NAMES_H
|
||||
|
||||
/* This must be kept up to date with sistina/pool/module/pool_sptypes.h */
|
||||
|
||||
/* Generic Labels */
|
||||
#define SPTYPE_DATA (0x00000000)
|
||||
|
||||
/* GFS specific labels */
|
||||
#define SPTYPE_GFS_DATA (0x68011670)
|
||||
#define SPTYPE_GFS_JOURNAL (0x69011670)
|
||||
|
||||
struct sptype_name {
|
||||
const char *name;
|
||||
uint32_t label;
|
||||
};
|
||||
|
||||
static const struct sptype_name sptype_names[] = {
|
||||
{"data", SPTYPE_DATA},
|
||||
|
||||
{"gfs_data", SPTYPE_GFS_DATA},
|
||||
{"gfs_journal", SPTYPE_GFS_JOURNAL},
|
||||
|
||||
{"", 0x0} /* This must be the last flag. */
|
||||
};
|
||||
|
||||
#endif
|
@@ -53,7 +53,7 @@ struct archive_file {
|
||||
struct list list;
|
||||
|
||||
char *path;
|
||||
int index;
|
||||
uint32_t index;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -132,7 +132,8 @@ static char *_join(struct pool *mem, const char *dir, const char *name)
|
||||
static struct list *_scan_archive(struct pool *mem,
|
||||
const char *vgname, const char *dir)
|
||||
{
|
||||
int i, count, ix;
|
||||
int i, count;
|
||||
uint32_t ix;
|
||||
char vgname_found[64], *path;
|
||||
struct dirent **dirent;
|
||||
struct archive_file *af;
|
||||
@@ -240,7 +241,7 @@ int archive_vg(struct volume_group *vg,
|
||||
uint32_t retain_days, uint32_t min_archive)
|
||||
{
|
||||
int i, fd, renamed = 0;
|
||||
unsigned int ix = 0;
|
||||
uint32_t ix = 0;
|
||||
struct archive_file *last;
|
||||
FILE *fp = NULL;
|
||||
char temp_file[PATH_MAX], archive_name[PATH_MAX];
|
||||
@@ -285,7 +286,7 @@ int archive_vg(struct volume_group *vg,
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (lvm_snprintf(archive_name, sizeof(archive_name),
|
||||
"%s/%s_%05d.vg", dir, vg->name, ix) < 0) {
|
||||
"%s/%s_%05u.vg", dir, vg->name, ix) < 0) {
|
||||
log_error("Archive file name too long.");
|
||||
return 0;
|
||||
}
|
||||
|
@@ -20,7 +20,7 @@
|
||||
#include "pool.h"
|
||||
#include "display.h"
|
||||
#include "lvm-string.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
#include "text_export.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
@@ -477,87 +477,6 @@ static int _count_segments(struct logical_volume *lv)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _print_snapshot(struct formatter *f, struct snapshot *snap,
|
||||
unsigned int count)
|
||||
{
|
||||
char buffer[256];
|
||||
struct lv_segment seg;
|
||||
|
||||
f->nl(f);
|
||||
|
||||
outf(f, "snapshot%u {", count);
|
||||
_inc_indent(f);
|
||||
|
||||
if (!id_write_format(&snap->id, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
outf(f, "id = \"%s\"", buffer);
|
||||
|
||||
seg.status = LVM_READ | LVM_WRITE | VISIBLE_LV;
|
||||
if (!print_flags(seg.status, LV_FLAGS, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
outf(f, "status = %s", buffer);
|
||||
outf(f, "segment_count = 1");
|
||||
|
||||
f->nl(f);
|
||||
|
||||
if (!(seg.segtype = get_segtype_from_string(snap->origin->vg->cmd,
|
||||
"snapshot"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg.le = 0;
|
||||
seg.len = snap->origin->le_count;
|
||||
seg.origin = snap->origin;
|
||||
seg.cow = snap->cow;
|
||||
seg.chunk_size = snap->chunk_size;
|
||||
|
||||
/* FIXME Dummy values */
|
||||
list_init(&seg.list);
|
||||
seg.lv = snap->cow;
|
||||
seg.stripe_size = 0;
|
||||
seg.area_count = 0;
|
||||
seg.area_len = 0;
|
||||
seg.extents_copied = 0;
|
||||
|
||||
/* Can't tag a snapshot independently of its origin */
|
||||
list_init(&seg.tags);
|
||||
|
||||
if (!_print_segment(f, snap->origin->vg, 1, &seg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
outf(f, "}");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _print_snapshots(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
struct list *sh;
|
||||
struct snapshot *s;
|
||||
unsigned int count = 0;
|
||||
|
||||
list_iterate(sh, &vg->snapshots) {
|
||||
s = list_item(sh, struct snapshot_list)->snapshot;
|
||||
|
||||
if (!_print_snapshot(f, s, count++)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
struct list *lvh;
|
||||
@@ -629,11 +548,6 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
||||
outf(f, "}");
|
||||
}
|
||||
|
||||
if (!_print_snapshots(f, vg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
outf(f, "}");
|
||||
|
||||
@@ -652,7 +566,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;
|
||||
}
|
||||
|
@@ -54,6 +54,7 @@ static struct flag _lv_flags[] = {
|
||||
{LOCKED, "LOCKED"},
|
||||
{MIRRORED, NULL},
|
||||
{VIRTUAL, NULL},
|
||||
{SNAPSHOT, NULL},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
|
@@ -88,8 +88,11 @@ static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
|
||||
}
|
||||
*/
|
||||
|
||||
if (!*lv->lvid.s)
|
||||
lvid_create(&lv->lvid, &lv->vg->id);
|
||||
if (!*lv->lvid.s && !lvid_create(&lv->lvid, &lv->vg->id)) {
|
||||
log_error("Random lvid creation failed for %s/%s.",
|
||||
lv->vg->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -180,57 +183,74 @@ static int _raw_write_mda_header(const struct format_type *fmt,
|
||||
|
||||
static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
|
||||
struct mda_header *mdah,
|
||||
const char *vgname)
|
||||
const char *vgname,
|
||||
int precommit)
|
||||
{
|
||||
size_t len;
|
||||
char vgnamebuf[NAME_LEN + 2];
|
||||
struct raw_locn *rlocn;
|
||||
struct lvmcache_info *info;
|
||||
|
||||
rlocn = mdah->raw_locns;
|
||||
rlocn = mdah->raw_locns; /* Slot 0 */
|
||||
|
||||
if (precommit)
|
||||
rlocn++; /* Slot 1 */
|
||||
|
||||
/* FIXME Loop through rlocns two-at-a-time. List null-terminated. */
|
||||
/* FIXME Ignore if checksum incorrect!!! */
|
||||
while (rlocn->offset) {
|
||||
if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
|
||||
sizeof(vgnamebuf), vgnamebuf)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
|
||||
(isspace(vgnamebuf[len]) || vgnamebuf[len] == '{')) {
|
||||
return rlocn;
|
||||
}
|
||||
rlocn++;
|
||||
if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
|
||||
sizeof(vgnamebuf), vgnamebuf)) {
|
||||
stack;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
|
||||
(isspace(vgnamebuf[len]) || vgnamebuf[len] == '{')) {
|
||||
return rlocn;
|
||||
}
|
||||
|
||||
error:
|
||||
if ((info = info_from_pvid(dev_area->dev->pvid)))
|
||||
lvmcache_update_vgname(info, ORPHAN);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct raw_locn *_vg_posn(struct format_instance *fid,
|
||||
struct device_area *dev_area,
|
||||
const char *vgname)
|
||||
/*
|
||||
* Determine offset for uncommitted metadata
|
||||
*/
|
||||
static uint64_t _next_rlocn_offset(struct raw_locn *rlocn,
|
||||
struct mda_header *mdah)
|
||||
{
|
||||
if (!rlocn)
|
||||
/* Find an empty slot */
|
||||
/* FIXME Assume only one VG per mdah for now */
|
||||
return MDA_HEADER_SIZE;
|
||||
|
||||
struct mda_header *mdah;
|
||||
|
||||
if (!(mdah = _raw_read_mda_header(fid->fmt, dev_area))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return _find_vg_rlocn(dev_area, mdah, vgname);
|
||||
/* Start of free space - round up to next sector; circular */
|
||||
return ((rlocn->offset + rlocn->size +
|
||||
(SECTOR_SIZE - rlocn->size % SECTOR_SIZE) -
|
||||
MDA_HEADER_SIZE) % (mdah->size - MDA_HEADER_SIZE))
|
||||
+ MDA_HEADER_SIZE;
|
||||
}
|
||||
|
||||
static int _raw_holds_vgname(struct format_instance *fid,
|
||||
struct device_area *dev_area, const char *vgname)
|
||||
{
|
||||
int r = 0;
|
||||
struct mda_header *mdah;
|
||||
|
||||
if (!dev_open(dev_area->dev)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_vg_posn(fid, dev_area, vgname))
|
||||
if (!(mdah = _raw_read_mda_header(fid->fmt, dev_area))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_find_vg_rlocn(dev_area, mdah, vgname, 0))
|
||||
r = 1;
|
||||
|
||||
if (!dev_close(dev_area->dev))
|
||||
@@ -241,7 +261,8 @@ static int _raw_holds_vgname(struct format_instance *fid,
|
||||
|
||||
static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct device_area *area)
|
||||
struct device_area *area,
|
||||
int precommit)
|
||||
{
|
||||
struct volume_group *vg = NULL;
|
||||
struct raw_locn *rlocn;
|
||||
@@ -260,8 +281,8 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(rlocn = _vg_posn(fid, area, vgname))) {
|
||||
stack;
|
||||
if (!(rlocn = _find_vg_rlocn(area, mdah, vgname, precommit))) {
|
||||
log_debug("VG %s not found on %s", vgname, dev_name(area->dev));
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -284,8 +305,9 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
log_debug("Read %s metadata (%u) from %s at %" PRIu64 " size %" PRIu64,
|
||||
vg->name, vg->seqno, dev_name(area->dev),
|
||||
log_debug("Read %s %smetadata (%u) from %s at %" PRIu64 " size %"
|
||||
PRIu64, vg->name, precommit ? "pre-commit " : "",
|
||||
vg->seqno, dev_name(area->dev),
|
||||
area->start + rlocn->offset, rlocn->size);
|
||||
|
||||
out:
|
||||
@@ -301,7 +323,16 @@ static struct volume_group *_vg_read_raw(struct format_instance *fid,
|
||||
{
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
|
||||
return _vg_read_raw_area(fid, vgname, &mdac->area);
|
||||
return _vg_read_raw_area(fid, vgname, &mdac->area, 0);
|
||||
}
|
||||
|
||||
static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
|
||||
return _vg_read_raw_area(fid, vgname, &mdac->area, 1);
|
||||
}
|
||||
|
||||
static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
@@ -341,18 +372,8 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name))) {
|
||||
/* Start of free space - round up to next sector; circular */
|
||||
mdac->rlocn.offset =
|
||||
((rlocn->offset + rlocn->size +
|
||||
(SECTOR_SIZE - rlocn->size % SECTOR_SIZE) -
|
||||
MDA_HEADER_SIZE) % (mdah->size - MDA_HEADER_SIZE))
|
||||
+ MDA_HEADER_SIZE;
|
||||
} else {
|
||||
/* Find an empty slot */
|
||||
/* FIXME Assume only one VG per mdah for now */
|
||||
mdac->rlocn.offset = MDA_HEADER_SIZE;
|
||||
}
|
||||
rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, 0);
|
||||
mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah);
|
||||
|
||||
if (!(mdac->rlocn.size = text_vg_export_raw(vg, "", buf, sizeof(buf)))) {
|
||||
log_error("VG %s metadata writing failed", vg->name);
|
||||
@@ -417,8 +438,10 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
struct metadata_area *mda)
|
||||
static int _vg_commit_raw_rlocn(struct format_instance *fid,
|
||||
struct volume_group *vg,
|
||||
struct metadata_area *mda,
|
||||
int precommit)
|
||||
{
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct mda_header *mdah;
|
||||
@@ -445,18 +468,23 @@ static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name))) {
|
||||
rlocn = &mdah->raw_locns[0];
|
||||
if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, 0))) {
|
||||
mdah->raw_locns[0].offset = 0;
|
||||
mdah->raw_locns[1].offset = 0;
|
||||
mdah->raw_locns[2].offset = 0;
|
||||
rlocn = &mdah->raw_locns[0];
|
||||
}
|
||||
|
||||
if (precommit)
|
||||
rlocn++;
|
||||
|
||||
rlocn->offset = mdac->rlocn.offset;
|
||||
rlocn->size = mdac->rlocn.size;
|
||||
rlocn->checksum = mdac->rlocn.checksum;
|
||||
|
||||
log_debug("Committing %s metadata (%u) to %s header at %" PRIu64,
|
||||
vg->name, vg->seqno, dev_name(mdac->area.dev),
|
||||
mdac->area.start);
|
||||
log_debug("%sCommitting %s metadata (%u) to %s header at %" PRIu64,
|
||||
precommit ? "Pre-" : "", vg->name, vg->seqno,
|
||||
dev_name(mdac->area.dev), mdac->area.start);
|
||||
if (!_raw_write_mda_header(fid->fmt, mdac->area.dev, mdac->area.start,
|
||||
mdah)) {
|
||||
log_error("Failed to write metadata area header");
|
||||
@@ -466,12 +494,25 @@ static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
if (!dev_close(mdac->area.dev))
|
||||
if (!precommit && !dev_close(mdac->area.dev))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
return _vg_commit_raw_rlocn(fid, vg, mda, 0);
|
||||
}
|
||||
|
||||
static int _vg_precommit_raw(struct format_instance *fid,
|
||||
struct volume_group *vg,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
return _vg_commit_raw_rlocn(fid, vg, mda, 1);
|
||||
}
|
||||
|
||||
/* Close metadata area devices */
|
||||
static int _vg_revert_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
struct metadata_area *mda)
|
||||
@@ -517,7 +558,7 @@ static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name))) {
|
||||
if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, 0))) {
|
||||
rlocn = &mdah->raw_locns[0];
|
||||
mdah->raw_locns[1].offset = 0;
|
||||
}
|
||||
@@ -543,13 +584,13 @@ static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
|
||||
static struct volume_group *_vg_read_file_name(struct format_instance *fid,
|
||||
const char *vgname,
|
||||
const char *path_live)
|
||||
const char *read_path)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
time_t when;
|
||||
char *desc;
|
||||
|
||||
if (!(vg = text_vg_import_file(fid, path_live, &when, &desc))) {
|
||||
if (!(vg = text_vg_import_file(fid, read_path, &when, &desc))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
@@ -562,10 +603,10 @@ static struct volume_group *_vg_read_file_name(struct format_instance *fid,
|
||||
if (vgname && strcmp(vgname, vg->name)) {
|
||||
pool_free(fid->fmt->cmd->mem, vg);
|
||||
log_err("'%s' does not contain volume group '%s'.",
|
||||
path_live, vgname);
|
||||
read_path, vgname);
|
||||
return NULL;
|
||||
} else
|
||||
log_debug("Read volume group %s from %s", vg->name, path_live);
|
||||
log_debug("Read volume group %s from %s", vg->name, read_path);
|
||||
|
||||
return vg;
|
||||
}
|
||||
@@ -579,6 +620,15 @@ static struct volume_group *_vg_read_file(struct format_instance *fid,
|
||||
return _vg_read_file_name(fid, vgname, tc->path_live);
|
||||
}
|
||||
|
||||
static struct volume_group *_vg_read_precommit_file(struct format_instance *fid,
|
||||
const char *vgname,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
struct text_context *tc = (struct text_context *) mda->metadata_locn;
|
||||
|
||||
return _vg_read_file_name(fid, vgname, tc->path_edit);
|
||||
}
|
||||
|
||||
static int _vg_write_file(struct format_instance *fid, struct volume_group *vg,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
@@ -850,7 +900,7 @@ static int _scan_raw(const struct format_type *fmt)
|
||||
if (vgname_from_mda(fmt, &rl->dev_area, vgnamebuf,
|
||||
sizeof(vgnamebuf))) {
|
||||
if ((vg = _vg_read_raw_area(&fid, vgnamebuf,
|
||||
&rl->dev_area)))
|
||||
&rl->dev_area, 0)))
|
||||
lvmcache_update_vg(vg);
|
||||
}
|
||||
}
|
||||
@@ -1099,34 +1149,6 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _get_pv_from_vg(const struct format_type *fmt, const char *vg_name,
|
||||
const char *id, struct physical_volume *pv)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
int consistent = 0;
|
||||
|
||||
if (!(vg = vg_read(fmt->cmd, vg_name, &consistent))) {
|
||||
log_error("format_text: _vg_read failed to read VG %s",
|
||||
vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!consistent)
|
||||
log_error("Warning: Volume group %s is not consistent",
|
||||
vg_name);
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pvl = list_item(pvh, struct pv_list);
|
||||
if (id_equal(&pvl->pv->id, (const struct id *) id)) {
|
||||
memcpy(pv, pvl->pv, sizeof(*pv));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _add_raw(struct list *raw_list, struct device_area *dev_area)
|
||||
{
|
||||
struct raw_list *rl;
|
||||
@@ -1175,19 +1197,19 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
|
||||
/* Have we already cached vgname? */
|
||||
if (info->vginfo && info->vginfo->vgname && *info->vginfo->vgname &&
|
||||
_get_pv_from_vg(info->fmt, info->vginfo->vgname, info->dev->pvid,
|
||||
pv)) {
|
||||
get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
|
||||
info->dev->pvid, pv)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Perform full scan and try again */
|
||||
if (!memlock()) {
|
||||
lvmcache_label_scan(fmt->cmd, 1);
|
||||
/* Perform full scan (just the first time) and try again */
|
||||
if (!memlock() && !full_scan_done()) {
|
||||
lvmcache_label_scan(fmt->cmd, 2);
|
||||
|
||||
if (info->vginfo && info->vginfo->vgname &&
|
||||
*info->vginfo->vgname &&
|
||||
_get_pv_from_vg(info->fmt, info->vginfo->vgname,
|
||||
info->dev->pvid, pv)) {
|
||||
get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
|
||||
info->dev->pvid, pv)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -1272,6 +1294,7 @@ static void _destroy(const struct format_type *fmt)
|
||||
|
||||
static struct metadata_area_ops _metadata_text_file_ops = {
|
||||
vg_read:_vg_read_file,
|
||||
vg_read_precommit:_vg_read_precommit_file,
|
||||
vg_write:_vg_write_file,
|
||||
vg_remove:_vg_remove_file,
|
||||
vg_commit:_vg_commit_file
|
||||
@@ -1286,8 +1309,10 @@ static struct metadata_area_ops _metadata_text_file_backup_ops = {
|
||||
|
||||
static struct metadata_area_ops _metadata_text_raw_ops = {
|
||||
vg_read:_vg_read_raw,
|
||||
vg_read_precommit:_vg_read_precommit_raw,
|
||||
vg_write:_vg_write_raw,
|
||||
vg_remove:_vg_remove_raw,
|
||||
vg_precommit:_vg_precommit_raw,
|
||||
vg_commit:_vg_commit_raw,
|
||||
vg_revert:_vg_revert_raw
|
||||
};
|
||||
@@ -1643,7 +1668,8 @@ struct format_type *create_text_format(struct cmd_context *cmd)
|
||||
fmt->ops = &_text_handler;
|
||||
fmt->name = FMT_TEXT_NAME;
|
||||
fmt->alias = FMT_TEXT_ALIAS;
|
||||
fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_UNLIMITED_VOLS;
|
||||
fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_PRECOMMIT |
|
||||
FMT_UNLIMITED_VOLS;
|
||||
|
||||
if (!(mda_lists = dbg_malloc(sizeof(struct mda_lists)))) {
|
||||
log_error("Failed to allocate dir_list");
|
||||
@@ -1682,14 +1708,15 @@ struct format_type *create_text_format(struct cmd_context *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
if (!(cn = find_config_node(cmd->cft->root, "metadata/disk_areas")))
|
||||
return fmt;
|
||||
|
||||
for (cn = cn->child; cn; cn = cn->sib) {
|
||||
if (!_get_config_disk_area(cmd, cn, &mda_lists->raws))
|
||||
goto err;
|
||||
if ((cn = find_config_node(cmd->cft->root, "metadata/disk_areas"))) {
|
||||
for (cn = cn->child; cn; cn = cn->sib) {
|
||||
if (!_get_config_disk_area(cmd, cn, &mda_lists->raws))
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
log_very_verbose("Initialised format: %s", fmt->name);
|
||||
|
||||
return fmt;
|
||||
|
||||
err:
|
||||
|
@@ -22,7 +22,8 @@
|
||||
#include "toolcontext.h"
|
||||
#include "lvmcache.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "segtypes.h"
|
||||
#include "pv_alloc.h"
|
||||
#include "segtype.h"
|
||||
#include "text_import.h"
|
||||
|
||||
typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
|
||||
@@ -31,7 +32,7 @@ typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
|
||||
struct hash_table * pv_hash);
|
||||
|
||||
#define _read_int32(root, path, result) \
|
||||
get_config_uint32(root, path, result)
|
||||
get_config_uint32(root, path, (uint32_t *) result)
|
||||
|
||||
#define _read_uint32(root, path, result) \
|
||||
get_config_uint32(root, path, result)
|
||||
@@ -190,6 +191,8 @@ static int _read_pv(struct format_instance *fid, struct pool *mem,
|
||||
}
|
||||
|
||||
list_init(&pv->tags);
|
||||
list_init(&pv->segments);
|
||||
list_init(&pv->free_segments);
|
||||
|
||||
/* Optional tags */
|
||||
if ((cn = find_config_node(pvn, "tags")) &&
|
||||
@@ -208,6 +211,11 @@ static int _read_pv(struct format_instance *fid, struct pool *mem,
|
||||
pv->pe_alloc_count = 0;
|
||||
pv->fmt = fid->fmt;
|
||||
|
||||
if (!alloc_pv_segment_whole_pv(mem, pv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
vg->pv_count++;
|
||||
list_add(&vg->pvs, &pvl->list);
|
||||
|
||||
@@ -283,19 +291,13 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(seg = alloc_lv_segment(mem, area_count))) {
|
||||
if (!(seg = alloc_lv_segment(mem, segtype, lv, start_extent,
|
||||
extent_count, 0, 0, area_count,
|
||||
extent_count, 0, 0))) {
|
||||
log_error("Segment allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->lv = lv;
|
||||
seg->le = start_extent;
|
||||
seg->len = extent_count;
|
||||
seg->area_len = extent_count;
|
||||
seg->status = 0u;
|
||||
seg->segtype = segtype;
|
||||
seg->extents_copied = 0u;
|
||||
|
||||
if (seg->segtype->ops->text_import &&
|
||||
!seg->segtype->ops->text_import(seg, sn, pv_hash)) {
|
||||
stack;
|
||||
@@ -361,19 +363,14 @@ int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
|
||||
|
||||
/* FIXME Cope if LV not yet read in */
|
||||
if ((pv = hash_lookup(pv_hash, cv->v.str))) {
|
||||
seg->area[s].type = AREA_PV;
|
||||
seg->area[s].u.pv.pv = pv;
|
||||
seg->area[s].u.pv.pe = cv->next->v.i;
|
||||
set_lv_segment_area_pv(seg, s, pv, cv->next->v.i);
|
||||
/*
|
||||
* Adjust extent counts in the pv and vg.
|
||||
*/
|
||||
pv->pe_alloc_count += seg->area_len;
|
||||
seg->lv->vg->free_count -= seg->area_len;
|
||||
|
||||
} else if ((lv1 = find_lv(seg->lv->vg, cv->v.str))) {
|
||||
seg->area[s].type = AREA_LV;
|
||||
seg->area[s].u.lv.lv = lv1;
|
||||
seg->area[s].u.lv.le = cv->next->v.i;
|
||||
set_lv_segment_area_lv(seg, s, lv1, cv->next->v.i);
|
||||
} else {
|
||||
log_error("Couldn't find volume '%s' "
|
||||
"for segment '%s'.",
|
||||
@@ -508,6 +505,8 @@ static int _read_lvnames(struct format_instance *fid, struct pool *mem,
|
||||
if (!_read_int32(lvn, "read_ahead", &lv->read_ahead))
|
||||
lv->read_ahead = 0;
|
||||
|
||||
lv->snapshot = NULL;
|
||||
list_init(&lv->snapshot_segs);
|
||||
list_init(&lv->segments);
|
||||
list_init(&lv->tags);
|
||||
|
||||
@@ -561,24 +560,29 @@ static int _read_lvsegs(struct format_instance *fid, struct pool *mem,
|
||||
|
||||
lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size;
|
||||
|
||||
/* Skip this for now for snapshots */
|
||||
if (!(lv->status & SNAPSHOT)) {
|
||||
lv->minor = -1;
|
||||
if ((lv->status & FIXED_MINOR) &&
|
||||
!_read_int32(lvn, "minor", &lv->minor)) {
|
||||
log_error("Couldn't read minor number for logical "
|
||||
"volume %s.", lv->name);
|
||||
return 0;
|
||||
}
|
||||
lv->major = -1;
|
||||
if ((lv->status & FIXED_MINOR) &&
|
||||
!_read_int32(lvn, "major", &lv->major)) {
|
||||
log_error("Couldn't read major number for logical "
|
||||
"volume %s.", lv->name);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* FIXME We now have 2 LVs for each snapshot. The real one was
|
||||
* created by vg_add_snapshot from the segment text_import.
|
||||
*/
|
||||
if (lv->status & SNAPSHOT) {
|
||||
vg->lv_count--;
|
||||
list_del(&lvl->list);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lv->minor = -1;
|
||||
if ((lv->status & FIXED_MINOR) &&
|
||||
!_read_int32(lvn, "minor", &lv->minor)) {
|
||||
log_error("Couldn't read minor number for logical "
|
||||
"volume %s.", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv->major = -1;
|
||||
if ((lv->status & FIXED_MINOR) &&
|
||||
!_read_int32(lvn, "major", &lv->major)) {
|
||||
log_error("Couldn't read major number for logical "
|
||||
"volume %s.", lv->name);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -736,7 +740,6 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
}
|
||||
|
||||
list_init(&vg->lvs);
|
||||
list_init(&vg->snapshots);
|
||||
list_init(&vg->tags);
|
||||
|
||||
/* Optional tags */
|
||||
|
@@ -117,12 +117,17 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
struct labeller_i *li;
|
||||
struct labeller *r = NULL;
|
||||
struct label_header *lh;
|
||||
struct lvmcache_info *info;
|
||||
uint64_t sector;
|
||||
int found = 0;
|
||||
char readbuf[LABEL_SCAN_SIZE];
|
||||
|
||||
if (!dev_open(dev)) {
|
||||
stack;
|
||||
|
||||
if ((info = info_from_pvid(dev->pvid)))
|
||||
lvmcache_update_vgname(info, ORPHAN);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -182,10 +187,13 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
log_very_verbose("%s: No label detected", dev_name(dev));
|
||||
|
||||
out:
|
||||
if (!found) {
|
||||
if ((info = info_from_pvid(dev->pvid)))
|
||||
lvmcache_update_vgname(info, ORPHAN);
|
||||
log_very_verbose("%s: No label detected", dev_name(dev));
|
||||
}
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
@@ -279,7 +287,7 @@ int label_read(struct device *dev, struct label **result)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((r = l->ops->read(l, dev, buf, result)) && result && *result)
|
||||
if ((r = (l->ops->read)(l, dev, buf, result)) && result && *result)
|
||||
(*result)->sector = sector;
|
||||
|
||||
return r;
|
||||
@@ -309,7 +317,7 @@ int label_write(struct device *dev, struct label *label)
|
||||
lh->sector_xl = xlate64(label->sector);
|
||||
lh->offset_xl = xlate32(sizeof(*lh));
|
||||
|
||||
if (!label->labeller->ops->write(label, buf)) {
|
||||
if (!(label->labeller->ops->write)(label, buf)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
@@ -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)
|
||||
@@ -148,10 +147,16 @@ 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));
|
||||
return 0;
|
||||
if (outheader->status != 0) {
|
||||
errno = outheader->status;
|
||||
|
||||
/* Only return an error here if there are no node-specific
|
||||
errors present in the message that might have more detail */
|
||||
if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) {
|
||||
log_error("cluster request failed: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -329,7 +334,7 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
|
||||
* VG locks are just that: locks, and have no side effects
|
||||
* so we only need to do them on the local node because all
|
||||
* locks are cluster-wide.
|
||||
* Also, if the lock is exclusive it makes no sense to try to
|
||||
* Also, if the lock is exclusive it makes no sense to try to
|
||||
* acquire it on all nodes, so just do that on the local node too.
|
||||
*/
|
||||
if (cmd == CLVMD_CMD_LOCK_VG ||
|
||||
@@ -342,10 +347,11 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
|
||||
|
||||
/* If any nodes were down then display them and return an error */
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
if (response[i].status == -EHOSTDOWN) {
|
||||
if (response[i].status == EHOSTDOWN) {
|
||||
log_error("clvmd not running on node %s",
|
||||
response[i].node);
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
} else if (response[i].status) {
|
||||
log_error("Error locking on node %s: %s",
|
||||
response[i].node,
|
||||
@@ -353,6 +359,7 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
|
||||
response[i].response :
|
||||
strerror(response[i].status));
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,7 +446,7 @@ int init_cluster_locking(struct locking_type *locking, struct config_tree *cft)
|
||||
locking->lock_resource = _lock_resource;
|
||||
locking->fin_locking = _locking_end;
|
||||
locking->reset_locking = _reset_locking;
|
||||
locking->flags = LCK_PRE_MEMLOCK;
|
||||
locking->flags = LCK_PRE_MEMLOCK | LCK_CLUSTERED;
|
||||
|
||||
_clvmd_sock = _open_local_sock();
|
||||
if (_clvmd_sock == -1)
|
||||
@@ -456,6 +463,7 @@ int locking_init(int type, struct config_tree *cf, uint32_t *flags)
|
||||
|
||||
/* Ask LVM to lock memory before calling us */
|
||||
*flags |= LCK_PRE_MEMLOCK;
|
||||
*flags |= LCK_CLUSTERED;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@@ -41,7 +41,7 @@ static char _lock_dir[NAME_LEN];
|
||||
|
||||
static sig_t _oldhandler;
|
||||
static sigset_t _fullsigset, _intsigset;
|
||||
static int _handler_installed;
|
||||
static volatile sig_atomic_t _handler_installed;
|
||||
|
||||
static int _release_lock(const char *file, int unlock)
|
||||
{
|
||||
@@ -95,38 +95,40 @@ static void _reset_file_locking(void)
|
||||
static void _remove_ctrl_c_handler()
|
||||
{
|
||||
siginterrupt(SIGINT, 0);
|
||||
if (!_handler_installed || _oldhandler == SIG_ERR)
|
||||
if (!_handler_installed)
|
||||
return;
|
||||
|
||||
_handler_installed = 0;
|
||||
|
||||
sigprocmask(SIG_SETMASK, &_fullsigset, NULL);
|
||||
if (signal(SIGINT, _oldhandler) == SIG_ERR)
|
||||
log_sys_error("signal", "_remove_ctrl_c_handler");
|
||||
|
||||
_handler_installed = 0;
|
||||
}
|
||||
|
||||
static void _trap_ctrl_c(int sig)
|
||||
{
|
||||
_remove_ctrl_c_handler();
|
||||
log_error("CTRL-c detected: giving up waiting for lock");
|
||||
return;
|
||||
}
|
||||
|
||||
static void _install_ctrl_c_handler()
|
||||
{
|
||||
if ((_oldhandler = signal(SIGINT, _trap_ctrl_c)) == SIG_ERR)
|
||||
_handler_installed = 1;
|
||||
|
||||
if ((_oldhandler = signal(SIGINT, _trap_ctrl_c)) == SIG_ERR) {
|
||||
_handler_installed = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
sigprocmask(SIG_SETMASK, &_intsigset, NULL);
|
||||
siginterrupt(SIGINT, 1);
|
||||
|
||||
_handler_installed = 1;
|
||||
}
|
||||
|
||||
static int _lock_file(const char *file, int flags)
|
||||
{
|
||||
int operation;
|
||||
int r = 1;
|
||||
int old_errno;
|
||||
|
||||
struct lock_list *ll;
|
||||
struct stat buf1, buf2;
|
||||
@@ -176,10 +178,12 @@ static int _lock_file(const char *file, int flags)
|
||||
_install_ctrl_c_handler();
|
||||
|
||||
r = flock(ll->lf, operation);
|
||||
old_errno = errno;
|
||||
if (!(flags & LCK_NONBLOCK))
|
||||
_remove_ctrl_c_handler();
|
||||
|
||||
if (r) {
|
||||
errno = old_errno;
|
||||
log_sys_error("flock", ll->res);
|
||||
goto err;
|
||||
}
|
||||
|
@@ -124,6 +124,8 @@ static inline void _update_vg_lock_count(int flags)
|
||||
*/
|
||||
int init_locking(int type, struct config_tree *cft)
|
||||
{
|
||||
init_lockingfailed(0);
|
||||
|
||||
switch (type) {
|
||||
case 0:
|
||||
init_no_locking(&_locking, cft);
|
||||
@@ -165,6 +167,7 @@ int init_locking(int type, struct config_tree *cft)
|
||||
log_verbose("Locking disabled - only read operations permitted.");
|
||||
|
||||
init_no_locking(&_locking, cft);
|
||||
init_lockingfailed(1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -321,3 +324,9 @@ int vg_write_lock_held(void)
|
||||
{
|
||||
return _vg_write_lock_held;
|
||||
}
|
||||
|
||||
int locking_is_clustered(void)
|
||||
{
|
||||
return (_locking.flags & LCK_CLUSTERED) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
@@ -20,6 +20,7 @@ int init_locking(int type, struct config_tree *cf);
|
||||
void fin_locking(void);
|
||||
void reset_locking(void);
|
||||
int vg_write_lock_held(void);
|
||||
int locking_is_clustered(void);
|
||||
|
||||
/*
|
||||
* LCK_VG:
|
||||
|
@@ -23,6 +23,7 @@ typedef void (*fin_lock_fn) (void);
|
||||
typedef void (*reset_lock_fn) (void);
|
||||
|
||||
#define LCK_PRE_MEMLOCK 0x00000001 /* Is memlock() needed before calls? */
|
||||
#define LCK_CLUSTERED 0x00000002
|
||||
|
||||
struct locking_type {
|
||||
uint32_t flags;
|
||||
|
@@ -28,7 +28,9 @@ 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 _full_scan_done = 0; /* Restrict to one full scan during each cmd */
|
||||
static int _debug_level = 0;
|
||||
static int _syslog = 0;
|
||||
static int _log_to_file = 0;
|
||||
@@ -38,6 +40,7 @@ static int _indent = 1;
|
||||
static int _log_cmd_name = 0;
|
||||
static int _log_suppress = 0;
|
||||
static int _ignorelockingfailure = 0;
|
||||
static int _lockingfailed = 0;
|
||||
static int _security_level = SECURITY_LEVEL;
|
||||
static char _cmd_name[30] = "";
|
||||
static char _msg_prefix[30] = " ";
|
||||
@@ -138,16 +141,31 @@ void init_partial(int level)
|
||||
_partial = level;
|
||||
}
|
||||
|
||||
void init_md_filtering(int level)
|
||||
{
|
||||
_md_filtering = level;
|
||||
}
|
||||
|
||||
void init_pvmove(int level)
|
||||
{
|
||||
_pvmove = level;
|
||||
}
|
||||
|
||||
void init_full_scan_done(int level)
|
||||
{
|
||||
_full_scan_done = level;
|
||||
}
|
||||
|
||||
void init_ignorelockingfailure(int level)
|
||||
{
|
||||
_ignorelockingfailure = level;
|
||||
}
|
||||
|
||||
void init_lockingfailed(int level)
|
||||
{
|
||||
_lockingfailed = level;
|
||||
}
|
||||
|
||||
void init_security_level(int level)
|
||||
{
|
||||
_security_level = level;
|
||||
@@ -187,11 +205,26 @@ int partial_mode()
|
||||
return _partial;
|
||||
}
|
||||
|
||||
int md_filtering()
|
||||
{
|
||||
return _md_filtering;
|
||||
}
|
||||
|
||||
int pvmove_mode()
|
||||
{
|
||||
return _pvmove;
|
||||
}
|
||||
|
||||
int full_scan_done()
|
||||
{
|
||||
return _full_scan_done;
|
||||
}
|
||||
|
||||
int lockingfailed()
|
||||
{
|
||||
return _lockingfailed;
|
||||
}
|
||||
|
||||
int ignorelockingfailure()
|
||||
{
|
||||
return _ignorelockingfailure;
|
||||
@@ -215,7 +248,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 +276,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 +327,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 +336,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);
|
||||
}
|
||||
|
@@ -63,21 +63,27 @@ 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_full_scan_done(int level);
|
||||
void init_debug(int level);
|
||||
void init_cmd_name(int status);
|
||||
void init_msg_prefix(const char *prefix);
|
||||
void init_indent(int indent);
|
||||
void init_ignorelockingfailure(int level);
|
||||
void init_lockingfailed(int level);
|
||||
void init_security_level(int level);
|
||||
|
||||
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 full_scan_done(void);
|
||||
int debug_level(void);
|
||||
int ignorelockingfailure(void);
|
||||
int lockingfailed(void);
|
||||
int security_level(void);
|
||||
|
||||
/* Suppress messages to stdout/stderr */
|
||||
|
@@ -16,5 +16,23 @@
|
||||
#ifndef _LVM_LV_ALLOC_H
|
||||
#include "pool.h"
|
||||
|
||||
struct lv_segment *alloc_lv_segment(struct pool *mem, uint32_t num_areas);
|
||||
struct lv_segment *alloc_lv_segment(struct pool *mem,
|
||||
struct segment_type *segtype,
|
||||
struct logical_volume *lv,
|
||||
uint32_t le, uint32_t len,
|
||||
uint32_t status,
|
||||
uint32_t stripe_size,
|
||||
uint32_t area_count,
|
||||
uint32_t area_len,
|
||||
uint32_t chunk_size,
|
||||
uint32_t extents_copied);
|
||||
|
||||
struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
|
||||
uint32_t allocated);
|
||||
|
||||
void set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num,
|
||||
struct physical_volume *pv, uint32_t pe);
|
||||
void set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
|
||||
struct logical_volume *lv, uint32_t le);
|
||||
|
||||
#endif
|
||||
|
@@ -21,7 +21,7 @@
|
||||
#include "toolcontext.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "display.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
|
||||
/*
|
||||
* These functions adjust the pe counts in pv's
|
||||
@@ -61,22 +61,57 @@ static void _put_extents(struct lv_segment *seg)
|
||||
}
|
||||
}
|
||||
|
||||
struct lv_segment *alloc_lv_segment(struct pool *mem, uint32_t num_areas)
|
||||
struct lv_segment *alloc_lv_segment(struct pool *mem,
|
||||
struct segment_type *segtype,
|
||||
struct logical_volume *lv,
|
||||
uint32_t le, uint32_t len,
|
||||
uint32_t status,
|
||||
uint32_t stripe_size,
|
||||
uint32_t area_count,
|
||||
uint32_t area_len,
|
||||
uint32_t chunk_size,
|
||||
uint32_t extents_copied)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
uint32_t len = sizeof(*seg) + (num_areas * sizeof(seg->area[0]));
|
||||
uint32_t sz = sizeof(*seg) + (area_count * sizeof(seg->area[0]));
|
||||
|
||||
if (!(seg = pool_zalloc(mem, len))) {
|
||||
if (!(seg = pool_zalloc(mem, sz))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
seg->area_count = num_areas;
|
||||
seg->segtype = segtype;
|
||||
seg->lv = lv;
|
||||
seg->le = le;
|
||||
seg->len = len;
|
||||
seg->status = status;
|
||||
seg->stripe_size = stripe_size;
|
||||
seg->area_count = area_count;
|
||||
seg->area_len = area_len;
|
||||
seg->chunk_size = chunk_size;
|
||||
seg->extents_copied = extents_copied;
|
||||
list_init(&seg->tags);
|
||||
|
||||
return seg;
|
||||
}
|
||||
|
||||
void set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num,
|
||||
struct physical_volume *pv, uint32_t pe)
|
||||
{
|
||||
seg->area[area_num].type = AREA_PV;
|
||||
seg->area[area_num].u.pv.pv = pv;
|
||||
seg->area[area_num].u.pv.pe = pe;
|
||||
seg->area[area_num].u.pv.pvseg = NULL;
|
||||
}
|
||||
|
||||
void set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
|
||||
struct logical_volume *lv, uint32_t le)
|
||||
{
|
||||
seg->area[area_num].type = AREA_LV;
|
||||
seg->area[area_num].u.lv.lv = lv;
|
||||
seg->area[area_num].u.lv.le = le;
|
||||
}
|
||||
|
||||
static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
|
||||
uint32_t stripe_size,
|
||||
struct segment_type *segtype,
|
||||
@@ -98,24 +133,17 @@ static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
|
||||
if (smallest < area_len)
|
||||
area_len = smallest;
|
||||
|
||||
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, area_count))) {
|
||||
log_err("Couldn't allocate new parallel segment.");
|
||||
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, *ix,
|
||||
area_len * (striped ? area_count : 1),
|
||||
0u, stripe_size, area_count, area_len,
|
||||
0u, 0u))) {
|
||||
log_error("Couldn't allocate new parallel segment.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->lv = lv;
|
||||
seg->segtype = segtype;
|
||||
seg->le = *ix;
|
||||
seg->len = area_len * (striped ? area_count : 1);
|
||||
seg->area_len = area_len;
|
||||
seg->stripe_size = stripe_size;
|
||||
seg->extents_copied = 0u;
|
||||
|
||||
for (s = 0; s < area_count; s++) {
|
||||
struct pv_area *pva = areas[s];
|
||||
seg->area[s].type = AREA_PV;
|
||||
seg->area[s].u.pv.pv = pva->map->pvl->pv;
|
||||
seg->area[s].u.pv.pe = pva->start;
|
||||
set_lv_segment_area_pv(seg, s, pva->map->pvl->pv, pva->start);
|
||||
consume_pv_area(pva, area_len);
|
||||
}
|
||||
|
||||
@@ -221,34 +249,31 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t *ix,
|
||||
{
|
||||
uint32_t count, remaining;
|
||||
struct lv_segment *seg;
|
||||
struct segment_type *segtype;
|
||||
|
||||
count = pva->count;
|
||||
remaining = lv->le_count - *ix;
|
||||
if (count > remaining)
|
||||
count = remaining;
|
||||
|
||||
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, 1))) {
|
||||
log_err("Couldn't allocate new stripe segment.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->lv = lv;
|
||||
if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd, "striped"))) {
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, "striped"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
seg->le = *ix;
|
||||
seg->len = count;
|
||||
seg->area_len = count;
|
||||
seg->stripe_size = 0;
|
||||
seg->area[0].type = AREA_PV;
|
||||
seg->area[0].u.pv.pv = map->pvl->pv;
|
||||
seg->area[0].u.pv.pe = pva->start;
|
||||
|
||||
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, *ix,
|
||||
count, 0, 0, 1, count, 0, 0))) {
|
||||
log_error("Couldn't allocate new stripe segment.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
set_lv_segment_area_pv(seg, 0, map->pvl->pv, pva->start);
|
||||
|
||||
list_add(&lv->segments, &seg->list);
|
||||
|
||||
consume_pv_area(pva, count);
|
||||
*ix += count;
|
||||
consume_pv_area(pva, seg->len);
|
||||
*ix += seg->len;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -266,30 +291,21 @@ static int _alloc_mirrored_area(struct logical_volume *lv, uint32_t *ix,
|
||||
if (count > remaining)
|
||||
count = remaining;
|
||||
|
||||
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, 2))) {
|
||||
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, *ix,
|
||||
count, 0, 0, 2, count, 0, 0))) {
|
||||
log_err("Couldn't allocate new mirrored segment.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->lv = lv;
|
||||
seg->segtype = segtype;
|
||||
seg->le = *ix;
|
||||
seg->status = 0u;
|
||||
seg->len = count;
|
||||
seg->area_len = count;
|
||||
seg->stripe_size = 0;
|
||||
seg->extents_copied = 0u;
|
||||
/* FIXME Remove AREA_PV restriction here? */
|
||||
seg->area[0].type = AREA_PV;
|
||||
seg->area[0].u.pv.pv = mirrored_pv;
|
||||
seg->area[0].u.pv.pe = mirrored_pe;
|
||||
seg->area[1].type = AREA_PV;
|
||||
seg->area[1].u.pv.pv = map->pvl->pv;
|
||||
seg->area[1].u.pv.pe = pva->start;
|
||||
set_lv_segment_area_pv(seg, 0, mirrored_pv, mirrored_pe);
|
||||
set_lv_segment_area_pv(seg, 1, map->pvl->pv, pva->start);
|
||||
|
||||
list_add(&lv->segments, &seg->list);
|
||||
|
||||
consume_pv_area(pva, count);
|
||||
*ix += count;
|
||||
consume_pv_area(pva, seg->len);
|
||||
*ix += seg->len;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -421,25 +437,44 @@ static int _alloc_virtual(struct logical_volume *lv,
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
|
||||
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, 0))) {
|
||||
log_err("Couldn't allocate new zero segment.");
|
||||
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, allocated,
|
||||
lv->le_count - allocated, 0, 0, 0,
|
||||
lv->le_count - allocated, 0, 0))) {
|
||||
log_error("Couldn't allocate new zero segment.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->lv = lv;
|
||||
seg->segtype = segtype;
|
||||
seg->status = 0u;
|
||||
seg->le = allocated;
|
||||
seg->len = lv->le_count - allocated;
|
||||
seg->area_len = seg->len;
|
||||
seg->stripe_size = 0;
|
||||
seg->extents_copied = 0u;
|
||||
list_add(&lv->segments, &seg->list);
|
||||
lv->status |= VIRTUAL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
|
||||
uint32_t allocated)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
struct segment_type *segtype;
|
||||
|
||||
segtype = get_segtype_from_string(lv->vg->cmd, "snapshot");
|
||||
if (!segtype) {
|
||||
log_error("Failed to find snapshot segtype");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, allocated,
|
||||
lv->le_count - allocated, 0, 0, 0,
|
||||
lv->le_count - allocated, 0, 0))) {
|
||||
log_error("Couldn't allocate new snapshot segment.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_add(&lv->segments, &seg->list);
|
||||
lv->status |= VIRTUAL;
|
||||
|
||||
return seg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Chooses a correct allocation policy.
|
||||
*/
|
||||
@@ -458,7 +493,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;
|
||||
}
|
||||
@@ -543,8 +578,10 @@ static char *_generate_lv_name(struct volume_group *vg, const char *format,
|
||||
struct logical_volume *lv_create_empty(struct format_instance *fi,
|
||||
const char *name,
|
||||
const char *name_format,
|
||||
union lvid *lvid,
|
||||
uint32_t status,
|
||||
alloc_policy_t alloc,
|
||||
int import,
|
||||
struct volume_group *vg)
|
||||
{
|
||||
struct cmd_context *cmd = vg->cmd;
|
||||
@@ -565,7 +602,8 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log_verbose("Creating logical volume %s", name);
|
||||
if (!import)
|
||||
log_verbose("Creating logical volume %s", name);
|
||||
|
||||
if (!(ll = pool_zalloc(cmd->mem, sizeof(*ll))) ||
|
||||
!(ll->lv = pool_zalloc(cmd->mem, sizeof(*ll->lv)))) {
|
||||
@@ -592,9 +630,14 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
|
||||
lv->minor = -1;
|
||||
lv->size = UINT64_C(0);
|
||||
lv->le_count = 0;
|
||||
lv->snapshot = NULL;
|
||||
list_init(&lv->snapshot_segs);
|
||||
list_init(&lv->segments);
|
||||
list_init(&lv->tags);
|
||||
|
||||
if (lvid)
|
||||
lv->lvid = *lvid;
|
||||
|
||||
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
|
||||
stack;
|
||||
if (ll)
|
||||
@@ -602,7 +645,9 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vg->lv_count++;
|
||||
if (!import)
|
||||
vg->lv_count++;
|
||||
|
||||
list_add(&vg->lvs, &ll->list);
|
||||
|
||||
return lv;
|
||||
@@ -623,6 +668,16 @@ int lv_extend(struct format_instance *fid,
|
||||
lv->le_count += extents;
|
||||
lv->size += (uint64_t) extents *lv->vg->extent_size;
|
||||
|
||||
if (fid->fmt->ops->segtype_supported &&
|
||||
!fid->fmt->ops->segtype_supported(fid, segtype)) {
|
||||
log_error("Metadata format (%s) does not support required "
|
||||
"LV segment type (%s).", fid->fmt->name,
|
||||
segtype->name);
|
||||
log_error("Consider changing the metadata format by running "
|
||||
"vgconvert.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_allocate(lv->vg, lv, allocatable_pvs, old_le_count, alloc,
|
||||
segtype, stripes, stripe_size, mirrors, mirrored_pv,
|
||||
mirrored_pe, status)) {
|
||||
|
@@ -18,7 +18,7 @@
|
||||
#include "toolcontext.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "str_list.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
|
||||
/*
|
||||
* Attempt to merge two adjacent segments.
|
||||
@@ -98,11 +98,17 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
|
||||
}
|
||||
|
||||
/* Clone the existing segment */
|
||||
if (!(split_seg = alloc_lv_segment(lv->vg->cmd->mem, seg->area_count))) {
|
||||
log_error("Couldn't allocate new LV segment.");
|
||||
if (!(split_seg = alloc_lv_segment(lv->vg->cmd->mem, seg->segtype,
|
||||
seg->lv, seg->le, seg->len,
|
||||
seg->status, seg->stripe_size,
|
||||
seg->area_count, seg->area_len,
|
||||
seg->chunk_size,
|
||||
seg->extents_copied))) {
|
||||
log_error("Couldn't allocate cloned LV segment.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME Avoid the memcpy */
|
||||
len = sizeof(*seg) + (seg->area_count * sizeof(seg->area[0]));
|
||||
memcpy(split_seg, seg, len);
|
||||
|
||||
|
@@ -21,6 +21,8 @@
|
||||
#include "lvm-string.h"
|
||||
#include "lvmcache.h"
|
||||
#include "memlock.h"
|
||||
#include "str_list.h"
|
||||
#include "pv_alloc.h"
|
||||
|
||||
static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
|
||||
const char *pv_name)
|
||||
@@ -109,6 +111,57 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _copy_pv(struct physical_volume *pv_to,
|
||||
struct physical_volume *pv_from)
|
||||
{
|
||||
memcpy(pv_to, pv_from, sizeof(*pv_to));
|
||||
|
||||
if (!str_list_dup(pv_to->fmt->cmd->mem, &pv_to->tags, &pv_from->tags)) {
|
||||
log_error("PV tags duplication failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!peg_dup(pv_to->fmt->cmd->mem, &pv_to->segments,
|
||||
&pv_to->free_segments, &pv_from->segments)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
|
||||
const char *id, struct physical_volume *pv)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
int consistent = 0;
|
||||
|
||||
if (!(vg = vg_read(fmt->cmd, vg_name, &consistent))) {
|
||||
log_error("get_pv_from_vg_by_id: vg_read failed to read VG %s",
|
||||
vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!consistent)
|
||||
log_error("Warning: Volume group %s is not consistent",
|
||||
vg_name);
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pvl = list_item(pvh, struct pv_list);
|
||||
if (id_equal(&pvl->pv->id, (const struct id *) id)) {
|
||||
if (!_copy_pv(pv, pvl->pv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vg_rename(struct cmd_context *cmd, struct volume_group *vg,
|
||||
const char *new_name)
|
||||
{
|
||||
@@ -221,7 +274,6 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||
list_init(&vg->lvs);
|
||||
|
||||
vg->snapshot_count = 0;
|
||||
list_init(&vg->snapshots);
|
||||
|
||||
list_init(&vg->tags);
|
||||
|
||||
@@ -249,6 +301,153 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _recalc_extents(uint32_t *extents, const char *desc1,
|
||||
const char *desc2, uint32_t old_size,
|
||||
uint32_t new_size)
|
||||
{
|
||||
uint64_t size = (uint64_t) old_size * (*extents);
|
||||
|
||||
if (size % new_size) {
|
||||
log_error("New size %" PRIu64 " for %s%s not an exact number "
|
||||
"of new extents.", size, desc1, desc2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size /= new_size;
|
||||
|
||||
if (size > UINT32_MAX) {
|
||||
log_error("New extent count %" PRIu64 " for %s%s exceeds "
|
||||
"32 bits.", size, desc1, desc2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*extents = (uint32_t) size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
|
||||
uint32_t new_size)
|
||||
{
|
||||
uint32_t old_size = vg->extent_size;
|
||||
struct pv_list *pvl;
|
||||
struct lv_list *lvl;
|
||||
struct physical_volume *pv;
|
||||
struct logical_volume *lv;
|
||||
struct lv_segment *seg;
|
||||
uint32_t s;
|
||||
|
||||
vg->extent_size = new_size;
|
||||
|
||||
if (vg->fid->fmt->ops->vg_setup &&
|
||||
!vg->fid->fmt->ops->vg_setup(vg->fid, vg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_recalc_extents(&vg->extent_count, vg->name, "", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_recalc_extents(&vg->free_count, vg->name, " free space",
|
||||
old_size, new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* foreach PV */
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
pv = pvl->pv;
|
||||
|
||||
pv->pe_size = new_size;
|
||||
if (!_recalc_extents(&pv->pe_count, dev_name(pv->dev), "",
|
||||
old_size, new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_recalc_extents(&pv->pe_alloc_count, dev_name(pv->dev),
|
||||
" allocated space", old_size, new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* foreach LV */
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
lv = lvl->lv;
|
||||
|
||||
if (!_recalc_extents(&lv->le_count, lv->name, "", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (!_recalc_extents(&seg->le, lv->name,
|
||||
" segment start", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_recalc_extents(&seg->len, lv->name,
|
||||
" segment length", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_recalc_extents(&seg->area_len, lv->name,
|
||||
" area length", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_recalc_extents(&seg->extents_copied, lv->name,
|
||||
" extents moved", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* foreach area */
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
switch (seg->area[s].type) {
|
||||
case AREA_PV:
|
||||
if (!_recalc_extents
|
||||
(&seg->area[s].u.pv.pe, lv->name,
|
||||
" area start", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case AREA_LV:
|
||||
if (!_recalc_extents
|
||||
(&seg->area[s].u.lv.le, lv->name,
|
||||
" area start", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log_error("Unrecognised segment type "
|
||||
"%u", seg->area[s].type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Sizes in sectors */
|
||||
struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
struct device *dev,
|
||||
@@ -267,10 +466,13 @@ struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!id)
|
||||
id_create(&pv->id);
|
||||
else
|
||||
if (id)
|
||||
memcpy(&pv->id, id, sizeof(*id));
|
||||
else if (!id_create(&pv->id)) {
|
||||
log_error("Failed to create random uuid for %s.",
|
||||
dev_name(dev));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pv->dev = dev;
|
||||
|
||||
@@ -308,6 +510,8 @@ struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
pv->fmt = fmt;
|
||||
|
||||
list_init(&pv->tags);
|
||||
list_init(&pv->segments);
|
||||
list_init(&pv->free_segments);
|
||||
|
||||
if (!fmt->ops->pv_setup(fmt, pe_start, existing_extent_count,
|
||||
existing_extent_size,
|
||||
@@ -504,6 +708,7 @@ int vg_write(struct volume_group *vg)
|
||||
/* Revert */
|
||||
list_uniterate(mdah2, &vg->fid->metadata_areas, mdah) {
|
||||
mda = list_item(mdah2, struct metadata_area);
|
||||
|
||||
if (mda->ops->vg_revert &&
|
||||
!mda->ops->vg_revert(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
@@ -525,6 +730,24 @@ int vg_write(struct volume_group *vg)
|
||||
}
|
||||
}
|
||||
|
||||
/* Now pre-commit each copy of the new metadata */
|
||||
list_iterate(mdah, &vg->fid->metadata_areas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
if (mda->ops->vg_precommit &&
|
||||
!mda->ops->vg_precommit(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
/* Revert */
|
||||
list_iterate(mdah2, &vg->fid->metadata_areas) {
|
||||
mda = list_item(mdah2, struct metadata_area);
|
||||
if (mda->ops->vg_revert &&
|
||||
!mda->ops->vg_revert(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -595,7 +818,6 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
|
||||
}
|
||||
list_init(&vg->pvs);
|
||||
list_init(&vg->lvs);
|
||||
list_init(&vg->snapshots);
|
||||
list_init(&vg->tags);
|
||||
vg->cmd = cmd;
|
||||
if (!(vg->name = pool_strdup(cmd->mem, ORPHAN))) {
|
||||
@@ -627,8 +849,9 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
|
||||
* and take appropriate action if it isn't (e.g. abort; get write lock
|
||||
* and call vg_read again).
|
||||
*/
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
|
||||
int *consistent)
|
||||
static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
const char *vgname,
|
||||
int *consistent, int precommitted)
|
||||
{
|
||||
struct format_instance *fid;
|
||||
const struct format_type *fmt;
|
||||
@@ -638,6 +861,11 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
|
||||
int inconsistent = 0;
|
||||
|
||||
if (!*vgname) {
|
||||
if (precommitted) {
|
||||
log_error("Internal error: vg_read requires vgname "
|
||||
"with pre-commit.");
|
||||
return NULL;
|
||||
}
|
||||
*consistent = 1;
|
||||
return _vg_read_orphans(cmd);
|
||||
}
|
||||
@@ -651,7 +879,7 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
lvmcache_label_scan(cmd, 1);
|
||||
lvmcache_label_scan(cmd, 2);
|
||||
if (!(fmt = fmt_from_vgname(vgname))) {
|
||||
stack;
|
||||
return NULL;
|
||||
@@ -659,6 +887,12 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
|
||||
}
|
||||
}
|
||||
|
||||
if (precommitted && !(fmt->features & FMT_PRECOMMIT)) {
|
||||
log_error("Internal error: %s doesn't support "
|
||||
"pre-commit", fmt->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* create format instance with appropriate metadata area */
|
||||
if (!(fid = fmt->ops->create_instance(fmt, vgname, NULL))) {
|
||||
log_error("Failed to create format instance");
|
||||
@@ -668,7 +902,10 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
|
||||
/* Ensure contents of all metadata areas match - else do recovery */
|
||||
list_iterate(mdah, &fid->metadata_areas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
if (!(vg = mda->ops->vg_read(fid, vgname, mda))) {
|
||||
if ((precommitted &&
|
||||
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda))) ||
|
||||
(!precommitted &&
|
||||
!(vg = mda->ops->vg_read(fid, vgname, mda)))) {
|
||||
inconsistent = 1;
|
||||
continue;
|
||||
}
|
||||
@@ -684,15 +921,67 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
|
||||
}
|
||||
}
|
||||
|
||||
/* Failed to find VG */
|
||||
/* Failed to find VG where we expected it - full scan and retry */
|
||||
if (!correct_vg) {
|
||||
stack;
|
||||
return NULL;
|
||||
inconsistent = 0;
|
||||
|
||||
lvmcache_label_scan(cmd, 2);
|
||||
if (!(fmt = fmt_from_vgname(vgname))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (precommitted && !(fmt->features & FMT_PRECOMMIT)) {
|
||||
log_error("Internal error: %s doesn't support "
|
||||
"pre-commit", fmt->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* create format instance with appropriate metadata area */
|
||||
if (!(fid = fmt->ops->create_instance(fmt, vgname, NULL))) {
|
||||
log_error("Failed to create format instance");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Ensure contents of all metadata areas match - else recover */
|
||||
list_iterate(mdah, &fid->metadata_areas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
if ((precommitted &&
|
||||
!(vg = mda->ops->vg_read_precommit(fid, vgname,
|
||||
mda))) ||
|
||||
(!precommitted &&
|
||||
!(vg = mda->ops->vg_read(fid, vgname, mda)))) {
|
||||
inconsistent = 1;
|
||||
continue;
|
||||
}
|
||||
if (!correct_vg) {
|
||||
correct_vg = vg;
|
||||
continue;
|
||||
}
|
||||
/* FIXME Also ensure contents same - checksums same? */
|
||||
if (correct_vg->seqno != vg->seqno) {
|
||||
inconsistent = 1;
|
||||
if (vg->seqno > correct_vg->seqno)
|
||||
correct_vg = vg;
|
||||
}
|
||||
}
|
||||
|
||||
/* Give up looking */
|
||||
if (!correct_vg) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
lvmcache_update_vg(correct_vg);
|
||||
|
||||
if (inconsistent) {
|
||||
if (precommitted) {
|
||||
log_error("Inconsistent pre-commit metadata copies "
|
||||
"for volume group %s", vgname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!*consistent)
|
||||
return correct_vg;
|
||||
|
||||
@@ -711,6 +1000,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()) {
|
||||
@@ -725,6 +1019,19 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
|
||||
return correct_vg;
|
||||
}
|
||||
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
|
||||
int *consistent)
|
||||
{
|
||||
return _vg_read(cmd, vgname, consistent, 0);
|
||||
}
|
||||
|
||||
struct volume_group *vg_read_precommitted(struct cmd_context *cmd,
|
||||
const char *vgname,
|
||||
int *consistent)
|
||||
{
|
||||
return _vg_read(cmd, vgname, consistent, 1);
|
||||
}
|
||||
|
||||
/* This is only called by lv_from_lvid, which is only called from
|
||||
* activate.c so we know the appropriate VG lock is already held and
|
||||
* the vg_read is therefore safe.
|
||||
@@ -760,7 +1067,7 @@ struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid)
|
||||
* allowed to do a full scan here any more. */
|
||||
|
||||
// The slow way - full scan required to cope with vgrename
|
||||
if (!(vgnames = get_vgs(cmd, 1))) {
|
||||
if (!(vgnames = get_vgs(cmd, 2))) {
|
||||
log_error("vg_read_by_vgid: get_vgs failed");
|
||||
return NULL;
|
||||
}
|
||||
@@ -824,14 +1131,14 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
||||
|
||||
if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
|
||||
stack;
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(label_read(dev, &label))) {
|
||||
if (warnings)
|
||||
log_error("No physical volume label read from %s",
|
||||
pv_name);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info = (struct lvmcache_info *) label->info;
|
||||
@@ -840,22 +1147,29 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
||||
|
||||
if (!(pv = pool_zalloc(cmd->mem, sizeof(*pv)))) {
|
||||
log_error("pv allocation for '%s' failed", pv_name);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_init(&pv->tags);
|
||||
list_init(&pv->segments);
|
||||
list_init(&pv->free_segments);
|
||||
|
||||
/* FIXME Move more common code up here */
|
||||
if (!(info->fmt->ops->pv_read(info->fmt, pv_name, pv, mdas))) {
|
||||
log_error("Failed to read existing physical volume '%s'",
|
||||
pv_name);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!pv->size)
|
||||
return NULL;
|
||||
else
|
||||
return pv;
|
||||
|
||||
if (!alloc_pv_segment_whole_pv(cmd->mem, pv)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pv;
|
||||
}
|
||||
|
||||
/* May return empty list */
|
||||
|
@@ -50,7 +50,7 @@
|
||||
#define VISIBLE_LV 0x00000040 /* LV */
|
||||
#define FIXED_MINOR 0x00000080 /* LV */
|
||||
/* FIXME Remove when metadata restructuring is completed */
|
||||
#define SNAPSHOT 0x00001000 /* LV - tmp internal use only */
|
||||
#define SNAPSHOT 0x00001000 /* LV - internal use only */
|
||||
#define PVMOVE 0x00002000 /* VG LV SEG */
|
||||
#define LOCKED 0x00004000 /* LV */
|
||||
#define MIRRORED 0x00008000 /* LV - internal use only */
|
||||
@@ -68,6 +68,7 @@
|
||||
#define FMT_UNLIMITED_VOLS 0x00000008 /* Unlimited PVs/LVs? */
|
||||
#define FMT_RESTRICTED_LVIDS 0x00000010 /* LVID <= 255 */
|
||||
#define FMT_ORPHAN_ALLOCATABLE 0x00000020 /* Orphan PV allocatable? */
|
||||
#define FMT_PRECOMMIT 0x00000040 /* Supports pre-commit? */
|
||||
|
||||
typedef enum {
|
||||
ALLOC_INVALID,
|
||||
@@ -98,6 +99,20 @@ struct format_type {
|
||||
void *private;
|
||||
};
|
||||
|
||||
struct pv_segment {
|
||||
struct list list; /* Member of pv->segments: ordered list
|
||||
* covering entire data area on this PV */
|
||||
|
||||
struct physical_volume *pv;
|
||||
uint32_t pe;
|
||||
uint32_t len;
|
||||
|
||||
struct lv_segment *lvseg; /* NULL if free space */
|
||||
uint32_t lv_area; /* Index to area in LV segment */
|
||||
|
||||
struct list freelist; /* Member of pv->free_segments */
|
||||
};
|
||||
|
||||
struct physical_volume {
|
||||
struct id id;
|
||||
struct device *dev;
|
||||
@@ -113,6 +128,8 @@ struct physical_volume {
|
||||
uint32_t pe_count;
|
||||
uint32_t pe_alloc_count;
|
||||
|
||||
struct list segments; /* Ordered pv_segments covering complete PV */
|
||||
struct list free_segments; /* Free pv_segments for this PV */
|
||||
struct list tags;
|
||||
};
|
||||
|
||||
@@ -124,6 +141,9 @@ struct metadata_area_ops {
|
||||
struct volume_group *(*vg_read) (struct format_instance * fi,
|
||||
const char *vg_name,
|
||||
struct metadata_area * mda);
|
||||
struct volume_group *(*vg_read_precommit) (struct format_instance * fi,
|
||||
const char *vg_name,
|
||||
struct metadata_area * mda);
|
||||
/*
|
||||
* Write out complete VG metadata. You must ensure internal
|
||||
* consistency before calling. eg. PEs can't refer to PVs not
|
||||
@@ -140,6 +160,9 @@ struct metadata_area_ops {
|
||||
*/
|
||||
int (*vg_write) (struct format_instance * fid, struct volume_group * vg,
|
||||
struct metadata_area * mda);
|
||||
int (*vg_precommit) (struct format_instance * fid,
|
||||
struct volume_group * vg,
|
||||
struct metadata_area * mda);
|
||||
int (*vg_commit) (struct format_instance * fid,
|
||||
struct volume_group * vg, struct metadata_area * mda);
|
||||
int (*vg_revert) (struct format_instance * fid,
|
||||
@@ -184,11 +207,8 @@ struct volume_group {
|
||||
|
||||
/* logical volumes */
|
||||
uint32_t lv_count;
|
||||
struct list lvs;
|
||||
|
||||
/* snapshots */
|
||||
uint32_t snapshot_count;
|
||||
struct list snapshots;
|
||||
struct list lvs;
|
||||
|
||||
struct list tags;
|
||||
};
|
||||
@@ -210,7 +230,8 @@ struct lv_segment {
|
||||
uint32_t area_len;
|
||||
struct logical_volume *origin;
|
||||
struct logical_volume *cow;
|
||||
uint32_t chunk_size;
|
||||
struct list origin_list;
|
||||
uint32_t chunk_size; /* In sectors */
|
||||
uint32_t extents_copied;
|
||||
|
||||
struct list tags;
|
||||
@@ -222,6 +243,7 @@ struct lv_segment {
|
||||
struct {
|
||||
struct physical_volume *pv;
|
||||
uint32_t pe;
|
||||
struct pv_segment *pvseg;
|
||||
} pv;
|
||||
struct {
|
||||
struct logical_volume *lv;
|
||||
@@ -246,20 +268,14 @@ struct logical_volume {
|
||||
uint64_t size;
|
||||
uint32_t le_count;
|
||||
|
||||
uint32_t origin_count;
|
||||
struct list snapshot_segs;
|
||||
struct lv_segment *snapshot;
|
||||
|
||||
struct list segments;
|
||||
struct list tags;
|
||||
};
|
||||
|
||||
struct snapshot {
|
||||
struct id id;
|
||||
|
||||
int persistent; /* boolean */
|
||||
uint32_t chunk_size; /* in 512 byte sectors */
|
||||
|
||||
struct logical_volume *origin;
|
||||
struct logical_volume *cow;
|
||||
};
|
||||
|
||||
struct name_list {
|
||||
struct list list;
|
||||
char *name;
|
||||
@@ -283,17 +299,16 @@ struct lv_list {
|
||||
struct logical_volume *lv;
|
||||
};
|
||||
|
||||
struct snapshot_list {
|
||||
struct list list;
|
||||
|
||||
struct snapshot *snapshot;
|
||||
};
|
||||
|
||||
struct mda_list {
|
||||
struct list list;
|
||||
struct device_area mda;
|
||||
};
|
||||
|
||||
struct peg_list {
|
||||
struct list list;
|
||||
struct pv_segment *peg;
|
||||
};
|
||||
|
||||
/*
|
||||
* Ownership of objects passes to caller.
|
||||
*/
|
||||
@@ -341,6 +356,12 @@ struct format_handler {
|
||||
*/
|
||||
int (*vg_setup) (struct format_instance * fi, struct volume_group * vg);
|
||||
|
||||
/*
|
||||
* Check whether particular segment type is supported.
|
||||
*/
|
||||
int (*segtype_supported) (struct format_instance *fid,
|
||||
struct segment_type *segtype);
|
||||
|
||||
/*
|
||||
* Create format instance with a particular metadata area
|
||||
*/
|
||||
@@ -367,6 +388,9 @@ int vg_commit(struct volume_group *vg);
|
||||
int vg_revert(struct volume_group *vg);
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
|
||||
int *consistent);
|
||||
struct volume_group *vg_read_precommitted(struct cmd_context *cmd,
|
||||
const char *vg_name,
|
||||
int *consistent);
|
||||
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid);
|
||||
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
||||
struct list *mdas, uint64_t *label_sector,
|
||||
@@ -400,13 +424,17 @@ int vg_rename(struct cmd_context *cmd, struct volume_group *vg,
|
||||
const char *new_name);
|
||||
int vg_extend(struct format_instance *fi, struct volume_group *vg,
|
||||
int pv_count, char **pv_names);
|
||||
int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
|
||||
uint32_t new_extent_size);
|
||||
|
||||
/* Manipulate LVs */
|
||||
struct logical_volume *lv_create_empty(struct format_instance *fi,
|
||||
const char *name,
|
||||
const char *name_format,
|
||||
union lvid *lvid,
|
||||
uint32_t status,
|
||||
alloc_policy_t alloc,
|
||||
int import,
|
||||
struct volume_group *vg);
|
||||
|
||||
int lv_reduce(struct format_instance *fi,
|
||||
@@ -433,6 +461,8 @@ struct physical_volume *pv_find(struct volume_group *vg, const char *pv_name);
|
||||
struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name);
|
||||
struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg,
|
||||
struct id *id);
|
||||
int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
|
||||
const char *id, struct physical_volume *pv);
|
||||
|
||||
/* Find an LV within a given VG */
|
||||
struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name);
|
||||
@@ -486,13 +516,12 @@ int lv_is_cow(const struct logical_volume *lv);
|
||||
|
||||
int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv);
|
||||
|
||||
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);
|
||||
struct lv_segment *find_cow(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 format_instance *fid, const char *name,
|
||||
struct logical_volume *origin, struct logical_volume *cow,
|
||||
union lvid *lvid, uint32_t extent_count,
|
||||
uint32_t chunk_size);
|
||||
|
||||
int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow);
|
||||
|
||||
|
@@ -16,9 +16,10 @@
|
||||
#include "lib.h"
|
||||
#include "metadata.h"
|
||||
#include "toolcontext.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
#include "display.h"
|
||||
#include "activate.h"
|
||||
#include "lv_alloc.h"
|
||||
|
||||
/*
|
||||
* Replace any LV segments on given PV with temporary mirror.
|
||||
@@ -149,13 +150,11 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
seg->area[s].u.pv.pe,
|
||||
PVMOVE, allocatable_pvs,
|
||||
lv->alloc)) {
|
||||
log_error("Allocation for temporary "
|
||||
"pvmove LV failed");
|
||||
log_error("Unable to allocate "
|
||||
"temporary LV for pvmove.");
|
||||
return 0;
|
||||
}
|
||||
seg->area[s].type = AREA_LV;
|
||||
seg->area[s].u.lv.lv = lv_mirr;
|
||||
seg->area[s].u.lv.le = start_le;
|
||||
set_lv_segment_area_lv(seg, s, lv_mirr, start_le);
|
||||
|
||||
extent_count += seg->area_len;
|
||||
|
||||
@@ -225,9 +224,9 @@ int remove_pvmove_mirrors(struct volume_group *vg,
|
||||
else
|
||||
c = 0;
|
||||
|
||||
seg->area[s].type = AREA_PV;
|
||||
seg->area[s].u.pv.pv = mir_seg->area[c].u.pv.pv;
|
||||
seg->area[s].u.pv.pe = mir_seg->area[c].u.pv.pe;
|
||||
set_lv_segment_area_pv(seg, s,
|
||||
mir_seg->area[c].u.pv.pv,
|
||||
mir_seg->area[c].u.pv.pe);
|
||||
|
||||
/* Replace mirror with old area */
|
||||
if (!
|
||||
|
22
lib/metadata/pv_alloc.h
Normal file
22
lib/metadata/pv_alloc.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU 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 _LVM_PV_ALLOC_H
|
||||
#include "pool.h"
|
||||
|
||||
int alloc_pv_segment_whole_pv(struct pool *mem, struct physical_volume *pv);
|
||||
int peg_dup(struct pool *mem, struct list *peg_new, struct list *peg_free_new,
|
||||
struct list *peg_old);
|
||||
|
||||
#endif
|
83
lib/metadata/pv_manip.c
Normal file
83
lib/metadata/pv_manip.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2003 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 - 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU 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 "pool.h"
|
||||
#include "metadata.h"
|
||||
#include "pv_alloc.h"
|
||||
|
||||
static struct pv_segment *_alloc_pv_segment(struct pool *mem,
|
||||
struct physical_volume *pv,
|
||||
uint32_t pe, uint32_t len)
|
||||
{
|
||||
struct pv_segment *peg;
|
||||
|
||||
if (!(peg = pool_zalloc(mem, sizeof(*peg)))) {
|
||||
log_error("pv_segment allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
peg->pv = pv;
|
||||
peg->pe = pe;
|
||||
peg->len = len;
|
||||
peg->lvseg = NULL;
|
||||
peg->lv_area = 0;
|
||||
|
||||
list_init(&peg->list);
|
||||
list_init(&peg->freelist);
|
||||
|
||||
return peg;
|
||||
}
|
||||
|
||||
int alloc_pv_segment_whole_pv(struct pool *mem, struct physical_volume *pv)
|
||||
{
|
||||
struct pv_segment *peg;
|
||||
|
||||
/* FIXME Cope with holes in PVs */
|
||||
if (!(peg = _alloc_pv_segment(mem, pv, 0, pv->pe_count))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_add(&pv->segments, &peg->list);
|
||||
list_add(&pv->free_segments, &peg->freelist);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int peg_dup(struct pool *mem, struct list *peg_new, struct list *peg_free_new,
|
||||
struct list *peg_old)
|
||||
{
|
||||
struct pv_segment *peg, *pego;
|
||||
|
||||
list_init(peg_new);
|
||||
list_init(peg_free_new);
|
||||
|
||||
list_iterate_items(pego, peg_old) {
|
||||
if (!(peg = _alloc_pv_segment(mem, pego->pv, pego->pe,
|
||||
pego->len))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
peg->lvseg = pego->lvseg;
|
||||
peg->lv_area = pego->lv_area;
|
||||
list_add(peg_new, &peg->list);
|
||||
if (!peg->lvseg)
|
||||
list_add(peg_free_new, &peg->freelist);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@
|
||||
|
||||
#include "lib.h"
|
||||
#include "toolcontext.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
|
||||
struct segment_type *get_segtype_from_string(struct cmd_context *cmd,
|
||||
const char *str)
|
@@ -85,4 +85,8 @@ struct segment_type *init_snapshot_segtype(struct cmd_context *cmd);
|
||||
struct segment_type *init_mirrored_segtype(struct cmd_context *cmd);
|
||||
#endif
|
||||
|
||||
#ifdef CRYPT_INTERNAL
|
||||
struct segment_type *init_crypt_segtype(struct cmd_context *cmd);
|
||||
#endif
|
||||
|
||||
#endif
|
@@ -16,101 +16,31 @@
|
||||
#include "lib.h"
|
||||
#include "metadata.h"
|
||||
#include "toolcontext.h"
|
||||
#include "lv_alloc.h"
|
||||
|
||||
int lv_is_origin(const struct logical_volume *lv)
|
||||
{
|
||||
struct list *slh;
|
||||
struct snapshot *s;
|
||||
|
||||
list_iterate(slh, &lv->vg->snapshots) {
|
||||
s = list_item(slh, struct snapshot_list)->snapshot;
|
||||
if (s->origin == lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return lv->origin_count ? 1 : 0;
|
||||
}
|
||||
|
||||
int lv_is_cow(const struct logical_volume *lv)
|
||||
{
|
||||
struct list *slh;
|
||||
struct snapshot *s;
|
||||
|
||||
list_iterate(slh, &lv->vg->snapshots) {
|
||||
s = list_item(slh, struct snapshot_list)->snapshot;
|
||||
if (s->cow == lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return lv->snapshot ? 1 : 0;
|
||||
}
|
||||
|
||||
struct snapshot *find_origin(const struct logical_volume *lv)
|
||||
/* Given a cow LV, return the snapshot lv_segment that uses it */
|
||||
struct lv_segment *find_cow(const struct logical_volume *lv)
|
||||
{
|
||||
struct list *slh;
|
||||
struct snapshot *s;
|
||||
|
||||
list_iterate(slh, &lv->vg->snapshots) {
|
||||
s = list_item(slh, struct snapshot_list)->snapshot;
|
||||
if (s->origin == lv)
|
||||
return s;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return lv->snapshot;
|
||||
}
|
||||
|
||||
struct snapshot *find_cow(const struct logical_volume *lv)
|
||||
int vg_add_snapshot(struct format_instance *fid, const char *name,
|
||||
struct logical_volume *origin,
|
||||
struct logical_volume *cow, union lvid *lvid,
|
||||
uint32_t extent_count, uint32_t chunk_size)
|
||||
{
|
||||
struct list *slh;
|
||||
struct snapshot *s;
|
||||
|
||||
list_iterate(slh, &lv->vg->snapshots) {
|
||||
s = list_item(slh, struct snapshot_list)->snapshot;
|
||||
if (s->cow == lv)
|
||||
return s;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct list *find_snapshots(const struct logical_volume *lv)
|
||||
{
|
||||
struct list *slh;
|
||||
struct list *snaplist;
|
||||
struct snapshot *s;
|
||||
struct snapshot_list *newsl;
|
||||
struct pool *mem = lv->vg->cmd->mem;
|
||||
|
||||
if (!(snaplist = pool_alloc(mem, sizeof(*snaplist)))) {
|
||||
log_error("snapshot name list allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_init(snaplist);
|
||||
|
||||
list_iterate(slh, &lv->vg->snapshots) {
|
||||
s = list_item(slh, struct snapshot_list)->snapshot;
|
||||
if (!(s->origin == lv))
|
||||
continue;
|
||||
if (!(newsl = pool_alloc(mem, sizeof(*newsl)))) {
|
||||
log_error("snapshot_list structure allocation failed");
|
||||
pool_free(mem, snaplist);
|
||||
return NULL;
|
||||
}
|
||||
newsl->snapshot = s;
|
||||
list_add(snaplist, &newsl->list);
|
||||
}
|
||||
|
||||
return snaplist;
|
||||
}
|
||||
|
||||
int vg_add_snapshot(struct logical_volume *origin,
|
||||
struct logical_volume *cow,
|
||||
int persistent, struct id *id, uint32_t chunk_size)
|
||||
{
|
||||
struct snapshot *s;
|
||||
struct snapshot_list *sl;
|
||||
struct pool *mem = origin->vg->cmd->mem;
|
||||
struct logical_volume *snap;
|
||||
struct lv_segment *seg;
|
||||
|
||||
/*
|
||||
* Is the cow device already being used ?
|
||||
@@ -120,53 +50,53 @@ int vg_add_snapshot(struct logical_volume *origin,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(s = pool_alloc(mem, sizeof(*s)))) {
|
||||
if (!(snap = lv_create_empty(fid, name, name ? NULL : "snapshot%d",
|
||||
lvid, LVM_READ | LVM_WRITE | VISIBLE_LV,
|
||||
ALLOC_INHERIT, 1, origin->vg))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s->persistent = persistent;
|
||||
s->chunk_size = chunk_size;
|
||||
s->origin = origin;
|
||||
s->cow = cow;
|
||||
snap->le_count = extent_count;
|
||||
|
||||
if (id)
|
||||
s->id = *id;
|
||||
else if (!id_create(&s->id)) {
|
||||
log_error("Snapshot UUID creation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(sl = pool_alloc(mem, sizeof(*sl)))) {
|
||||
if (!(seg = alloc_snapshot_seg(snap, 0))) {
|
||||
stack;
|
||||
pool_free(mem, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->chunk_size = chunk_size;
|
||||
seg->origin = origin;
|
||||
seg->cow = cow;
|
||||
seg->lv->status |= SNAPSHOT;
|
||||
|
||||
origin->origin_count++;
|
||||
origin->vg->snapshot_count++;
|
||||
origin->vg->lv_count--;
|
||||
cow->snapshot = seg;
|
||||
|
||||
cow->status &= ~VISIBLE_LV;
|
||||
sl->snapshot = s;
|
||||
list_add(&origin->vg->snapshots, &sl->list);
|
||||
origin->vg->snapshot_count++;
|
||||
|
||||
list_add(&origin->snapshot_segs, &seg->origin_list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow)
|
||||
{
|
||||
struct list *slh;
|
||||
struct snapshot_list *sl;
|
||||
list_del(&cow->snapshot->origin_list);
|
||||
cow->snapshot->origin->origin_count--;
|
||||
|
||||
list_iterate(slh, &vg->snapshots) {
|
||||
sl = list_item(slh, struct snapshot_list);
|
||||
|
||||
if (sl->snapshot->cow == cow) {
|
||||
list_del(slh);
|
||||
vg->snapshot_count--;
|
||||
return 1;
|
||||
}
|
||||
if (!lv_remove(vg, cow->snapshot->lv)) {
|
||||
log_error("Failed to remove internal snapshot LV %s",
|
||||
cow->snapshot->lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fail */
|
||||
log_err("Asked to remove an unknown snapshot.");
|
||||
return 0;
|
||||
cow->snapshot = NULL;
|
||||
|
||||
vg->snapshot_count--;
|
||||
vg->lv_count++;
|
||||
cow->status |= VISIBLE_LV;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@
|
||||
#include "list.h"
|
||||
#include "toolcontext.h"
|
||||
#include "metadata.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
#include "display.h"
|
||||
#include "text_export.h"
|
||||
#include "text_import.h"
|
||||
@@ -131,6 +131,7 @@ static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
|
||||
int areas = seg->area_count;
|
||||
int start_area = 0u;
|
||||
uint32_t region_size, region_max;
|
||||
int ret;
|
||||
|
||||
if (!*target_state)
|
||||
*target_state = _init_target(mem, cft);
|
||||
@@ -166,10 +167,10 @@ static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
|
||||
region_size);
|
||||
}
|
||||
|
||||
if ((*pos = lvm_snprintf(params, paramsize, "core 1 %u %u ",
|
||||
region_size, areas)) < 0) {
|
||||
if ((ret = compose_log_line(dm, seg, params, paramsize, pos,
|
||||
areas, region_size)) <= 0) {
|
||||
stack;
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,5 +259,7 @@ struct segment_type *init_segtype(struct cmd_context *cmd)
|
||||
segtype->private = NULL;
|
||||
segtype->flags = SEG_AREAS_MIRRORED;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
return segtype;
|
||||
}
|
||||
|
@@ -86,7 +86,11 @@ int lvm_rename(const char *old, const char *new)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
link(old, new);
|
||||
if (link(old, new)) {
|
||||
log_error("%s: rename to %s failed: %s", old, new,
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stat(old, &buf)) {
|
||||
log_sys_error("stat", old);
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include "lib.h"
|
||||
#include "lvm-types.h"
|
||||
#include "lvm-string.h"
|
||||
#include "pool.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
@@ -98,3 +99,109 @@ int split_words(char *buffer, unsigned max, char **argv)
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Device layer names are all of the form <vg>-<lv>-<layer>, any
|
||||
* other hyphens that appear in these names are quoted with yet
|
||||
* another hyphen. The top layer of any device has no layer
|
||||
* name. eg, vg0-lvol0.
|
||||
*/
|
||||
static void _count_hyphens(const char *str, size_t *len, int *hyphens)
|
||||
{
|
||||
const char *ptr;
|
||||
|
||||
for (ptr = str; *ptr; ptr++, (*len)++)
|
||||
if (*ptr == '-')
|
||||
(*hyphens)++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copies a string, quoting hyphens with hyphens.
|
||||
*/
|
||||
static void _quote_hyphens(char **out, const char *src)
|
||||
{
|
||||
while (*src) {
|
||||
if (*src == '-')
|
||||
*(*out)++ = '-';
|
||||
|
||||
*(*out)++ = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* <vg>-<lv>-<layer> or if !layer just <vg>-<lv>.
|
||||
*/
|
||||
char *build_dm_name(struct pool *mem, const char *vg,
|
||||
const char *lv, const char *layer)
|
||||
{
|
||||
size_t len = 1;
|
||||
int hyphens = 1;
|
||||
char *r, *out;
|
||||
|
||||
_count_hyphens(vg, &len, &hyphens);
|
||||
_count_hyphens(lv, &len, &hyphens);
|
||||
|
||||
if (layer && *layer) {
|
||||
_count_hyphens(layer, &len, &hyphens);
|
||||
hyphens++;
|
||||
}
|
||||
|
||||
len += hyphens;
|
||||
|
||||
if (!(r = pool_alloc(mem, len))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out = r;
|
||||
_quote_hyphens(&out, vg);
|
||||
*out++ = '-';
|
||||
_quote_hyphens(&out, lv);
|
||||
|
||||
if (layer && *layer) {
|
||||
*out++ = '-';
|
||||
_quote_hyphens(&out, layer);
|
||||
}
|
||||
*out = '\0';
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove hyphen quoting from a component of a name.
|
||||
* NULL-terminates the component and returns start of next component.
|
||||
*/
|
||||
static char *_unquote(char *component)
|
||||
{
|
||||
char *c = component;
|
||||
char *o = c;
|
||||
|
||||
while (*c) {
|
||||
if (*(c + 1)) {
|
||||
if (*c == '-') {
|
||||
if (*(c + 1) == '-')
|
||||
c++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
*o = *c;
|
||||
o++;
|
||||
c++;
|
||||
}
|
||||
|
||||
*o = '\0';
|
||||
return (c + 1);
|
||||
}
|
||||
|
||||
int split_dm_name(struct pool *mem, const char *dmname,
|
||||
char **vgname, char **lvname, char **layer)
|
||||
{
|
||||
if (!(*vgname = pool_strdup(mem, dmname)))
|
||||
return 0;
|
||||
|
||||
_unquote(*layer = _unquote(*lvname = _unquote(*vgname)));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@@ -19,6 +19,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
struct pool;
|
||||
|
||||
/*
|
||||
* On error, up to glibc 2.0.6, snprintf returned -1 if buffer was too small;
|
||||
* From glibc 2.1 it returns number of chars (excl. trailing null) that would
|
||||
@@ -32,4 +34,10 @@ int emit_to_buffer(char **buffer, size_t *size, const char *fmt, ...);
|
||||
|
||||
int split_words(char *buffer, unsigned max, char **argv);
|
||||
|
||||
char *build_dm_name(struct pool *mem, const char *vg,
|
||||
const char *lv, const char *layer);
|
||||
|
||||
int split_dm_name(struct pool *mem, const char *dmname,
|
||||
char **vgname, char **lvname, char **layer);
|
||||
|
||||
#endif
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user