1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-09-29 13:44:18 +03:00

Compare commits

...

65 Commits

Author SHA1 Message Date
Alasdair Kergon
38a90e7669 New column-based reporting tools: lvs, pvs & vgs. 2002-12-12 20:55:49 +00:00
Andres Salomon
6bfc526dcd close another bug 2002-12-09 08:59:34 +00:00
Andres Salomon
aadb8a7405 it's about that time again 2002-12-09 08:37:58 +00:00
Alasdair Kergon
27082bf77e Use sync_dir(). 2002-12-05 22:56:22 +00:00
Alasdair Kergon
a2903c80cd Add sync_dir() 2002-12-05 22:51:15 +00:00
Alasdair Kergon
9a77c5369c Fix display alignment of zero. 2002-12-05 22:42:31 +00:00
Alasdair Kergon
3c30741a19 Remove an unused .h file. 2002-12-05 22:37:36 +00:00
Alasdair Kergon
7028ad4ec0 Fix long arg processing. 2002-12-05 22:35:15 +00:00
Alasdair Kergon
8de750c6aa Maintain snapshot_count correctly. 2002-12-05 22:30:39 +00:00
Alasdair Kergon
04f98de9ee Keep certain versions of ld happy. 2002-12-05 22:28:18 +00:00
Alasdair Kergon
a1a019784b Keep some ld versions happy. 2002-12-05 22:27:43 +00:00
Alasdair Kergon
4aeeae77bd New devices/types config file entry to add new types of block devices. 2002-12-03 16:20:38 +00:00
Alasdair Kergon
651cfc2b78 tidy 2002-12-03 13:27:23 +00:00
Alasdair Kergon
2ef8af25e2 Show PV uuid; single stripe is 'linear'; suppress snapshot fields for origin. 2002-12-03 13:26:17 +00:00
Alasdair Kergon
0b13852a5b More restore hints. 2002-12-03 13:25:09 +00:00
Alasdair Kergon
13427578c9 Default size unit normally MB not KB. 2002-12-03 13:24:38 +00:00
Alasdair Kergon
d89ca2087e Suppress a (normally) unnecessary warning. 2002-12-03 13:23:50 +00:00
Alasdair Kergon
8b0ea9fba6 Further help text tidying & support for -?. 2002-11-29 15:02:57 +00:00
Heinz Mauelshagen
9f0b653d5a tiny tidying 2002-11-28 15:27:59 +00:00
Heinz Mauelshagen
659a339233 Corrected lvcreate synopsis.
Added --ignorelockingflag to synopsis where missing.
2002-11-28 15:27:29 +00:00
Alasdair Kergon
4c29f177a0 Show stripesize in KB. 2002-11-26 21:56:57 +00:00
Alasdair Kergon
d664e63d55 Skip config file reload attempt if no config file location. 2002-11-26 12:14:37 +00:00
Alasdair Kergon
2493509dbe Fix snapshot lvcreate activation check. 2002-11-22 14:19:56 +00:00
Alasdair Kergon
1c8b27f554 Remove 2 TB LV size restriction message. 2002-11-18 16:21:00 +00:00
Alasdair Kergon
68297b7186 Missing sector->k conversion in "logical volumes cannot be larger than" mesg. 2002-11-18 16:08:45 +00:00
Alasdair Kergon
34dd8d0a91 Some new features. 2002-11-18 14:04:08 +00:00
Alasdair Kergon
81c44790d5 Refactoring. 2002-11-18 14:01:16 +00:00
Alasdair Kergon
d557b335cf A new cache. 2002-11-18 13:53:58 +00:00
Alasdair Kergon
e2adc28cff Only functions listed in libdevmapper.h should get exported. 2002-11-14 19:26:28 +00:00
Alasdair Kergon
0fef6a6ecc Fix includes after DM_DIR definition move. 2002-11-14 14:44:42 +00:00
Alasdair Kergon
f2fd4b8a1f Don't let LVM2 access a VG if the original LVM driver appears to be using it. 2002-11-01 19:57:25 +00:00
Alasdair Kergon
95bd5605a8 Improve missing-kernel-driver error message. 2002-11-01 16:16:42 +00:00
Andres Salomon
497cca7eca agk, I recall you saying you had a massive commit pending; if you need me
to back this out so you can do that commit, let me know.  Also, if there's
an issue with the error message that's displayed, just change it in tools.h.

This causes a "device-mapper driver/module not loaded?" error message to
be displayed for the commands that require dm-mod, if the tools can't get
the driver version.  It's not done for commands that don't require dm-mod.
This should clear up some problems people have had attempting to use lvm2
without rtfm'ing.
2002-10-27 21:04:03 +00:00
Andres Salomon
54f78feedd synch w/ debian 2002-10-27 18:40:35 +00:00
Andres Salomon
76408e53ae Wow, learn something new every day. Apparently, the signed-ness of char is
implementation-dependent; some archs (s390, arm, and ppc) default to
an unsigned char.
2002-10-08 20:16:44 +00:00
Alasdair Kergon
be19e74d30 Support alternative lvrename syntax. 2002-09-05 12:49:23 +00:00
Andres Salomon
dac578a775 update, synch w/ debian 2002-09-01 23:08:17 +00:00
Joe Thornber
04732ce74b o inline _step_matcher 2002-08-29 15:05:16 +00:00
Joe Thornber
a6c95a2374 o Give an example filter that uses anchors. 2002-08-29 14:47:06 +00:00
Joe Thornber
f68622abe9 o Anchor support for the regex engine. 2002-08-29 14:46:30 +00:00
AJ Lewis
83a9a7bdb2 o This resolves bug #79
o added -D_REENTRANT to the CFLAGS so clvmd works properly with liblvm
   (I saw this problem with Redhat 7.3)
2002-08-15 15:31:33 +00:00
Patrick Caulfield
6500afc0ca Remove O_DIRECT as it causes problems with some systems.
Harumph.
2002-08-14 14:58:00 +00:00
Joe Thornber
c69b7ecc96 o Remove e2fsadm to stop people waiting expectantly for something that isn't going
to arrive.
2002-08-08 07:54:57 +00:00
Joe Thornber
615ef1e2d2 o Make sure the status parsing code can deal with an empty array. 2002-08-01 12:51:48 +00:00
Joe Thornber
cf69a0cd7f o Added new value type CFG_EMPTY_ARRAY, to indicate '[]', useful since we use
the arrays to hold a symbolic set of flags.
2002-08-01 12:46:52 +00:00
Joe Thornber
06e892fb33 o 0 was used rather than NULL in a couple of places.
o  Indent output with tabs rather than single spaces.
2002-08-01 08:22:09 +00:00
Joe Thornber
e6c5dd6865 o Test program for the config unit. Just reads a config and then writes it
out again.
2002-08-01 08:18:54 +00:00
Patrick Caulfield
247efdebdb Rename lock_resource to file_lock_resource to avoid name clashes 2002-07-25 09:04:30 +00:00
Patrick Caulfield
76f3792287 Use O_DIRECT for writing to devices.
Doesn't work on HPPA due to a kernel bug but other archs shuld be OK.
2002-07-22 08:10:54 +00:00
Alasdair Kergon
64d8e2c727 Remove hard-coded extent_size from snapshot target (field no longer used). 2002-07-17 17:00:54 +00:00
Alasdair Kergon
ead0bd9cb0 Improved snapshot-related arg validation 2002-07-17 16:04:05 +00:00
Joe Thornber
66fc13b2ec i) Add the VISIBLE flag to the text format. (Other changes are pending
for lib/activate.)
2002-07-11 15:28:49 +00:00
Joe Thornber
f3af4128b0 i) Added a little macro to aid defining the status flags. 2002-07-11 14:36:45 +00:00
Joe Thornber
0e43107c87 i) There's now a seperate field in struct logical_volume that stores the
allocation policy.  This can currently take one of three values:

   typedef enum {
        ALLOC_NEXT_FREE,
        ALLOC_STRICT,
        ALLOC_CONTIGUOUS
   } alloc_policy_t;

    Notice that 'SIMPLE' has turned into the slightly more meaningful NEXT_FREE.

ii) Put code into display.[hc] for converting one of these enums to a
    text representation and back again.

ii) Updated the text format so this also has the alloc_policy field.
2002-07-11 14:21:49 +00:00
Alasdair Kergon
1ee3e7997e tidy 2002-07-11 14:09:26 +00:00
Alasdair Kergon
50fd61d91f Add get_config_str 2002-07-11 14:07:43 +00:00
Patrick Caulfield
e4cdc051a9 Don't log an error if we can't write the cache file because the FS is read-only.
Gets rid of that annoying error at shutdown.
2002-07-11 09:23:29 +00:00
Alasdair Kergon
778e846e96 Add --ignorelockingfailure 2002-07-10 20:43:32 +00:00
Alasdair Kergon
a27759b647 Merge adjacent "Missing" segments. 2002-07-10 13:54:17 +00:00
Joe Thornber
b75eceab41 o Add version number to text format. 2002-07-02 18:47:43 +00:00
Alasdair Kergon
e748a5d5f4 Tidy up for another release: updated documentation; removed old files;
module build fix.
2002-06-26 21:50:53 +00:00
Patrick Caulfield
99c5a3ae46 Flush on open as well as close. 2002-06-25 14:02:28 +00:00
Alasdair Kergon
51da710f5a o Long-awaited ioctl interface clean-up. *** Not backwardly compatible ***
o Various other kernel side tidy-ups.
o Version number changes so we have the option of adding new ioctl commands
  in future without affecting the use of existing ones should you later
  revert to an older kernel but not revert the userspace library/tools.
o Better separation of kernel/userspace elements in the build process to
  prepare for independent distribution of the kernel driver.
2002-06-19 13:07:05 +00:00
Joe Thornber
569d69b3d2 o Knock the version check out of the makefile, Alasdair will no doubt put it back :)
o  Change to new ioctl names.
2002-06-17 15:50:17 +00:00
Patrick Caulfield
059a6b1d90 Get rid of compile warnings on 64bit platforms. 2002-06-07 08:37:07 +00:00
203 changed files with 11815 additions and 6289 deletions

21
INSTALL
View File

@@ -6,8 +6,8 @@ LVM2 installation
Ensure the device-mapper has been installed on the machine.
The device-mapper should be in the kernel (look for 'device-mapper'
messages in the kernel logs) and /usr/include/libdevmapper.h should
be present.
messages in the kernel logs) and /usr/include/libdevmapper.h
and libdevmapper.so should be present.
The device-mapper is available from:
ftp://ftp.sistina.com/pub/LVM2/device-mapper/
@@ -17,9 +17,15 @@ LVM2 installation
Run the 'configure' script from the top directory.
If you do not have GNU readline (http://www.gnu.org/directory/readline.html)
installed use
./configure --disable-readline
If you wish to use the built-in LVM2 shell and have GNU readline
installed (http://www.gnu.org/directory/readline.html) use:
./configure --enable-readline
If you don't want to include the LVM1 backwards-compatibility code use:
./configure --with-lvm1=none
To separate the LVM1 support into a shared library loaded by lvm.conf use:
./configure --with-lvm1=shared
3) Build and install LVM2.
@@ -31,6 +37,9 @@ LVM2 installation
The tools will work fine without a configuration file being
present, but you ought to review the example file in doc/example.conf.
For example, specifying the devices that LVM2 is to use should
For example, specifying the devices that LVM2 is to use can
make the tools run more efficiently - and avoid scanning /dev/cdrom!
Please also refer to the WHATS_NEW file and the manual pages for the
individual commands.

18
INTRO
View File

@@ -1,18 +0,0 @@
An introduction to LVM2
=======================
Background
Compatibility with LVM1
New features
Missing features
Future enhancements

View File

@@ -23,7 +23,8 @@ VPATH = @srcdir@
SUBDIRS = include man lib tools
ifeq ($(MAKECMDGOALS),distclean)
SUBDIRS += test/mm test/device test/format1 test/regex test/filters
SUBDIRS += lib/format1 \
test/mm test/device test/format1 test/regex test/filters
endif
include make.tmpl

4
README
View File

@@ -1,10 +1,10 @@
This directory contains a beta release of LMV2, the new version of
This directory contains a beta release of LVM2, the new version of
the userland LVM tools designed for the new device-mapper for
the Linux kernel.
The device-mapper needs to be installed before compiling these LVM2 tools.
For more information about LVM2 read the INTRO file.
For more information about LVM2 read the WHATS_NEW file.
Installation instructions are in INSTALL.
This is beta-quality software, released for testing purposes only.

28
TODO
View File

@@ -1,28 +0,0 @@
before 2.0
-----------
vgexport
vgimport
snapshots
pvmove
device-mapper support for 2.5 kernel series
review FIXMEs
extra validation & full consistency checks in format1 with LVM1
partial activation (aka VG quorum)
error message review
locking during metadata changes
format2 with atomic transactions
bidirectional format1/format2 migration tool
persistent minors
statistics target and tool support
review tool exit codes for LVM1 compatibility
before 2.1
----------
e2fsadm
lvmsadc
lvmsar
pvdata
vgsplit
vgmknodes

View File

@@ -1 +1 @@
1.95.10-cvs (2002-05-31)
1.95.12-cvs (2002-12-12)

86
WHATS_NEW Normal file
View File

@@ -0,0 +1,86 @@
Mondy 18th November 2002
========================
The new format of LVM metadata is ready for you to test!
We expect it to be more efficient and more robust than the original format.
It's more compact and supports transactional changes and replication.
Should things go wrong on a system, it's human-readable (and editable).
Please report any problems you find to the mailing list,
linux-lvm@sistina.com. The software has NOT yet been thoroughly
tested and so quite possibly there'll still be some bugs in it.
Be aware of the disclaimer in the COPYING file.
While testing, we recommend turning logging on in the configuration file
to provide us with diagnostic information:
log {
file="/tmp/lvm2.log"
level=6
}
You should schedule regular backups of your configuration file and
metadata backups and archives (normally kept under /etc/lvm).
Please read docs/example.conf and "man lvm.conf" to find out more about
the configuration file.
To convert an existing volume group called vg1 to the new format using
the default settings, use "vgconvert -M2 vg1". See "man vgconvert".
-M (or --metadatatype in its long form) is a new flag to indicate which
format of metadata the command should use for anything it creates.
Currently, the valid types are "lvm1" and "lvm2" and they can be
abbreviated to "1" and "2" respectively. The default value for this
flag can be changed in the global section in the config file.
Backwards-compatible support for the original LVM1 metadata format is
maintained, but it can be moved into a shared library or removed
completely with configure's --with-lvm1 option.
Under LVM2, the basic unit of metadata is the volume group. Different
volume groups can use different formats of metadata - vg1 could use
the original LVM1 format while vg2 used the new format - but you can't
mix formats within a volume group. So to add a PV to an LVM2-format
volume group you must run "pvcreate -M2" on it, followed by "vgextend".
With LVM2-format metadata, lvextend will let you specify striping
parameters. So an LV could consist of two or more "segments" - the
first segment could have 3 stripes while the second segment has just 2.
LVM2 maintains a backup of the current metadata for each volume group
in /etc/lvm/backup, and puts copies of previous versions in
/etc/lvm/archive. "vgcfgbackup" and "vgcfgrestore" can be used to
create and restore from these files. If you fully understand what
you're doing, metadata can be changed by editing a copy of a current
backup file and using vgcfgrestore to reload it.
Please read the pvcreate man page for more information on the new
format for metadata.
All tools that can change things have a --test flag which can be used
to check the effect of a set of cmdline args without really making the
changes.
What's not finished?
====================
The internal cache. If you turn on debugging output you'll see lots of
repeated disk reads, many of which will eventually get optimised out.
--test sometimes causes a command to fail (e.g. vgconvert --test) even
though the real command would work: again, fixing this is waiting for
the work on the cache.
Several of the tools do not yet contain the logic to handle full
recovery: combinations of pvcreate and vgcfgrestore may sometimes be
needed to restore metadata if a tool gets interrupted or crashes or
finds something unexpected. This applies particularly to tools that
work on more than one volume group at once (e.g. vgsplit).
Display output. Some metadata information cannot yet be displayed.
Work has started on new display tools.
Recovery tools to salvage "lost" metadata directly from the disks:
but we hope the new format will mean such tools are hardly ever needed!

196
configure vendored
View File

@@ -16,13 +16,16 @@ ac_help="$ac_help
--with-user=USER Set the owner of installed files "
ac_help="$ac_help
--with-group=GROUP Set the group owner of installed files "
ac_help="$ac_help
--with-lvm1=TYPE LVM1 metadata support: internal/shared/none
[TYPE=internal] "
ac_help="$ac_help
--enable-jobs=NUM Number of jobs to run simultaneously"
ac_help="$ac_help
--enable-static_link Use this to link the tools to the liblvm library
statically. Default is dynamic linking"
ac_help="$ac_help
--disable-readline Disable readline support"
--enable-readline Enable readline support"
# Initialize some variables set by options.
# The variables have the same names as the options, with
@@ -559,7 +562,7 @@ do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:563: checking for $ac_word" >&5
echo "configure:566: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -591,7 +594,7 @@ done
# Extract the first word of "gcc", so it can be a program name with args.
set dummy gcc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:595: checking for $ac_word" >&5
echo "configure:598: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -621,7 +624,7 @@ if test -z "$CC"; then
# Extract the first word of "cc", so it can be a program name with args.
set dummy cc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:625: checking for $ac_word" >&5
echo "configure:628: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -672,7 +675,7 @@ fi
# Extract the first word of "cl", so it can be a program name with args.
set dummy cl; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:676: checking for $ac_word" >&5
echo "configure:679: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -704,7 +707,7 @@ fi
fi
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
echo "configure:708: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
echo "configure:711: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
ac_ext=c
# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
@@ -715,12 +718,12 @@ cross_compiling=$ac_cv_prog_cc_cross
cat > conftest.$ac_ext << EOF
#line 719 "configure"
#line 722 "configure"
#include "confdefs.h"
main(){return(0);}
EOF
if { (eval echo configure:724: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
if { (eval echo configure:727: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
ac_cv_prog_cc_works=yes
# If we can't run a trivial program, we are probably using a cross compiler.
if (./conftest; exit) 2>/dev/null; then
@@ -746,12 +749,12 @@ if test $ac_cv_prog_cc_works = no; then
{ echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
fi
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
echo "configure:750: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
echo "configure:753: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
cross_compiling=$ac_cv_prog_cc_cross
echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
echo "configure:755: checking whether we are using GNU C" >&5
echo "configure:758: checking whether we are using GNU C" >&5
if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -760,7 +763,7 @@ else
yes;
#endif
EOF
if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:764: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:767: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
ac_cv_prog_gcc=yes
else
ac_cv_prog_gcc=no
@@ -779,7 +782,7 @@ ac_test_CFLAGS="${CFLAGS+set}"
ac_save_CFLAGS="$CFLAGS"
CFLAGS=
echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
echo "configure:783: checking whether ${CC-cc} accepts -g" >&5
echo "configure:786: checking whether ${CC-cc} accepts -g" >&5
if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -822,7 +825,7 @@ fi
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
# ./install, which can be erroneously created by make from ./install.sh.
echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
echo "configure:826: checking for a BSD compatible install" >&5
echo "configure:829: checking for a BSD compatible install" >&5
if test -z "$INSTALL"; then
if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -875,7 +878,7 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
echo "configure:879: checking whether ln -s works" >&5
echo "configure:882: checking whether ln -s works" >&5
if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -896,7 +899,7 @@ else
fi
echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
echo "configure:900: checking whether ${MAKE-make} sets \${MAKE}" >&5
echo "configure:903: checking whether ${MAKE-make} sets \${MAKE}" >&5
set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -925,7 +928,7 @@ fi
# Extract the first word of "ranlib", so it can be a program name with args.
set dummy ranlib; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:929: checking for $ac_word" >&5
echo "configure:932: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -958,12 +961,12 @@ for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
echo "configure:962: checking for $ac_hdr that defines DIR" >&5
echo "configure:965: checking for $ac_hdr that defines DIR" >&5
if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 967 "configure"
#line 970 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <$ac_hdr>
@@ -971,7 +974,7 @@ int main() {
DIR *dirp = 0;
; return 0; }
EOF
if { (eval echo configure:975: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
if { (eval echo configure:978: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
eval "ac_cv_header_dirent_$ac_safe=yes"
else
@@ -996,7 +999,7 @@ done
# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
if test $ac_header_dirent = dirent.h; then
echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
echo "configure:1000: checking for opendir in -ldir" >&5
echo "configure:1003: checking for opendir in -ldir" >&5
ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -1004,7 +1007,7 @@ else
ac_save_LIBS="$LIBS"
LIBS="-ldir $LIBS"
cat > conftest.$ac_ext <<EOF
#line 1008 "configure"
#line 1011 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
@@ -1015,7 +1018,7 @@ int main() {
opendir()
; return 0; }
EOF
if { (eval echo configure:1019: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
if { (eval echo configure:1022: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -1037,7 +1040,7 @@ fi
else
echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
echo "configure:1041: checking for opendir in -lx" >&5
echo "configure:1044: checking for opendir in -lx" >&5
ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -1045,7 +1048,7 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lx $LIBS"
cat > conftest.$ac_ext <<EOF
#line 1049 "configure"
#line 1052 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
@@ -1056,7 +1059,7 @@ int main() {
opendir()
; return 0; }
EOF
if { (eval echo configure:1060: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
if { (eval echo configure:1063: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -1079,7 +1082,7 @@ fi
fi
echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
echo "configure:1083: checking how to run the C preprocessor" >&5
echo "configure:1086: checking how to run the C preprocessor" >&5
# On Suns, sometimes $CPP names a directory.
if test -n "$CPP" && test -d "$CPP"; then
CPP=
@@ -1094,13 +1097,13 @@ else
# On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp.
cat > conftest.$ac_ext <<EOF
#line 1098 "configure"
#line 1101 "configure"
#include "confdefs.h"
#include <assert.h>
Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:1104: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:1107: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
:
@@ -1111,13 +1114,13 @@ else
rm -rf conftest*
CPP="${CC-cc} -E -traditional-cpp"
cat > conftest.$ac_ext <<EOF
#line 1115 "configure"
#line 1118 "configure"
#include "confdefs.h"
#include <assert.h>
Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:1121: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:1124: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
:
@@ -1128,13 +1131,13 @@ else
rm -rf conftest*
CPP="${CC-cc} -nologo -E"
cat > conftest.$ac_ext <<EOF
#line 1132 "configure"
#line 1135 "configure"
#include "confdefs.h"
#include <assert.h>
Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:1138: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:1141: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
:
@@ -1159,12 +1162,12 @@ fi
echo "$ac_t""$CPP" 1>&6
echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
echo "configure:1163: checking for ANSI C header files" >&5
echo "configure:1166: checking for ANSI C header files" >&5
if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1168 "configure"
#line 1171 "configure"
#include "confdefs.h"
#include <stdlib.h>
#include <stdarg.h>
@@ -1172,7 +1175,7 @@ else
#include <float.h>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:1176: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:1179: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
@@ -1189,7 +1192,7 @@ rm -f conftest*
if test $ac_cv_header_stdc = yes; then
# SunOS 4.x string.h does not declare mem*, contrary to ANSI.
cat > conftest.$ac_ext <<EOF
#line 1193 "configure"
#line 1196 "configure"
#include "confdefs.h"
#include <string.h>
EOF
@@ -1207,7 +1210,7 @@ fi
if test $ac_cv_header_stdc = yes; then
# ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
cat > conftest.$ac_ext <<EOF
#line 1211 "configure"
#line 1214 "configure"
#include "confdefs.h"
#include <stdlib.h>
EOF
@@ -1228,7 +1231,7 @@ if test "$cross_compiling" = yes; then
:
else
cat > conftest.$ac_ext <<EOF
#line 1232 "configure"
#line 1235 "configure"
#include "confdefs.h"
#include <ctype.h>
#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
@@ -1239,7 +1242,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
exit (0); }
EOF
if { (eval echo configure:1243: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
if { (eval echo configure:1246: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
then
:
else
@@ -1266,17 +1269,17 @@ for ac_hdr in fcntl.h malloc.h sys/ioctl.h unistd.h
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:1270: checking for $ac_hdr" >&5
echo "configure:1273: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1275 "configure"
#line 1278 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:1280: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:1283: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
@@ -1304,12 +1307,12 @@ done
echo $ac_n "checking for working const""... $ac_c" 1>&6
echo "configure:1308: checking for working const" >&5
echo "configure:1311: checking for working const" >&5
if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1313 "configure"
#line 1316 "configure"
#include "confdefs.h"
int main() {
@@ -1358,7 +1361,7 @@ ccp = (char const *const *) p;
; return 0; }
EOF
if { (eval echo configure:1362: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
if { (eval echo configure:1365: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_c_const=yes
else
@@ -1379,21 +1382,21 @@ EOF
fi
echo $ac_n "checking for inline""... $ac_c" 1>&6
echo "configure:1383: checking for inline" >&5
echo "configure:1386: checking for inline" >&5
if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
ac_cv_c_inline=no
for ac_kw in inline __inline__ __inline; do
cat > conftest.$ac_ext <<EOF
#line 1390 "configure"
#line 1393 "configure"
#include "confdefs.h"
int main() {
} int $ac_kw foo() {
; return 0; }
EOF
if { (eval echo configure:1397: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
if { (eval echo configure:1400: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_c_inline=$ac_kw; break
else
@@ -1419,12 +1422,12 @@ EOF
esac
echo $ac_n "checking for off_t""... $ac_c" 1>&6
echo "configure:1423: checking for off_t" >&5
echo "configure:1426: checking for off_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1428 "configure"
#line 1431 "configure"
#include "confdefs.h"
#include <sys/types.h>
#if STDC_HEADERS
@@ -1452,12 +1455,12 @@ EOF
fi
echo $ac_n "checking for pid_t""... $ac_c" 1>&6
echo "configure:1456: checking for pid_t" >&5
echo "configure:1459: checking for pid_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1461 "configure"
#line 1464 "configure"
#include "confdefs.h"
#include <sys/types.h>
#if STDC_HEADERS
@@ -1485,12 +1488,12 @@ EOF
fi
echo $ac_n "checking for size_t""... $ac_c" 1>&6
echo "configure:1489: checking for size_t" >&5
echo "configure:1492: checking for size_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1494 "configure"
#line 1497 "configure"
#include "confdefs.h"
#include <sys/types.h>
#if STDC_HEADERS
@@ -1518,12 +1521,12 @@ EOF
fi
echo $ac_n "checking for st_rdev in struct stat""... $ac_c" 1>&6
echo "configure:1522: checking for st_rdev in struct stat" >&5
echo "configure:1525: checking for st_rdev in struct stat" >&5
if eval "test \"`echo '$''{'ac_cv_struct_st_rdev'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1527 "configure"
#line 1530 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <sys/stat.h>
@@ -1531,7 +1534,7 @@ int main() {
struct stat s; s.st_rdev;
; return 0; }
EOF
if { (eval echo configure:1535: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
if { (eval echo configure:1538: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_struct_st_rdev=yes
else
@@ -1552,12 +1555,12 @@ EOF
fi
echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
echo "configure:1556: checking whether time.h and sys/time.h may both be included" >&5
echo "configure:1559: checking whether time.h and sys/time.h may both be included" >&5
if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1561 "configure"
#line 1564 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <sys/time.h>
@@ -1566,7 +1569,7 @@ int main() {
struct tm *tp;
; return 0; }
EOF
if { (eval echo configure:1570: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
if { (eval echo configure:1573: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_header_time=yes
else
@@ -1607,6 +1610,21 @@ else
fi
# Check whether --with-lvm1 or --without-lvm1 was given.
if test "${with_lvm1+set}" = set; then
withval="$with_lvm1"
LVM1="$withval"
else
LVM1="internal"
fi
if [ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ];
then { echo "configure: error: --with-lvm1 parameter invalid
" 1>&2; exit 1; }
exit
fi;
# Check whether --enable-jobs or --disable-jobs was given.
if test "${enable_jobs+set}" = set; then
enableval="$enable_jobs"
@@ -1631,7 +1649,7 @@ if test "${enable_readline+set}" = set; then
\
READLINE=$enableval
else
READLINE=yes
READLINE=no
fi
@@ -1641,13 +1659,13 @@ fi;
if test $ac_cv_prog_gcc = yes; then
echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
echo "configure:1645: checking whether ${CC-cc} needs -traditional" >&5
echo "configure:1663: checking whether ${CC-cc} needs -traditional" >&5
if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
ac_pattern="Autoconf.*'x'"
cat > conftest.$ac_ext <<EOF
#line 1651 "configure"
#line 1669 "configure"
#include "confdefs.h"
#include <sgtty.h>
Autoconf TIOCGETP
@@ -1665,7 +1683,7 @@ rm -f conftest*
if test $ac_cv_prog_gcc_traditional = no; then
cat > conftest.$ac_ext <<EOF
#line 1669 "configure"
#line 1687 "configure"
#include "confdefs.h"
#include <termio.h>
Autoconf TCGETA
@@ -1687,12 +1705,12 @@ echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
fi
echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
echo "configure:1691: checking return type of signal handlers" >&5
echo "configure:1709: checking return type of signal handlers" >&5
if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1696 "configure"
#line 1714 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <signal.h>
@@ -1709,7 +1727,7 @@ int main() {
int i;
; return 0; }
EOF
if { (eval echo configure:1713: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
if { (eval echo configure:1731: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_type_signal=void
else
@@ -1728,12 +1746,12 @@ EOF
echo $ac_n "checking for vprintf""... $ac_c" 1>&6
echo "configure:1732: checking for vprintf" >&5
echo "configure:1750: checking for vprintf" >&5
if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1737 "configure"
#line 1755 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char vprintf(); below. */
@@ -1756,7 +1774,7 @@ vprintf();
; return 0; }
EOF
if { (eval echo configure:1760: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
if { (eval echo configure:1778: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_vprintf=yes"
else
@@ -1780,12 +1798,12 @@ fi
if test "$ac_cv_func_vprintf" != yes; then
echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
echo "configure:1784: checking for _doprnt" >&5
echo "configure:1802: checking for _doprnt" >&5
if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1789 "configure"
#line 1807 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char _doprnt(); below. */
@@ -1808,7 +1826,7 @@ _doprnt();
; return 0; }
EOF
if { (eval echo configure:1812: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
if { (eval echo configure:1830: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func__doprnt=yes"
else
@@ -1835,12 +1853,12 @@ fi
for ac_func in mkdir rmdir uname
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
echo "configure:1839: checking for $ac_func" >&5
echo "configure:1857: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1844 "configure"
#line 1862 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
@@ -1863,7 +1881,7 @@ $ac_func();
; return 0; }
EOF
if { (eval echo configure:1867: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
if { (eval echo configure:1885: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
@@ -1891,14 +1909,14 @@ done
if test x$READLINE = xyes; then
echo $ac_n "checking for library containing tgetent""... $ac_c" 1>&6
echo "configure:1895: checking for library containing tgetent" >&5
echo "configure:1913: checking for library containing tgetent" >&5
if eval "test \"`echo '$''{'ac_cv_search_tgetent'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
ac_func_search_save_LIBS="$LIBS"
ac_cv_search_tgetent="no"
cat > conftest.$ac_ext <<EOF
#line 1902 "configure"
#line 1920 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
@@ -1909,7 +1927,7 @@ int main() {
tgetent()
; return 0; }
EOF
if { (eval echo configure:1913: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
if { (eval echo configure:1931: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
ac_cv_search_tgetent="none required"
else
@@ -1920,7 +1938,7 @@ rm -f conftest*
test "$ac_cv_search_tgetent" = "no" && for i in ncurses curses termcap termlib; do
LIBS="-l$i $ac_func_search_save_LIBS"
cat > conftest.$ac_ext <<EOF
#line 1924 "configure"
#line 1942 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
@@ -1931,7 +1949,7 @@ int main() {
tgetent()
; return 0; }
EOF
if { (eval echo configure:1935: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
if { (eval echo configure:1953: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
ac_cv_search_tgetent="-l$i"
break
@@ -1965,7 +1983,7 @@ fi
if test x$READLINE = xyes; then
echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6
echo "configure:1969: checking for readline in -lreadline" >&5
echo "configure:1987: checking for readline in -lreadline" >&5
ac_lib_var=`echo readline'_'readline | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -1973,7 +1991,7 @@ else
ac_save_LIBS="$LIBS"
LIBS="-lreadline $LIBS"
cat > conftest.$ac_ext <<EOF
#line 1977 "configure"
#line 1995 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
@@ -1984,7 +2002,7 @@ int main() {
readline()
; return 0; }
EOF
if { (eval echo configure:1988: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
if { (eval echo configure:2006: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -2021,12 +2039,12 @@ package as well (which may be called readline-devel or something similar).
fi
echo $ac_n "checking for rl_completion_matches""... $ac_c" 1>&6
echo "configure:2025: checking for rl_completion_matches" >&5
echo "configure:2043: checking for rl_completion_matches" >&5
if eval "test \"`echo '$''{'ac_cv_func_rl_completion_matches'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 2030 "configure"
#line 2048 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char rl_completion_matches(); below. */
@@ -2049,7 +2067,7 @@ rl_completion_matches();
; return 0; }
EOF
if { (eval echo configure:2053: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
if { (eval echo configure:2071: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_rl_completion_matches=yes"
else
@@ -2085,6 +2103,7 @@ fi
trap '' 1 2 15
cat > confcache <<\EOF
# This file is a shell script that caches the results of configure
@@ -2203,6 +2222,7 @@ Makefile \
make.tmpl \
include/Makefile \
lib/Makefile \
lib/format1/Makefile \
man/Makefile \
tools/Makefile \
tools/version.h \
@@ -2255,6 +2275,7 @@ s%@CPP@%$CPP%g
s%@JOBS@%$JOBS%g
s%@STATIC_LINK@%$STATIC_LINK%g
s%@READLINE@%$READLINE%g
s%@LVM1@%$LVM1%g
s%@HAVE_RL_COMPLETION_MATCHES@%$HAVE_RL_COMPLETION_MATCHES%g
s%@OWNER@%$OWNER%g
s%@GROUP@%$GROUP%g
@@ -2305,6 +2326,7 @@ Makefile \
make.tmpl \
include/Makefile \
lib/Makefile \
lib/format1/Makefile \
man/Makefile \
tools/Makefile \
tools/version.h \

View File

@@ -61,15 +61,29 @@ AC_ARG_WITH(group,
[ GROUP="$withval" ],
[ GROUP="root" ])
dnl -- format1 inclusion type
AC_ARG_WITH(lvm1,
[ --with-lvm1=TYPE LVM1 metadata support: internal/shared/none
[TYPE=internal] ],
[ LVM1="$withval" ],
[ LVM1="internal" ])
if [[ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]];
then AC_MSG_ERROR(
--with-lvm1 parameter invalid
)
exit
fi;
AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=)
dnl Enables staticly linked tools
AC_ARG_ENABLE(static_link, [ --enable-static_link Use this to link the tools to the liblvm library
statically. Default is dynamic linking], STATIC_LINK=$enableval, STATIC_LINK=no)
dnl Disable readline
AC_ARG_ENABLE(readline, [ --disable-readline Disable readline support], \
READLINE=$enableval, READLINE=yes)
dnl Enable readline
AC_ARG_ENABLE(readline, [ --enable-readline Enable readline support], \
READLINE=$enableval, READLINE=no)
dnl Mess with default exec_prefix
if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
@@ -125,6 +139,7 @@ fi
AC_SUBST(JOBS)
AC_SUBST(STATIC_LINK)
AC_SUBST(READLINE)
AC_SUBST(LVM1)
AC_SUBST(HAVE_RL_COMPLETION_MATCHES)
AC_SUBST(OWNER)
AC_SUBST(GROUP)
@@ -137,6 +152,7 @@ Makefile \
make.tmpl \
include/Makefile \
lib/Makefile \
lib/format1/Makefile \
man/Makefile \
tools/Makefile \
tools/version.h \

6
debian/README.Debian vendored Normal file
View File

@@ -0,0 +1,6 @@
LVM2 requires the device-mapper kernel module (dm-mod). This is
available as a kernel patch for 2.4 (in kernel-patch-device-mapper), and
is distributed with linux 2.5 and above. The LVM1 kernel module (lvm-mod)
will not work with lvm2 packages. dm-mod and lvm-mod may both be loaded
in the kernel at the same time with no problems. Without dm-mod, this
package is pretty useless.

28
debian/changelog vendored
View File

@@ -1,8 +1,30 @@
lvm2 (1.95.08-1) unstable; urgency=low
lvm2 (1.95.11-1) unstable; urgency=low
* New upstream release (Beta3).
* New upstream release. (Closes: #171436)
* Removed TODO and INTRO from debian/docs; added WHATS_NEW.
* Remove vgcfgrestore.8 undocumented symlink.
* Added a README.Debian, mentioning the device-mapper kernel module
requirement that lvm2 has. (Closes: #171674, #163020)
* Get rid of debian/conffiles (debhelper's smart enough to figure that out).
* debian/copyright fix to appease lintian.
* Fix typo in tools/commands.h that caused /usr/sbin/; to be created.
-- Andres Salomon <dilinger@mp3revolution.net> Thu, 23 May 2002 03:46:37 -0500
-- Andres Salomon <dilinger@mp3revolution.net> Mon, 9 Dec 2002 02:51:02 -0400
lvm2 (1.95.10-2) unstable; urgency=low
* Fix software raid problems by ensuring lvm init script runs after
raidtools init script. (Closes: #152569)
-- Andres Salomon <dilinger@mp3revolution.net> Tue, 3 Sep 2002 04:05:43 -0400
lvm2 (1.95.10-1) unstable; urgency=low
* New upstream release (Beta 3.2).
* Change all references to /dev/device-mapper/control to
/dev/mapper/control.
-- Andres Salomon <dilinger@mp3revolution.net> Sun, 1 Sep 2002 18:55:12 -0400
lvm2 (0.95.05-3) unstable; urgency=low

2
debian/conffiles vendored
View File

@@ -1,2 +0,0 @@
/etc/lvm/lvm.conf
/etc/init.d/lvm2

2
debian/control vendored
View File

@@ -2,7 +2,7 @@ Source: lvm2
Section: admin
Priority: optional
Maintainer: Andres Salomon <dilinger@mp3revolution.net>
Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev, libreadline4-dev
Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev (>= 0.96.04), libreadline4-dev
Standards-Version: 3.5.2
Package: lvm2

2
debian/copyright vendored
View File

@@ -3,7 +3,7 @@ Wed, 20 Feb 2002 03:17:25 -0500.
It was downloaded from http://www.sistina.com/products_lvm.htm
Upstream Author(s): LVM Development Team
Upstream Author: LVM Development Team
Copyright (c) 2001-2002 LVM Development Team

3
debian/docs vendored
View File

@@ -1,6 +1,5 @@
BUGS
INTRO
README
TODO
VERSION
WHATS_NEW
doc/*

8
debian/init.d vendored
View File

@@ -14,7 +14,7 @@ modprobe dm-mod >/dev/null 2>&1
# Create necessary files in /dev for device-mapper
create_devfiles() {
DIR="/dev/device-mapper"
DIR="/dev/mapper"
FILE="$DIR/control"
major=$(grep "[0-9] misc$" /proc/devices | sed 's/[ ]\+misc//')
minor=$(grep "[0-9] device-mapper$" /proc/misc | sed 's/[ ]\+device-mapper//')
@@ -33,6 +33,12 @@ case "$1" in
echo -n "Initializing $DESC: "
create_devfiles
vgchange -a y
# # Mount all LVM devices
# for vg in $( vgchange -a y 2>/dev/null | grep active | awk -F\" '{print $2}' ); do
# MTPT=$( grep $vg /etc/fstab | awk '{print $2}' )
# mount $MTPT
# done
echo "$NAME."
;;
stop)

2
debian/rules vendored
View File

@@ -98,7 +98,7 @@ binary-arch: build install
# dh_installemacsen -a
# dh_installpam -a
# dh_installmime -a
dh_installinit --update-rcd-params="start 25 S . start 50 0 6 ."
dh_installinit --update-rcd-params="start 26 S . start 50 0 6 ."
dh_installcron
dh_installman
dh_installinfo

1
debian/undocumented vendored
View File

@@ -7,7 +7,6 @@ pvdata.8
pvmove.8
pvresize.8
version.8
vgcfgrestore.8
vgexport.8
vgimport.8
vgmknodes.8

View File

@@ -1,74 +1,87 @@
# This is an example configuration file for the LVM2 system. It
# contains the default settings that would be used if there was no
# This is an example configuration file for the LVM2 system.
# It contains the default settings that would be used if there was no
# /etc/lvm/lvm.conf file.
# Refer to 'man lvm.conf' for further information.
#
# Refer to 'man lvm.conf' for further information including the file layout.
#
# To put this file in a different directory and override /etc/lvm set
# the environment variable LVM_SYSTEM_DIR before running the tools.
# This section allows the user to configure which block devices should
# This section allows you to configure which block devices should
# be used by the LVM system.
devices {
# where do you want your volume groups to appear ?
# Where do you want your volume groups to appear ?
dir = "/dev"
# An array of directories that contain the device nodes you wish
# to use with LVM2.
scan = "/dev"
# A very important option, that allows you to tune the LVM2 system
# to just look at a restricted set of devices that you're
# interested in.
scan = [ "/dev" ]
# A filter that tells LVM2 to only use a restricted set of devices.
# The filter consists of an array of regular expressions. These
# expressions can be delimited by a character of your choice, and
# prefixed with either an 'a' (for accept) or 'r' (for reject).
# ATM you cannot use anchors (^ or $) in your regular expression.
# Remember to run vgscan after you change this parameter.
# By default we accept every block device:
filter = "a/.*/"
filter = [ "a/.*/" ]
# Exclude the cdrom drive
# filter = [ "r|/dev/cdrom|" ]
# When testing I like to work with just loopback devices:
# filter = ["a/loop/", "r/.*/"]
# filter = [ "a/loop/", "r/.*/" ]
# Or maybe all loops and ide drives except hdc:
# filter =["a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|"]
# filter =[ "a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|" ]
# The results of all the filtering are cached on disk to avoid
# Use anchors if you want to be really specific
# filter = [ "a|^/dev/hda8$|", "r/.*/" ]
# The results of the filtering are cached on disk to avoid
# rescanning dud devices (which can take a very long time). By
# default this cache file is hidden in the /etc/lvm directory, it
# is human readable to aid filter debugging.
# default this cache file is hidden in the /etc/lvm directory.
# It is safe to delete this file. vgscan regenerates it.
cache = "/etc/lvm/.cache"
# You can turn off writing this cache file by setting this to 0.
write_cache_state = 1
# An advanced setting.
# List of pairs of additional acceptable block device types found
# in /proc/devices with maximum (non-zero) number of partitions.
# types = [ "fd", 16 ]
}
# A section that allows the user to configure the nature of the
# This section that allows you to configure the nature of the
# information that LVM2 reports.
log {
# Where should the log of error and debug messages go ? By
# default there is no log.
#file = "/var/log/lvm2.log"
# Should we overwrite the last log. By default we append.
overwrite = 0
# There are 9 log levels, with 9 being the most verbose.
level = 3
# Controls the messages sent to stdout or stderr while running
# LVM2. There are three levels of verbosity, 3 being the most
# verbose.
# Controls the messages sent to stdout or stderr.
# There are three levels of verbosity, 3 being the most verbose.
verbose = 0
# Should we send log messages through syslog?
# 1 is yes; 0 is no.
syslog = 1
# Choose format of output messages
# Should we log error and debug messages to a file?
# By default there is no log file.
#file = "/var/log/lvm2.log"
# Should we overwrite the log file each time the program is run?
# By default we append.
overwrite = 0
# What level of log messages should we send to the log file and/or syslog?
# There are 6 syslog-like log levels currently in use - 2 to 7 inclusive.
# 7 is the most verbose (LOG_DEBUG).
level = 0
# Format of output messages
# Whether or not (1 or 0) to indent messages according to their severity
indent = 1
@@ -76,10 +89,11 @@ log {
command_names = 0
# A prefix to use before the message text (but after the command name,
# if selected)
# if selected). Default is two spaces, so you can see/grep the severity
# of each message.
prefix = " "
# To make the messages look similar to the original LVM use:
# To make the messages look similar to the original LVM tools use:
# indent = 0
# command_names = 1
# prefix = " -- "
@@ -93,19 +107,20 @@ backup {
# Should we maintain a backup of the current metadata configuration ?
# Use 1 for Yes; 0 for No.
# Think very hard before turning this off.
# Think very hard before turning this off!
backup = 1
# Where shall we keep it ?
# Remember to back up this directory regularly!
backup_dir = "/etc/lvm/backup"
# Should we maintain an archive of old metadata configurations.
# Use 1 for Yes; 0 for No.
# On by default. Think very hard before turning this off.
archive = 1
# Where should archived files go ?
# Remember to back up this directory regularly!
archive_dir = "/etc/lvm/archive"
# What is the minimum number of archive files you wish to keep ?
@@ -115,20 +130,15 @@ backup {
retain_days = 30
}
# Settings for the running LVM2 in shell mode.
# Settings for the running LVM2 in shell (readline) mode.
shell {
# Number of lines of history to store in ~/.lvm_history
history_size = 100
}
# Metadata settings
metadata {
# List of directories holding copies of text format metadata
dirs = [ "/etc/lvm/metadata" ]
}
# Miscellaneous global settings
# Miscellaneous global LVM2 settings
global {
# The file creation mask for any files and directories created.
@@ -143,10 +153,73 @@ global {
# command. Defaults to off.
test = 0
# Default metadata format commands use - "lvm1" (default) or "text"
format = "lvm1"
# Whether or not to communicate with the kernel device-mapper.
# Set to 0 if you want to use the tools to manipulate LVM metadata
# without activating any logical volumes.
# If the device-mapper kernel driver is not present in your kernel
# setting this to 0 should suppress the error messages.
activation = 1
# The default metadata format that commands should use - "lvm1" or "lvm2".
# The command line override is -M1 or -M2.
# Defaults to "lvm1" if compiled in, else "lvm2".
# format = "lvm1"
# Location of proc filesystem
proc = "/proc"
# Type of locking to use. Defaults to file-based locking (1).
# Turn locking off by setting to 0 (dangerous: risks metadata corruption
# if LVM2 commands get run concurrently).
locking_type = 1
# Local non-LV directory that holds file-based locks while commands are
# in progress. A directory like /tmp that may get wiped on reboot is OK.
locking_dir = "/var/lock/lvm"
# Other entries can go here to allow you to load shared libraries
# e.g. if support for LVM1 metadata was compiled as a shared library use
# format_libraries = "liblvm2format1.so"
# Full pathnames can be given.
# Search this directory first for shared libraries.
# library_dir = "/lib"
}
####################
# Advanced section #
####################
# Metadata settings
#
# 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
# when running pvcreate on new PVs which are to be added to large VGs.
# pvmetadatacopies = 2
# Approximate default size of on-disk metadata areas in sectors.
# You should increase this if you have large volume groups or
# you want to retain a large on-disk history of your metadata changes.
# pvmetadatasize = 255
# List of directories holding live copies of text format metadata.
# These directories must not be on logical volumes!
# It's possible to use LVM2 with a couple of directories here,
# preferably on different (non-LV) filesystems, and with no other
# on-disk metadata (pvmetadatacopies = 0). Or this can be in
# addition to on-disk metadata areas.
# The feature was originally added to simplify testing.
#
# Never edit any files in these directories by hand unless you
# you are absolutely sure you know what you are doing! Use
# the supplied toolset to make changes (e.g. vgcfgrestore).
# dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ]
#}

View File

@@ -1,4 +1,5 @@
../lib/activate/activate.h
../lib/cache/cache.h
../lib/commands/errors.h
../lib/commands/toolcontext.h
../lib/config/config.h
@@ -16,18 +17,20 @@
../lib/filters/filter-regex.h
../lib/filters/filter.h
../lib/format1/format1.h
../lib/format1/lvm1_label.h
../lib/format1/lvm1-label.h
../lib/format_text/format-text.h
../lib/label/label.h
../lib/label/uuid-map.h
../lib/locking/locking.h
../lib/log/log.h
../lib/metadata/metadata.h
../lib/mm/dbg_malloc.h
../lib/mm/pool.h
../lib/mm/xlate.h
../lib/misc/crc.h
../lib/misc/lib.h
../lib/misc/lvm-file.h
../lib/misc/lvm-string.h
../lib/misc/sharedlib.h
../lib/regex/matcher.h
../lib/report/report.h
../lib/uuid/uuid.h
../lib/vgcache/vgcache.h

View File

@@ -8,10 +8,16 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
ifeq ("@LVM1@", "shared")
SUBDIRS = format1
endif
SOURCES=\
activate/activate.c \
activate/dev_manager.c \
activate/fs.c \
cache/cache.c \
commands/toolcontext.c \
config/config.c \
datastruct/bitset.c \
datastruct/btree.c \
@@ -24,20 +30,14 @@ SOURCES=\
filters/filter-persistent.c \
filters/filter-regex.c \
filters/filter.c \
format1/disk-rep.c \
format1/format1.c \
format1/import-export.c \
format1/import-extents.c \
format1/layout.c \
format1/lvm1_label.c \
format1/vg_number.c \
format_text/archive.c \
format_text/export.c \
format_text/flags.c \
format_text/format-text.c \
format_text/import.c \
format_text/import_vsn1.c \
format_text/text_label.c \
label/label.c \
label/uuid-map.c \
locking/external_locking.c \
locking/file_locking.c \
locking/locking.c \
@@ -48,14 +48,27 @@ SOURCES=\
metadata/metadata.c \
metadata/pv_map.c \
metadata/snapshot_manip.c \
misc/crc.c \
misc/lvm-file.c \
misc/sharedlib.c \
mm/dbg_malloc.c \
mm/pool.c \
regex/matcher.c \
regex/parse_rx.c \
regex/ttree.c \
uuid/uuid.c \
vgcache/vgcache.c
report/report.c \
uuid/uuid.c
ifeq ("@LVM1@", "internal")
SOURCES+=\
format1/disk-rep.c \
format1/format1.c \
format1/import-export.c \
format1/import-extents.c \
format1/layout.c \
format1/lvm1-label.c \
format1/vg_number.c
endif
TARGETS=liblvm.a

View File

@@ -4,27 +4,48 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "metadata.h"
#include "activate.h"
#include "display.h"
#include "log.h"
#include "fs.h"
#include "lvm-string.h"
#include "pool.h"
#include "toolcontext.h"
#include "dev_manager.h"
/* FIXME Temporary */
#include "vgcache.h"
#include <limits.h>
#include <linux/kdev_t.h>
#include <fcntl.h>
#define _skip(fmt, args...) log_very_verbose("Skipping: " fmt , ## args)
static int _activation = 1;
void set_activation(int activation)
{
if (activation == _activation)
return;
_activation = activation;
if (_activation)
log_verbose("Activation enabled. Device-mapper kernel "
"driver will be used.");
else
log_verbose("Activation disabled. No device-mapper "
"interaction will be attempted.");
}
int activation()
{
return _activation;
}
int library_version(char *version, size_t size)
{
if (!activation())
return 0;
if (!dm_get_library_version(version, size))
return 0;
return 1;
@@ -35,6 +56,9 @@ int driver_version(char *version, size_t size)
int r = 0;
struct dm_task *dmt;
if (!activation())
return 0;
log_very_verbose("Getting driver version");
if (!(dmt = dm_task_create(DM_DEVICE_VERSION))) {
stack;
@@ -63,6 +87,9 @@ int lv_info(struct logical_volume *lv, struct dm_info *info)
int r;
struct dev_manager *dm;
if (!activation())
return 0;
if (!(dm = dev_manager_create(lv->vg->name))) {
stack;
return 0;
@@ -83,6 +110,9 @@ int lv_snapshot_percent(struct logical_volume *lv, float *percent)
int r;
struct dev_manager *dm;
if (!activation())
return 0;
if (!(dm = dev_manager_create(lv->vg->name))) {
stack;
return 0;
@@ -182,6 +212,9 @@ int lvs_in_vg_activated(struct volume_group *vg)
struct logical_volume *lv;
int count = 0;
if (!activation())
return 0;
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
count += (_lv_active(lv) == 1);
@@ -196,6 +229,9 @@ int lvs_in_vg_opened(struct volume_group *vg)
struct logical_volume *lv;
int count = 0;
if (!activation())
return 0;
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
count += (_lv_open_count(lv) == 1);
@@ -204,44 +240,21 @@ int lvs_in_vg_opened(struct volume_group *vg)
return count;
}
static struct logical_volume *_lv_from_lvid(struct cmd_context *cmd,
const char *lvid_s)
{
struct lv_list *lvl;
struct volume_group *vg;
union lvid *lvid;
lvid = (union lvid *) lvid_s;
log_very_verbose("Finding volume group for uuid %s", lvid_s);
if (!(vg = vg_read_by_vgid(cmd, lvid->id[0].uuid))) {
log_error("Volume group for uuid not found: %s", lvid_s);
return NULL;
}
log_verbose("Found volume group \"%s\"", vg->name);
if (vg->status & EXPORTED_VG) {
log_error("Volume group \"%s\" is exported", vg->name);
return NULL;
}
if (!(lvl = find_lv_in_vg_by_lvid(vg, lvid))) {
log_very_verbose("Can't find logical volume id %s", lvid_s);
return NULL;
}
return lvl->lv;
}
/* These return success if the device is not active */
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s)
{
struct logical_volume *lv;
struct dm_info info;
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
if (!activation())
return 1;
if (!(lv = lv_from_lvid(cmd, lvid_s)))
return 0;
if (!activation())
return 1;
if (test_mode()) {
_skip("Suspending '%s'.", lv->name);
return 0;
@@ -263,7 +276,10 @@ int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s)
struct logical_volume *lv;
struct dm_info info;
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
if (!activation())
return 1;
if (!(lv = lv_from_lvid(cmd, lvid_s)))
return 0;
if (test_mode()) {
@@ -287,7 +303,10 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
struct logical_volume *lv;
struct dm_info info;
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
if (!activation())
return 1;
if (!(lv = lv_from_lvid(cmd, lvid_s)))
return 0;
if (test_mode()) {
@@ -311,7 +330,10 @@ int lv_activate(struct cmd_context *cmd, const char *lvid_s)
struct logical_volume *lv;
struct dm_info info;
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
if (!activation())
return 1;
if (!(lv = lv_from_lvid(cmd, lvid_s)))
return 0;
if (test_mode()) {

View File

@@ -7,8 +7,12 @@
#ifndef LVM_ACTIVATE_H
#define LVM_ACTIVATE_H
#include "metadata.h"
#include <libdevmapper.h>
void set_activation(int activation);
int activation();
int driver_version(char *version, size_t size);
int library_version(char *version, size_t size);

View File

@@ -4,10 +4,10 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "dev_manager.h"
#include "pool.h"
#include "hash.h"
#include "log.h"
#include "lvm-string.h"
#include "fs.h"
@@ -162,7 +162,7 @@ static int _pre_list_add(struct pool *mem, struct list *pl, char *str)
* 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)
static void _count_hyphens(const char *str, size_t *len, int *hyphens)
{
const char *ptr;
@@ -337,7 +337,7 @@ static int _status_run(const char *name, const char *uuid,
int r = 0;
struct dm_task *dmt;
void *next = NULL;
unsigned long long start, length;
uint64_t start, length;
char *type = NULL;
char *params = NULL;
@@ -577,7 +577,7 @@ static int _resume(struct dev_layer *dl)
* Emit a target for a given segment.
* FIXME: tidy this function.
*/
static int _emit_target(struct dm_task *dmt, struct stripe_segment *seg)
static int _emit_target(struct dm_task *dmt, struct lv_segment *seg)
{
char params[1024];
uint64_t esize = seg->lv->vg->extent_size;
@@ -638,11 +638,11 @@ static int _populate_vanilla(struct dev_manager *dm,
struct dm_task *dmt, struct dev_layer *dl)
{
struct list *segh;
struct stripe_segment *seg;
struct lv_segment *seg;
struct logical_volume *lv = dl->lv;
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment);
seg = list_item(segh, struct lv_segment);
if (!_emit_target(dmt, seg)) {
log_error("Unable to build table for '%s'", lv->name);
return 0;
@@ -703,7 +703,7 @@ static int _populate_snapshot(struct dev_manager *dm,
return 0;
}
if (snprintf(params, sizeof(params), "%s/%s %s/%s P %d 128",
if (snprintf(params, sizeof(params), "%s/%s %s/%s P %d",
dm_dir(), origin, dm_dir(), cow, s->chunk_size) == -1) {
stack;
return 0;

View File

@@ -4,20 +4,16 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "fs.h"
#include "log.h"
#include "toolcontext.h"
#include "lvm-string.h"
#include "lvm-file.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <libdevmapper.h>
static int _mk_dir(struct volume_group *vg)

491
lib/cache/cache.c vendored Normal file
View File

@@ -0,0 +1,491 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#include "lib.h"
#include "cache.h"
#include "hash.h"
#include "toolcontext.h"
#include "dev-cache.h"
#include "metadata.h"
static struct hash_table *_pvid_hash = NULL;
static struct hash_table *_vgid_hash = NULL;
static struct hash_table *_vgname_hash = NULL;
static struct list _vginfos;
int _has_scanned = 0;
int cache_init()
{
list_init(&_vginfos);
if (!(_vgname_hash = hash_create(128)))
return 0;
if (!(_vgid_hash = hash_create(128)))
return 0;
if (!(_pvid_hash = hash_create(128)))
return 0;
return 1;
}
struct cache_vginfo *vginfo_from_vgname(const char *vgname)
{
struct cache_vginfo *vginfo;
if (!_vgname_hash)
return NULL;
if (!(vginfo = hash_lookup(_vgname_hash, vgname)))
return NULL;
return vginfo;
}
struct format_type *fmt_from_vgname(const char *vgname)
{
struct cache_vginfo *vginfo;
if (!(vginfo = vginfo_from_vgname(vgname)))
return NULL;
return vginfo->fmt;
}
struct cache_vginfo *vginfo_from_vgid(const char *vgid)
{
struct cache_vginfo *vginfo;
if (!_vgid_hash || !vgid)
return NULL;
if (!(vginfo = hash_lookup_fixed(_vgid_hash, vgid, ID_LEN)))
return NULL;
return vginfo;
}
struct cache_info *info_from_pvid(const char *pvid)
{
struct cache_info *info;
if (!_pvid_hash || !pvid)
return NULL;
if (!(info = hash_lookup_fixed(_pvid_hash, pvid, ID_LEN)))
return NULL;
return info;
}
static void _rescan_entry(struct cache_info *info)
{
struct label *label;
if (info->status & CACHE_INVALID)
label_read(info->dev, &label);
}
static int _scan_invalid(struct cmd_context *cmd)
{
hash_iter(_pvid_hash, (iterate_fn) _rescan_entry);
return 1;
}
int cache_label_scan(struct cmd_context *cmd, int full_scan)
{
struct label *label;
struct dev_iter *iter;
struct device *dev;
struct list *fmth;
struct format_type *fmt;
static int _scanning_in_progress = 0;
int r = 0;
/* Avoid recursion when a PVID can't be found! */
if (_scanning_in_progress)
return 0;
_scanning_in_progress = 1;
if (!_vgname_hash && !cache_init()) {
log_error("Internal cache initialisation failed");
goto out;
}
if (_has_scanned && !full_scan) {
r = _scan_invalid(cmd);
goto out;
}
if (!(iter = dev_iter_create(cmd->filter))) {
log_error("dev_iter creation failed");
goto out;
}
while ((dev = dev_iter_get(iter)))
label_read(dev, &label);
dev_iter_destroy(iter);
_has_scanned = 1;
/* Perform any format-specific scanning e.g. text files */
list_iterate(fmth, &cmd->formats) {
fmt = list_item(fmth, struct format_type);
if (fmt->ops->scan && !fmt->ops->scan(fmt))
goto out;
}
r = 1;
out:
_scanning_in_progress = 0;
return r;
}
struct list *cache_get_vgnames(struct cmd_context *cmd, int full_scan)
{
struct list *vgih, *vgnames;
struct str_list *sl;
cache_label_scan(cmd, full_scan);
if (!(vgnames = pool_alloc(cmd->mem, sizeof(struct list)))) {
log_error("vgnames list allocation failed");
return NULL;
}
list_init(vgnames);
list_iterate(vgih, &_vginfos) {
if (!(sl = pool_alloc(cmd->mem, sizeof(*sl)))) {
log_error("strlist allocation failed");
return NULL;
}
if (!(sl->str = pool_strdup(cmd->mem,
list_item(vgih,
struct cache_vginfo)->
vgname))) {
log_error("vgname allocation failed");
return NULL;
}
list_add(vgnames, &sl->list);
}
return vgnames;
}
struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
{
struct label *label;
struct cache_info *info;
/* Already cached ? */
if ((info = info_from_pvid((char *) pvid))) {
if (label_read(info->dev, &label)) {
info = (struct cache_info *) label->info;
if (id_equal(pvid, (struct id *) &info->dev->pvid))
return info->dev;
}
}
cache_label_scan(cmd, 0);
/* Try again */
if ((info = info_from_pvid((char *) pvid))) {
if (label_read(info->dev, &label)) {
info = (struct cache_info *) label->info;
if (id_equal(pvid, (struct id *) &info->dev->pvid))
return info->dev;
}
}
cache_label_scan(cmd, 1);
/* Try again */
if ((info = info_from_pvid((char *) pvid))) {
if (label_read(info->dev, &label)) {
info = (struct cache_info *) label->info;
if (id_equal(pvid, (struct id *) &info->dev->pvid))
return info->dev;
}
}
return NULL;
}
void _drop_vginfo(struct cache_info *info)
{
if (!list_empty(&info->list)) {
list_del(&info->list);
list_init(&info->list);
}
if (info->vginfo && list_empty(&info->vginfo->infos)) {
hash_remove(_vgname_hash, info->vginfo->vgname);
if (info->vginfo->vgname)
dbg_free(info->vginfo->vgname);
if (*info->vginfo->vgid)
hash_remove(_vgid_hash, info->vginfo->vgid);
list_del(&info->vginfo->list);
dbg_free(info->vginfo);
}
info->vginfo = NULL;
}
/* Unused
void cache_del(struct cache_info *info)
{
if (info->dev->pvid[0] && _pvid_hash)
hash_remove(_pvid_hash, info->dev->pvid);
_drop_vginfo(info);
info->label->labeller->ops->destroy_label(info->label->labeller,
info->label);
dbg_free(info);
return;
} */
static int _cache_update_pvid(struct cache_info *info, const char *pvid)
{
if (!strcmp(info->dev->pvid, pvid))
return 1;
if (*info->dev->pvid) {
hash_remove(_pvid_hash, info->dev->pvid);
}
strncpy(info->dev->pvid, pvid, sizeof(info->dev->pvid));
if (!hash_insert(_pvid_hash, pvid, info)) {
log_error("_cache_update: pvid insertion failed: %s", pvid);
return 0;
}
return 1;
}
static int _cache_update_vgid(struct cache_info *info, const char *vgid)
{
if (!vgid || !info->vginfo || !strncmp(info->vginfo->vgid, vgid,
sizeof(info->vginfo->vgid)))
return 1;
if (info->vginfo && *info->vginfo->vgid)
hash_remove(_vgid_hash, info->vginfo->vgid);
if (!vgid)
return 1;
strncpy(info->vginfo->vgid, vgid, sizeof(info->vginfo->vgid));
info->vginfo->vgid[sizeof(info->vginfo->vgid) - 1] = '\0';
if (!hash_insert(_vgid_hash, vgid, info->vginfo)) {
log_error("_cache_update: vgid hash insertion failed: %s",
vgid);
return 0;
}
return 1;
}
int cache_update_vgname(struct cache_info *info, const char *vgname)
{
struct cache_vginfo *vginfo;
/* If vgname is NULL and we don't already have a vgname,
* assume ORPHAN - we want every entry to have a vginfo
* attached for scanning reasons.
*/
if (!vgname && !info->vginfo)
vgname = ORPHAN;
if (!vgname || (info->vginfo && !strcmp(info->vginfo->vgname, vgname)))
return 1;
/* Remove existing vginfo entry */
_drop_vginfo(info);
/* Get existing vginfo or create new one */
if (!(vginfo = vginfo_from_vgname(vgname))) {
if (!(vginfo = dbg_malloc(sizeof(*vginfo)))) {
log_error("cache_update_vgname: list alloc failed");
return 0;
}
memset(vginfo, 0, sizeof(*vginfo));
if (!(vginfo->vgname = dbg_strdup(vgname))) {
dbg_free(vginfo);
log_error("cache vgname alloc failed for %s", vgname);
return 0;
}
list_init(&vginfo->infos);
if (!hash_insert(_vgname_hash, vginfo->vgname, vginfo)) {
log_error("cache_update: vg hash insertion failed: %s",
vginfo->vgname);
dbg_free(vginfo->vgname);
dbg_free(vginfo);
return 0;
}
/* Ensure orphans appear last on list_iterate */
if (!*vgname)
list_add(&_vginfos, &vginfo->list);
else
list_add_h(&_vginfos, &vginfo->list);
}
info->vginfo = vginfo;
list_add(&vginfo->infos, &info->list);
/* FIXME Check consistency of list! */
vginfo->fmt = info->fmt;
return 1;
}
int cache_update_vg(struct volume_group *vg)
{
struct list *pvh;
struct physical_volume *pv;
struct cache_info *info;
char pvid_s[ID_LEN + 1];
int vgid_updated = 0;
pvid_s[sizeof(pvid_s) - 1] = '\0';
list_iterate(pvh, &vg->pvs) {
pv = list_item(pvh, struct pv_list)->pv;
strncpy(pvid_s, (char *) &pv->id, sizeof(pvid_s) - 1);
/* FIXME Could pv->dev->pvid ever be different? */
if ((info = info_from_pvid(pvid_s))) {
cache_update_vgname(info, vg->name);
if (!vgid_updated) {
_cache_update_vgid(info, (char *) &vg->id);
vgid_updated = 1;
}
}
}
return 1;
}
struct cache_info *cache_add(struct labeller *labeller, const char *pvid,
struct device *dev,
const char *vgname, const char *vgid)
{
struct label *label;
struct cache_info *existing, *info;
char pvid_s[ID_LEN + 1];
if (!_vgname_hash && !cache_init()) {
log_error("Internal cache initialisation failed");
return NULL;
}
strncpy(pvid_s, pvid, sizeof(pvid_s));
pvid_s[sizeof(pvid_s) - 1] = '\0';
if (!(existing = info_from_pvid(pvid_s)) &&
!(existing = info_from_pvid(dev->pvid))) {
if (!(label = label_create(labeller))) {
stack;
return NULL;
}
if (!(info = dbg_malloc(sizeof(*info)))) {
log_error("cache_info allocation failed");
label_destroy(label);
return NULL;
}
memset(info, 0, sizeof(*info));
label->info = info;
info->label = label;
list_init(&info->list);
info->dev = dev;
} else {
info = existing;
/* Has labeller changed? */
if (info->label->labeller != labeller) {
label_destroy(info->label);
if (!(info->label = label_create(labeller))) {
/* FIXME leaves info without label! */
stack;
return NULL;
}
info->label->info = info;
}
label = info->label;
}
info->fmt = (struct format_type *) labeller->private;
info->status |= CACHE_INVALID;
if (!_cache_update_pvid(info, pvid_s)) {
if (!existing) {
dbg_free(info);
label_destroy(label);
}
return NULL;
}
if (!cache_update_vgname(info, vgname)) {
if (!existing) {
hash_remove(_pvid_hash, pvid_s);
strcpy(info->dev->pvid, "");
dbg_free(info);
label_destroy(label);
}
return NULL;
}
if (!_cache_update_vgid(info, vgid))
/* Non-critical */
stack;
return info;
}
static void _cache_destroy_entry(struct cache_info *info)
{
if (!list_empty(&info->list))
list_del(&info->list);
strcpy(info->dev->pvid, "");
label_destroy(info->label);
dbg_free(info);
}
static void _cache_destroy_vgnamelist(struct cache_vginfo *vginfo)
{
if (vginfo->vgname)
dbg_free(vginfo->vgname);
dbg_free(vginfo);
}
void cache_destroy()
{
_has_scanned = 0;
if (_vgid_hash) {
hash_destroy(_vgid_hash);
_vgid_hash = NULL;
}
if (_pvid_hash) {
hash_iter(_pvid_hash, (iterate_fn) _cache_destroy_entry);
hash_destroy(_pvid_hash);
_pvid_hash = NULL;
}
if (_vgname_hash) {
hash_iter(_vgname_hash, (iterate_fn) _cache_destroy_vgnamelist);
hash_destroy(_vgname_hash);
_vgname_hash = NULL;
}
list_init(&_vginfos);
}

73
lib/cache/cache.h vendored Normal file
View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#ifndef _LVM_CACHE_H
#define _LVM_CACHE_H
#include "dev-cache.h"
#include "list.h"
#include "uuid.h"
#include "label.h"
#include "metadata.h"
#include <sys/types.h>
#define ORPHAN ""
#define CACHE_INVALID 0x00000001
/* LVM specific per-volume info */
/* Eventual replacement for struct physical_volume perhaps? */
struct cache_vginfo {
struct list list; /* Join these vginfos together */
struct list infos; /* List head for cache_infos */
char *vgname; /* "" == orphan */
char vgid[ID_LEN + 1];
struct format_type *fmt;
};
struct cache_info {
struct list list; /* Join VG members together */
struct list mdas; /* list head for metadata areas */
struct list das; /* list head for data areas */
struct cache_vginfo *vginfo; /* NULL == unknown */
struct label *label;
struct format_type *fmt;
struct device *dev;
uint64_t device_size; /* Bytes */
uint32_t status;
};
int cache_init();
void cache_destroy();
/* Set full_scan to 1 to reread every filtered device label */
int cache_label_scan(struct cmd_context *cmd, int full_scan);
/* Add/delete a device */
struct cache_info *cache_add(struct labeller *labeller, const char *pvid,
struct device *dev,
const char *vgname, const char *vgid);
void cache_del(struct cache_info *info);
/* Update things */
int cache_update_vgname(struct cache_info *info, const char *vgname);
int cache_update_vg(struct volume_group *vg);
/* Queries */
struct format_type *fmt_from_vgname(const char *vgname);
struct cache_vginfo *vginfo_from_vgname(const char *vgname);
struct cache_vginfo *vginfo_from_vgid(const char *vgid);
struct cache_info *info_from_pvid(const char *pvid);
struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid);
/* Returns list of struct str_lists containing pool-allocated copy of vgnames */
/* Set full_scan to 1 to reread every filtered device label */
struct list *cache_get_vgnames(struct cmd_context *cmd, int full_scan);
#endif

492
lib/commands/toolcontext.c Normal file
View File

@@ -0,0 +1,492 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#include "lib.h"
#include "toolcontext.h"
#include "pool.h"
#include "metadata.h"
#include "defaults.h"
#include "lvm-string.h"
#include "activate.h"
#include "filter.h"
#include "filter-composite.h"
#include "filter-persistent.h"
#include "filter-regex.h"
#include "label.h"
#include "lvm-file.h"
#include "format-text.h"
#include "sharedlib.h"
#include "display.h"
#ifdef LVM1_INTERNAL
#include "format1.h"
#endif
#include <locale.h>
#include <sys/stat.h>
#include <syslog.h>
#include <dlfcn.h>
#include <time.h>
static FILE *_log;
static int _get_env_vars(struct cmd_context *cmd)
{
const char *e;
/* Set to "" to avoid using any system directory */
if ((e = getenv("LVM_SYSTEM_DIR"))) {
if (lvm_snprintf(cmd->sys_dir, sizeof(cmd->sys_dir),
"%s", e) < 0) {
log_error("LVM_SYSTEM_DIR environment variable "
"is too long.");
return 0;
}
}
return 1;
}
static void _init_logging(struct cmd_context *cmd)
{
char *open_mode = "a";
time_t t;
const char *log_file;
/* Syslog */
cmd->default_settings.syslog =
find_config_int(cmd->cf->root, "log/syslog", '/', DEFAULT_SYSLOG);
if (cmd->default_settings.syslog != 1)
fin_syslog();
if (cmd->default_settings.syslog > 1)
init_syslog(cmd->default_settings.syslog);
/* Debug level for log file output */
cmd->default_settings.debug =
find_config_int(cmd->cf->root, "log/level", '/', DEFAULT_LOGLEVEL);
init_debug(cmd->default_settings.debug);
/* Verbose level for tty output */
cmd->default_settings.verbose =
find_config_int(cmd->cf->root, "log/verbose", '/', DEFAULT_VERBOSE);
init_verbose(cmd->default_settings.verbose);
/* Log message formatting */
init_indent(find_config_int(cmd->cf->root, "log/indent", '/',
DEFAULT_INDENT));
cmd->default_settings.msg_prefix = find_config_str(cmd->cf->root,
"log/prefix", '/',
DEFAULT_MSG_PREFIX);
init_msg_prefix(cmd->default_settings.msg_prefix);
cmd->default_settings.cmd_name = find_config_int(cmd->cf->root,
"log/command_names",
'/', DEFAULT_CMD_NAME);
init_cmd_name(cmd->default_settings.cmd_name);
/* Test mode */
cmd->default_settings.test =
find_config_int(cmd->cf->root, "global/test", '/', 0);
/* Settings for logging to file */
if (find_config_int(cmd->cf->root, "log/overwrite", '/',
DEFAULT_OVERWRITE))
open_mode = "w";
log_file = find_config_str(cmd->cf->root, "log/file", '/', 0);
if (log_file) {
/* set up the logging */
if (!(_log = fopen(log_file, open_mode)))
log_error("Couldn't open log file %s", log_file);
else
init_log(_log);
}
t = time(NULL);
log_verbose("Logging initialised at %s", ctime(&t));
/* Tell device-mapper about our logging */
dm_log_init(print_log);
}
static int _process_config(struct cmd_context *cmd)
{
mode_t old_umask;
/* umask */
cmd->default_settings.umask = find_config_int(cmd->cf->root,
"global/umask", '/',
DEFAULT_UMASK);
if ((old_umask = umask((mode_t) cmd->default_settings.umask)) !=
(mode_t) cmd->default_settings.umask)
log_verbose("Set umask to %04o", cmd->default_settings.umask);
/* dev dir */
if (lvm_snprintf(cmd->dev_dir, sizeof(cmd->dev_dir), "%s/",
find_config_str(cmd->cf->root, "devices/dir",
'/', DEFAULT_DEV_DIR)) < 0) {
log_error("Device directory given in config file too long");
return 0;
}
dm_set_dev_dir(cmd->dev_dir);
/* proc dir */
if (lvm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
find_config_str(cmd->cf->root, "global/proc",
'/', DEFAULT_PROC_DIR)) < 0) {
log_error("Device directory given in config file too long");
return 0;
}
/* activation? */
cmd->default_settings.activation = find_config_int(cmd->cf->root,
"global/activation",
'/',
DEFAULT_ACTIVATION);
set_activation(cmd->default_settings.activation);
cmd->default_settings.suffix = find_config_int(cmd->cf->root,
"global/suffix",
'/', DEFAULT_SUFFIX);
if (!(cmd->default_settings.unit_factor =
units_to_bytes(find_config_str(cmd->cf->root,
"global/units",
'/',
DEFAULT_UNITS),
&cmd->default_settings.unit_type))) {
log_error("Invalid units specification");
return 0;
}
return 1;
}
/* Find and read config file */
static int _init_config(struct cmd_context *cmd)
{
struct stat info;
char config_file[PATH_MAX] = "";
if (!(cmd->cf = create_config_tree())) {
stack;
return 0;
}
/* No config file if LVM_SYSTEM_DIR is empty */
if (!*cmd->sys_dir)
return 1;
if (lvm_snprintf(config_file, sizeof(config_file),
"%s/lvm.conf", cmd->sys_dir) < 0) {
log_error("LVM_SYSTEM_DIR was too long");
destroy_config_tree(cmd->cf);
return 0;
}
/* Is there a config file? */
if (stat(config_file, &info) == -1) {
if (errno == ENOENT)
return 1;
log_sys_error("stat", config_file);
destroy_config_tree(cmd->cf);
return 0;
}
if (!read_config_file(cmd->cf, config_file)) {
log_error("Failed to load config file %s", config_file);
destroy_config_tree(cmd->cf);
return 0;
}
return 1;
}
static int _init_dev_cache(struct cmd_context *cmd)
{
struct config_node *cn;
struct config_value *cv;
if (!dev_cache_init()) {
stack;
return 0;
}
if (!(cn = find_config_node(cmd->cf->root, "devices/scan", '/'))) {
if (!dev_cache_add_dir("/dev")) {
log_error("Failed to add /dev to internal "
"device cache");
return 0;
}
log_verbose("device/scan not in config file: "
"Defaulting to /dev");
return 1;
}
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != CFG_STRING) {
log_error("Invalid string in config file: "
"devices/scan");
return 0;
}
if (!dev_cache_add_dir(cv->v.str)) {
log_error("Failed to add %s to internal device cache",
cv->v.str);
return 0;
}
}
return 1;
}
static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
{
struct config_node *cn;
struct dev_filter *f1, *f2, *f3;
cn = find_config_node(cmd->cf->root, "devices/types", '/');
if (!(f2 = lvm_type_filter_create(cmd->proc_dir, cn)))
return NULL;
if (!(cn = find_config_node(cmd->cf->root, "devices/filter", '/'))) {
log_debug("devices/filter not found in config file: no regex "
"filter installed");
return f2;
}
if (!(f1 = regex_filter_create(cn->v))) {
log_error("Failed to create regex device filter");
return f2;
}
if (!(f3 = composite_filter_create(2, f1, f2))) {
log_error("Failed to create composite device filter");
return f2;
}
return f3;
}
static int _init_filters(struct cmd_context *cmd)
{
const char *lvm_cache;
struct dev_filter *f3, *f4;
struct stat st;
char cache_file[PATH_MAX];
cmd->dump_filter = 0;
if (!(f3 = _init_filter_components(cmd)))
return 0;
if (lvm_snprintf(cache_file, sizeof(cache_file),
"%s/.cache", cmd->sys_dir) < 0) {
log_error("Persistent cache filename too long ('%s/.cache').",
cmd->sys_dir);
return 0;
}
lvm_cache =
find_config_str(cmd->cf->root, "devices/cache", '/', cache_file);
if (!(f4 = persistent_filter_create(f3, lvm_cache))) {
log_error("Failed to create persistent device filter");
return 0;
}
/* Should we ever dump persistent filter state? */
if (find_config_int(cmd->cf->root, "devices/write_cache_state", '/', 1))
cmd->dump_filter = 1;
if (!*cmd->sys_dir)
cmd->dump_filter = 0;
if (!stat(lvm_cache, &st) && !persistent_filter_load(f4))
log_verbose("Failed to load existing device cache from %s",
lvm_cache);
cmd->filter = f4;
return 1;
}
static int _init_formats(struct cmd_context *cmd)
{
const char *format;
struct format_type *fmt;
struct list *fmth;
struct config_node *cn;
struct config_value *cv;
struct format_type *(*init_format_fn) (struct cmd_context * cmd);
void *lib;
label_init();
#ifdef LVM1_INTERNAL
if (!(fmt = init_lvm1_format(cmd)))
return 0;
fmt->library = NULL;
list_add(&cmd->formats, &fmt->list);
#endif
/* Load any formats in shared libs */
if ((cn = find_config_node(cmd->cf->root, "global/format_libraries",
'/'))) {
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != CFG_STRING) {
log_error("Invalid string in config file: "
"global/format_libraries");
return 0;
}
if (!(lib = load_shared_library(cmd->cf, cv->v.str,
"format"))) {
stack;
return 0;
}
if (!(init_format_fn = dlsym(lib, "init_format"))) {
log_error("Shared library %s does not contain "
"format functions", cv->v.str);
dlclose(lib);
return 0;
}
if (!(fmt = init_format_fn(cmd)))
return 0;
fmt->library = lib;
list_add(&cmd->formats, &fmt->list);
}
}
if (!(fmt = create_text_format(cmd)))
return 0;
fmt->library = NULL;
list_add(&cmd->formats, &fmt->list);
cmd->fmt_backup = fmt;
format = find_config_str(cmd->cf->root, "global/format", '/',
DEFAULT_FORMAT);
list_iterate(fmth, &cmd->formats) {
fmt = list_item(fmth, struct format_type);
if (!strcasecmp(fmt->name, format) ||
(fmt->alias && !strcasecmp(fmt->alias, format))) {
cmd->default_settings.fmt = fmt;
return 1;
}
}
log_error("_init_formats: Default format (%s) not found", format);
return 0;
}
/* Entry point */
struct cmd_context *create_toolcontext(struct arg *the_args)
{
struct cmd_context *cmd;
if (!setlocale(LC_ALL, ""))
log_error("setlocale failed");
init_syslog(DEFAULT_LOG_FACILITY);
if (!(cmd = dbg_malloc(sizeof(*cmd)))) {
log_error("Failed to allocate command context");
return NULL;
}
memset(cmd, 0, sizeof(*cmd));
cmd->args = the_args;
list_init(&cmd->formats);
strcpy(cmd->sys_dir, DEFAULT_SYS_DIR);
if (!_get_env_vars(cmd))
goto error;
/* Create system directory if it doesn't already exist */
if (*cmd->sys_dir && !create_dir(cmd->sys_dir))
goto error;
if (!_init_config(cmd))
goto error;
_init_logging(cmd);
if (!_process_config(cmd))
goto error;
if (!_init_dev_cache(cmd))
goto error;
if (!_init_filters(cmd))
goto error;
if (!(cmd->mem = pool_create(4 * 1024))) {
log_error("Command memory pool creation failed");
return 0;
}
if (!_init_formats(cmd))
goto error;
cmd->current_settings = cmd->default_settings;
return cmd;
error:
dbg_free(cmd);
return NULL;
}
void destroy_formats(struct list *formats)
{
struct list *fmtl, *tmp;
struct format_type *fmt;
void *lib;
list_iterate_safe(fmtl, tmp, formats) {
fmt = list_item(fmtl, struct format_type);
list_del(&fmt->list);
lib = fmt->library;
fmt->ops->destroy(fmt);
if (lib)
dlclose(lib);
}
}
void destroy_toolcontext(struct cmd_context *cmd)
{
if (cmd->dump_filter)
persistent_filter_dump(cmd->filter);
cache_destroy();
label_exit();
destroy_formats(&cmd->formats);
cmd->filter->destroy(cmd->filter);
pool_destroy(cmd->mem);
dev_cache_exit();
destroy_config_tree(cmd->cf);
dbg_free(cmd);
dump_memory();
fin_log();
fin_syslog();
if (_log)
fclose(_log);
}

View File

@@ -13,25 +13,60 @@
#include "pool.h"
#include "metadata.h"
#include <stdio.h>
#include <limits.h>
/*
* Config options that can be changed while commands are processed
*/
struct config_info {
int debug;
int verbose;
int test;
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 ? */
struct format_type *fmt;
mode_t umask;
};
/* FIXME Split into tool & library contexts */
/* command-instance-related variables needed by library */
struct cmd_context {
/* format handler allocates all objects from here */
struct pool *mem;
struct format_type *fmt; /* Current format to use by default */
struct format_type *fmt_backup; /* Format to use for backups */
/* FIXME Move into dynamic list */
struct format_type *fmt1; /* Format1 */
struct format_type *fmtt; /* Format_text */
struct list formats; /* Available formats */
char *cmd_line;
char *dev_dir;
struct dev_filter *filter;
struct config_file *cf;
struct command *command;
struct uuid_map *um;
struct arg *args;
struct dev_filter *filter;
int dump_filter; /* Dump filter when exiting? */
struct config_tree *cf;
struct config_info default_settings;
struct config_info current_settings;
char sys_dir[PATH_MAX];
char dev_dir[PATH_MAX];
char proc_dir[PATH_MAX];
};
struct cmd_context *create_toolcontext(struct arg *the_args);
void destroy_toolcontext(struct cmd_context *cmd);
#endif

View File

@@ -4,18 +4,18 @@
* This file is released under the LGPL.
*/
#include <sys/types.h>
#include "lib.h"
#include "config.h"
#include "crc.h"
#include "pool.h"
#include "device.h"
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include "config.h"
#include "pool.h"
#include "log.h"
#include <asm/page.h>
enum {
TOK_INT,
@@ -32,10 +32,10 @@ enum {
};
struct parser {
const char *fb, *fe; /* file limits */
char *fb, *fe; /* file limits */
int t; /* token limits and type */
const char *tb, *te;
char *tb, *te;
int fd; /* descriptor for file being parsed */
int line; /* line number we are on */
@@ -44,8 +44,10 @@ struct parser {
};
struct cs {
struct config_file cf;
struct config_tree cf;
struct pool *mem;
time_t timestamp;
char *filename;
};
static void _get_token(struct parser *p);
@@ -81,7 +83,7 @@ static int _tok_match(const char *str, const char *b, const char *e)
/*
* public interface
*/
struct config_file *create_config_file(void)
struct config_tree *create_config_tree(void)
{
struct cs *c;
struct pool *mem = pool_create(10 * 1024);
@@ -99,20 +101,24 @@ struct config_file *create_config_file(void)
c->mem = mem;
c->cf.root = (struct config_node *) NULL;
c->timestamp = 0;
c->filename = NULL;
return &c->cf;
}
void destroy_config_file(struct config_file *cf)
void destroy_config_tree(struct config_tree *cf)
{
pool_destroy(((struct cs *) cf)->mem);
}
int read_config(struct config_file *cf, const char *file)
int read_config_fd(struct config_tree *cf, int fd, const char *file,
off_t offset, uint32_t size, off_t offset2, uint32_t size2,
checksum_fn_t checksum_fn, uint32_t checksum)
{
struct cs *c = (struct cs *) cf;
struct parser *p;
struct stat info;
int r = 1, fd;
off_t mmap_offset;
int r = 0;
if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
stack;
@@ -120,12 +126,93 @@ int read_config(struct config_file *cf, const char *file)
}
p->mem = c->mem;
/* memory map the file */
if (stat(file, &info) || S_ISDIR(info.st_mode)) {
if (size2) {
/* FIXME Attempt adjacent mmaps MAP_FIXED into malloced space
* one PAGE_SIZE larger than required...
*/
if (!(p->fb = dbg_malloc(size + size2))) {
stack;
return 0;
}
if (lseek(fd, offset, SEEK_SET) < 0) {
log_sys_error("lseek", file);
goto out;
}
if (raw_read(fd, p->fb, size) != size) {
log_error("Circular read from %s failed", file);
goto out;
}
if (lseek(fd, offset2, SEEK_SET) < 0) {
log_sys_error("lseek", file);
goto out;
}
if (raw_read(fd, p->fb + size, size2) != size2) {
log_error("Circular read from %s failed", file);
goto out;
}
} else {
mmap_offset = offset % PAGE_SIZE;
/* memory map the file */
p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
MAP_PRIVATE, fd, offset - mmap_offset);
if (p->fb == (caddr_t) (-1)) {
log_sys_error("mmap", file);
goto out;
}
p->fb = p->fb + mmap_offset;
}
if (checksum_fn && checksum !=
(checksum_fn(checksum_fn(INITIAL_CRC, p->fb, size),
p->fb + size, size2))) {
log_error("%s: Checksum error", file);
goto out;
}
p->fe = p->fb + size + size2;
/* parse */
p->tb = p->te = p->fb;
p->line = 1;
_get_token(p);
if (!(cf->root = _file(p))) {
stack;
goto out;
}
r = 1;
out:
if (size2)
dbg_free(p->fb);
else {
/* unmap the file */
if (munmap((char *) (p->fb - mmap_offset), size)) {
log_sys_error("munmap", file);
r = 0;
}
}
return r;
}
int read_config_file(struct config_tree *cf, const char *file)
{
struct cs *c = (struct cs *) cf;
struct stat info;
int r = 1, fd;
if (stat(file, &info)) {
log_sys_error("stat", file);
return 0;
}
if (!S_ISREG(info.st_mode)) {
log_error("%s is not a regular file", file);
return 0;
}
if (info.st_size == 0) {
log_verbose("%s is empty", file);
return 1;
@@ -136,34 +223,82 @@ int read_config(struct config_file *cf, const char *file)
return 0;
}
p->fb = mmap((caddr_t) 0, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (p->fb == (caddr_t) (-1)) {
log_sys_error("mmap", file);
close(fd);
return 0;
}
p->fe = p->fb + info.st_size;
/* parse */
p->tb = p->te = p->fb;
p->line = 1;
_get_token(p);
if (!(cf->root = _file(p))) {
stack;
r = 0;
}
/* unmap the file */
if (munmap((char *) p->fb, info.st_size)) {
log_sys_error("munmap", file);
r = 0;
}
r = read_config_fd(cf, fd, file, 0, info.st_size, 0, 0,
(checksum_fn_t) NULL, 0);
close(fd);
c->timestamp = info.st_mtime;
c->filename = pool_strdup(c->mem, file);
return r;
}
static void _write_value(FILE * fp, struct config_value *v)
/*
* Returns 1 if config file reloaded
*/
int reload_config_file(struct config_tree **cf)
{
struct config_tree *new_cf;
struct cs *c = (struct cs *) *cf;
struct cs *new_cs;
struct stat info;
int r, fd;
if (!c->filename)
return 0;
if (stat(c->filename, &info) == -1) {
if (errno == ENOENT)
return 1;
log_sys_error("stat", c->filename);
log_error("Failed to reload configuration file");
return 0;
}
if (!S_ISREG(info.st_mode)) {
log_error("Configuration file %s is not a regular file",
c->filename);
return 0;
}
/* Unchanged? */
if (c->timestamp == info.st_mtime)
return 0;
log_verbose("Detected config file change: Reloading %s", c->filename);
if (info.st_size == 0) {
log_verbose("Config file reload: %s is empty", c->filename);
return 0;
}
if ((fd = open(c->filename, O_RDONLY)) < 0) {
log_sys_error("open", c->filename);
return 0;
}
if (!(new_cf = create_config_tree())) {
log_error("Allocation of new config_tree failed");
return 0;
}
r = read_config_fd(new_cf, fd, c->filename, 0, info.st_size, 0, 0,
(checksum_fn_t) NULL, 0);
close(fd);
if (r) {
new_cs = (struct cs *) new_cf;
new_cs->filename = pool_strdup(new_cs->mem, c->filename);
new_cs->timestamp = info.st_mtime;
destroy_config_tree(*cf);
*cf = new_cf;
}
return r;
}
static void _write_value(FILE *fp, struct config_value *v)
{
switch (v->type) {
case CFG_STRING:
@@ -177,10 +312,18 @@ static void _write_value(FILE * fp, struct config_value *v)
case CFG_INT:
fprintf(fp, "%d", v->v.i);
break;
case CFG_EMPTY_ARRAY:
fprintf(fp, "[]");
break;
default:
log_error("_write_value: Unknown value type: %d", v->type);
}
}
static int _write_config(struct config_node *n, FILE * fp, int level)
static int _write_config(struct config_node *n, FILE *fp, int level)
{
char space[MAX_INDENT + 1];
int l = (level < MAX_INDENT) ? level : MAX_INDENT;
@@ -190,7 +333,7 @@ static int _write_config(struct config_node *n, FILE * fp, int level)
return 1;
for (i = 0; i < l; i++)
space[i] = ' ';
space[i] = '\t';
space[i] = '\0';
while (n) {
@@ -223,7 +366,7 @@ static int _write_config(struct config_node *n, FILE * fp, int level)
return 1;
}
int write_config(struct config_file *cf, const char *file)
int write_config_file(struct config_tree *cf, const char *file)
{
int r = 1;
FILE *fp = fopen(file, "w");
@@ -306,7 +449,7 @@ static struct config_node *_section(struct parser *p)
static struct config_value *_value(struct parser *p)
{
/* '[' TYPE* ']' | TYPE */
struct config_value *h = 0, *l, *ll = 0;
struct config_value *h = NULL, *l, *ll = NULL;
if (p->t == TOK_ARRAY_B) {
match(TOK_ARRAY_B);
while (p->t != TOK_ARRAY_E) {
@@ -325,6 +468,16 @@ static struct config_value *_value(struct parser *p)
match(TOK_COMMA);
}
match(TOK_ARRAY_E);
/*
* Special case for an empty array.
*/
if (!h) {
if (!(h = _create_value(p)))
return NULL;
h->type = CFG_EMPTY_ARRAY;
}
} else
h = _type(p);
@@ -336,16 +489,19 @@ static struct config_value *_type(struct parser *p)
/* [0-9]+ | [0-9]*\.[0-9]* | ".*" */
struct config_value *v = _create_value(p);
if (!v)
return NULL;
switch (p->t) {
case TOK_INT:
v->type = CFG_INT;
v->v.i = strtol(p->tb, 0, 0); /* FIXME: check error */
v->v.i = strtol(p->tb, NULL, 0); /* FIXME: check error */
match(TOK_INT);
break;
case TOK_FLOAT:
v->type = CFG_FLOAT;
v->v.r = strtod(p->tb, 0); /* FIXME: check error */
v->v.r = strtod(p->tb, NULL); /* FIXME: check error */
match(TOK_FLOAT);
break;
@@ -384,7 +540,7 @@ static void _get_token(struct parser *p)
{
p->tb = p->te;
_eat_space(p);
if (p->tb == p->fe) {
if (p->tb == p->fe || !*p->tb) {
p->t = TOK_EOF;
return;
}
@@ -425,13 +581,14 @@ static void _get_token(struct parser *p)
case '"':
p->t = TOK_STRING;
p->te++;
while ((p->te != p->fe) && (*p->te != '"')) {
if ((*p->te == '\\') && (p->te + 1 != p->fe))
while ((p->te != p->fe) && (*p->te) && (*p->te != '"')) {
if ((*p->te == '\\') && (p->te + 1 != p->fe) &&
*(p->te + 1))
p->te++;
p->te++;
}
if (p->te != p->fe)
if ((p->te != p->fe) && (*p->te))
p->te++;
break;
@@ -448,7 +605,7 @@ static void _get_token(struct parser *p)
case '8':
case '9':
p->te++;
while (p->te != p->fe) {
while ((p->te != p->fe) && (*p->te)) {
if (*p->te == '.') {
if (p->t == TOK_FLOAT)
break;
@@ -461,7 +618,7 @@ static void _get_token(struct parser *p)
default:
p->t = TOK_IDENTIFIER;
while ((p->te != p->fe) && !isspace(*p->te) &&
while ((p->te != p->fe) && (*p->te) && !isspace(*p->te) &&
(*p->te != '#') && (*p->te != '='))
p->te++;
break;
@@ -470,15 +627,15 @@ static void _get_token(struct parser *p)
static void _eat_space(struct parser *p)
{
while (p->tb != p->fe) {
while ((p->tb != p->fe) && (*p->tb)) {
if (*p->te == '#') {
while ((p->te != p->fe) && (*p->te != '\n'))
while ((p->te != p->fe) && (*p->te) && (*p->te != '\n'))
p->te++;
p->line++;
}
else if (isspace(*p->te)) {
while ((p->te != p->fe) && isspace(*p->te)) {
while ((p->te != p->fe) && (*p->te) && isspace(*p->te)) {
if (*p->te == '\n')
p->line++;
p->te++;
@@ -558,7 +715,7 @@ struct config_node *find_config_node(struct config_node *cn,
}
const char *find_config_str(struct config_node *cn,
const char *path, char sep, const char *fail)
const char *path, const char sep, const char *fail)
{
struct config_node *n = find_config_node(cn, path, sep);
@@ -655,7 +812,7 @@ int find_config_bool(struct config_node *cn, const char *path,
}
int get_config_uint32(struct config_node *cn, const char *path,
char sep, uint32_t * result)
char sep, uint32_t *result)
{
struct config_node *n;
@@ -669,7 +826,7 @@ int get_config_uint32(struct config_node *cn, const char *path,
}
int get_config_uint64(struct config_node *cn, const char *path,
char sep, uint64_t * result)
char sep, uint64_t *result)
{
struct config_node *n;
@@ -682,3 +839,17 @@ int get_config_uint64(struct config_node *cn, const char *path,
*result = (uint64_t) n->v->v.i;
return 1;
}
int get_config_str(struct config_node *cn, const char *path,
char sep, char **result)
{
struct config_node *n;
n = find_config_node(cn, path, sep);
if (!n || !n->v || n->v->type != CFG_STRING)
return 0;
*result = n->v->v.str;
return 1;
}

View File

@@ -8,44 +8,53 @@
#define _LVM_CONFIG_H
#include <inttypes.h>
#include <sys/types.h>
enum {
CFG_STRING,
CFG_FLOAT,
CFG_INT,
CFG_STRING,
CFG_FLOAT,
CFG_INT,
CFG_EMPTY_ARRAY
};
struct config_value {
int type;
union {
int i;
float r;
char *str;
} v;
struct config_value *next; /* for arrays */
int type;
union {
int i;
float r;
char *str;
} v;
struct config_value *next; /* for arrays */
};
struct config_node {
char *key;
struct config_node *sib, *child;
struct config_value *v;
char *key;
struct config_node *sib, *child;
struct config_value *v;
};
struct config_file {
struct config_node *root;
struct config_tree {
struct config_node *root;
};
struct config_file *create_config_file(void);
void destroy_config_file(struct config_file *cf);
struct config_tree *create_config_tree(void);
void destroy_config_tree(struct config_tree *cf);
int read_config(struct config_file *cf, const char *file);
int write_config(struct config_file *cf, const char *file);
typedef uint32_t (*checksum_fn_t) (uint32_t initial, void *buf, uint32_t size);
int read_config_fd(struct config_tree *cf, int fd, const char *file,
off_t offset, uint32_t size, off_t offset2, uint32_t size2,
checksum_fn_t checksum_fn, uint32_t checksum);
int read_config_file(struct config_tree *cf, const char *file);
int write_config_file(struct config_tree *cf, const char *file);
int reload_config_file(struct config_tree **cf);
struct config_node *find_config_node(struct config_node *cn,
const char *path, char seperator);
const char *path, char separator);
const char *find_config_str(struct config_node *cn,
const char *path, char sep, const char *fail);
const char *path, const char sep, const char *fail);
int find_config_int(struct config_node *cn, const char *path,
char sep, int fail);
@@ -58,9 +67,7 @@ float find_config_float(struct config_node *cn, const char *path,
* off), (true, false).
*/
int find_config_bool(struct config_node *cn, const char *path,
char sep, int fail);
char sep, int fail);
int get_config_uint32(struct config_node *cn, const char *path,
char sep, uint32_t *result);
@@ -68,5 +75,7 @@ int get_config_uint32(struct config_node *cn, const char *path,
int get_config_uint64(struct config_node *cn, const char *path,
char sep, uint64_t *result);
#endif
int get_config_str(struct config_node *cn, const char *path,
char sep, char **result);
#endif

View File

@@ -7,9 +7,6 @@
#ifndef _LVM_DEFAULTS_H
#define _LVM_DEFAULTS_H
#define DEFAULT_SYS_DIR "/etc/lvm"
#define DEFAULT_ARCHIVE_ENABLED 1
#define DEFAULT_BACKUP_ENABLED 1
@@ -19,22 +16,64 @@
#define DEFAULT_ARCHIVE_DAYS 30
#define DEFAULT_ARCHIVE_NUMBER 10
#define DEFAULT_SYS_DIR "/etc/lvm"
#define DEFAULT_DEV_DIR "/dev"
#define DEFAULT_PROC_DIR "/proc"
#define DEFAULT_LOCK_DIR "/var/lock/lvm"
#define DEFAULT_LOCKING_LIB "lvm2_locking.so"
#define DEFAULT_UMASK 0077
#define DEFAULT_FORMAT "lvm1"
#ifdef LVM1_SUPPORT
#define DEFAULT_FORMAT "lvm1"
#else
#define DEFAULT_FORMAT "lvm2"
#endif
#define DEFAULT_PVMETADATASIZE 255
#define DEFAULT_PVMETADATACOPIES 1
#define DEFAULT_LABELSECTOR 1
#define DEFAULT_MSG_PREFIX " "
#define DEFAULT_CMD_NAME 0
#define DEFAULT_OVERWRITE 0
#ifndef DEFAULT_LOG_FACILITY
#define DEFAULT_LOG_FACILITY LOG_USER
#endif
#define DEFAULT_SYSLOG 1
#define DEFAULT_VERBOSE 0
#define DEFAULT_LOGLEVEL 0
#define DEFAULT_INDENT 1
#define DEFAULT_UNITS "h"
#define DEFAULT_SUFFIX 1
#define DEFAULT_ACTIVATION 1
#ifdef READLINE_SUPPORT
#define DEFAULT_MAX_HISTORY 100
#endif
#define DEFAULT_REP_ALIGNED 1
#define DEFAULT_REP_BUFFERED 1
#define DEFAULT_REP_HEADINGS 1
#define DEFAULT_REP_SEPARATOR " "
#endif /* _LVM_DEFAULTS_H */
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent"
#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_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_minor,origin,snap_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,pv_uuid"
#define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize"
#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"
#endif /* _LVM_DEFAULTS_H */

View File

@@ -4,15 +4,13 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "bitset.h"
#include "dbg_malloc.h"
#include <stdlib.h>
/* FIXME: calculate this. */
#define INT_SHIFT 5
bitset_t bitset_create(struct pool * mem, unsigned num_bits)
bitset_t bitset_create(struct pool *mem, unsigned num_bits)
{
int n = (num_bits / BITS_PER_INT) + 2;
int size = sizeof(int) * n;

View File

@@ -11,8 +11,6 @@
#include "pool.h"
#include <limits.h>
#include <string.h>
typedef uint32_t *bitset_t;

View File

@@ -4,8 +4,8 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "btree.h"
#include "log.h"
struct node {
uint32_t key;

View File

@@ -4,9 +4,8 @@
* This file is released under the LGPL.
*/
#include "dbg_malloc.h"
#include "lib.h"
#include "hash.h"
#include "log.h"
struct hash_node {
struct hash_node *next;
@@ -26,26 +25,26 @@ static unsigned char _nums[] = {
87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65,
49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28,
12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172,
144,
144,
176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79, 46, 168, 198, 41, 254,
178, 85, 253, 237, 250, 154, 133, 88, 35, 206, 95, 116, 252, 192, 54,
221,
221,
102, 218, 255, 240, 82, 106, 158, 201, 61, 3, 89, 9, 42, 155, 159, 93,
166, 80, 50, 34, 175, 195, 100, 99, 26, 150, 16, 145, 4, 33, 8, 189,
121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185,
194,
194,
193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232,
139,
139,
6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112,
84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196,
43,
43,
249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231,
71,
71,
230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47,
109,
109,
44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184,
163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120,
209
209
};
static struct hash_node *_create_node(const char *str)
@@ -60,10 +59,10 @@ static struct hash_node *_create_node(const char *str)
return n;
}
static unsigned _hash(const char *str)
static unsigned _hash(const char *str, int len)
{
unsigned long int h = 0, g;
while (*str) {
while (*str && len--) {
h <<= 4;
h += _nums[(int) *str++];
g = h & ((unsigned long) 0xf << 16u);
@@ -126,18 +125,30 @@ void hash_destroy(struct hash_table *t)
dbg_free(t);
}
static inline struct hash_node **_find(struct hash_table *t, const char *key)
static inline struct hash_node **_find_fixed(struct hash_table *t,
const char *key, uint32_t len)
{
unsigned h = _hash(key) & (t->num_slots - 1);
unsigned h = _hash(key, len) & (t->num_slots - 1);
struct hash_node **c;
for (c = &t->slots[h]; *c; c = &((*c)->next))
if (!strcmp(key, (*c)->key))
if (!strncmp(key, (*c)->key, len))
break;
return c;
}
static inline struct hash_node **_find(struct hash_table *t, const char *key)
{
return _find_fixed(t, key, strlen(key));
}
void *hash_lookup_fixed(struct hash_table *t, const char *key, uint32_t len)
{
struct hash_node **c = _find_fixed(t, key, len);
return *c ? (*c)->data : 0;
}
void *hash_lookup(struct hash_table *t, const char *key)
{
struct hash_node **c = _find(t, key);
@@ -227,6 +238,6 @@ struct hash_node *hash_get_first(struct hash_table *t)
struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n)
{
unsigned int h = _hash(n->key) & (t->num_slots - 1);
unsigned int h = _hash(n->key, strlen(n->key)) & (t->num_slots - 1);
return n->next ? n->next : _next_slot(t, h + 1);
}

View File

@@ -7,6 +7,8 @@
#ifndef _LVM_HASH_H
#define _LVM_HASH_H
#include "lvm-types.h"
struct hash_table;
struct hash_node;
@@ -17,6 +19,7 @@ void hash_destroy(struct hash_table *t);
void hash_wipe(struct hash_table *t);
void *hash_lookup(struct hash_table *t, const char *key);
void *hash_lookup_fixed(struct hash_table *t, const char *key, uint32_t len);
int hash_insert(struct hash_table *t, const char *key, void *data);
void hash_remove(struct hash_table *t, const char *key);

View File

@@ -13,11 +13,13 @@ struct list {
struct list *n, *p;
};
static inline void list_init(struct list *head) {
static inline void list_init(struct list *head)
{
head->n = head->p = head;
}
static inline void list_add(struct list *head, struct list *elem) {
static inline void list_add(struct list *head, struct list *elem)
{
assert(head->n);
elem->n = head;
@@ -27,7 +29,8 @@ static inline void list_add(struct list *head, struct list *elem) {
head->p = elem;
}
static inline void list_add_h(struct list *head, struct list *elem) {
static inline void list_add_h(struct list *head, struct list *elem)
{
assert(head->n);
elem->n = head->n;
@@ -37,27 +40,35 @@ static inline void list_add_h(struct list *head, struct list *elem) {
head->n = elem;
}
static inline void list_del(struct list *elem) {
static inline void list_del(struct list *elem)
{
elem->n->p = elem->p;
elem->p->n = elem->n;
}
static inline int list_empty(struct list *head) {
static inline int list_empty(struct list *head)
{
return head->n == head;
}
static inline int list_end(struct list *head, struct list *elem)
{
return elem->n == head;
}
#define list_iterate(v, head) \
for (v = (head)->n; v != head; v = v->n)
#define list_iterate_safe(v, t, head) \
for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
static inline int list_size(struct list *head) {
static inline int list_size(struct list *head)
{
int s = 0;
struct list *v;
list_iterate(v, head)
s++;
s++;
return s;
}

View File

@@ -4,17 +4,14 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "dev-cache.h"
#include "log.h"
#include "pool.h"
#include "hash.h"
#include "list.h"
#include "lvm-types.h"
#include "btree.h"
#include "dbg_malloc.h"
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/param.h>
@@ -63,6 +60,8 @@ static struct device *_create_dev(dev_t d)
list_init(&dev->aliases);
dev->dev = d;
dev->fd = -1;
dev->flags = 0;
memset(dev->pvid, 0, sizeof(dev->pvid));
return dev;
}
@@ -229,6 +228,21 @@ static void _full_scan(void)
_cache.has_scanned = 1;
}
int dev_cache_has_scanned(void)
{
return _cache.has_scanned;
}
void dev_cache_scan(int do_scan)
{
if (!do_scan)
_cache.has_scanned = 1;
else {
_cache.has_scanned = 0;
_full_scan();
}
}
int dev_cache_init(void)
{
_cache.names = NULL;

View File

@@ -27,6 +27,10 @@ struct dev_filter {
int dev_cache_init(void);
void dev_cache_exit(void);
/* Trigger(1) or avoid(0) a scan */
void dev_cache_scan(int do_scan);
int dev_cache_has_scanned(void);
int dev_cache_add_dir(const char *path);
struct device *dev_cache_get(const char *name, struct dev_filter *f);

View File

@@ -4,18 +4,18 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "device.h"
#include "lvm-types.h"
#include "log.h"
#include "metadata.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fs.h> // UGH!!! for BLKSSZGET
int dev_get_size(struct device *dev, uint64_t * size)
int dev_get_size(struct device *dev, uint64_t *size)
{
int fd;
long s;
@@ -39,7 +39,7 @@ int dev_get_size(struct device *dev, uint64_t * size)
return 1;
}
int dev_get_sectsize(struct device *dev, uint32_t * size)
int dev_get_sectsize(struct device *dev, uint32_t *size)
{
int fd;
int s;
@@ -62,6 +62,11 @@ int dev_get_sectsize(struct device *dev, uint32_t * size)
return 1;
}
static void _flush(int fd)
{
ioctl(fd, BLKFLSBUF, 0);
}
int dev_open(struct device *dev, int flags)
{
struct stat buf;
@@ -90,19 +95,15 @@ int dev_open(struct device *dev, int flags)
if ((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;
return 0;
}
_flush(dev->fd);
dev->flags = 0;
return 1;
}
static void _flush(int fd)
{
ioctl(fd, BLKFLSBUF, 0);
}
int dev_close(struct device *dev)
{
if (dev->fd < 0) {
@@ -125,7 +126,7 @@ int dev_close(struct device *dev)
/*
* FIXME: factor common code out.
*/
int _read(int fd, void *buf, size_t count)
int raw_read(int fd, void *buf, size_t count)
{
size_t n = 0;
int tot = 0;
@@ -161,12 +162,12 @@ int64_t dev_read(struct device * dev, uint64_t offset,
return 0;
}
return _read(fd, buffer, len);
return raw_read(fd, buffer, len);
}
int _write(int fd, const void *buf, size_t count)
{
size_t n = 0;
ssize_t n = 0;
int tot = 0;
/* Skip all writes */
@@ -213,24 +214,34 @@ int dev_zero(struct device *dev, uint64_t offset, int64_t len)
{
int64_t r, s;
char buffer[4096];
const char *name = dev_name(dev);
int fd = dev->fd;
int already_open;
if (fd < 0) {
log_error("Attempt to zero part of an unopened device %s",
name);
already_open = dev_is_open(dev);
if (!already_open && !dev_open(dev, O_RDWR)) {
stack;
return 0;
}
if (lseek(fd, offset, SEEK_SET) < 0) {
log_sys_error("lseek", name);
if (lseek(dev->fd, offset, SEEK_SET) < 0) {
log_sys_error("lseek", dev_name(dev));
if (!already_open && !dev_close(dev))
stack;
return 0;
}
if ((offset % SECTOR_SIZE) || (len % SECTOR_SIZE))
log_debug("Wiping %s at %" PRIu64 " length %" PRId64,
dev_name(dev), offset, len);
else
log_debug("Wiping %s at sector %" PRIu64 " length %" PRId64
" sectors", dev_name(dev), offset >> SECTOR_SHIFT,
len >> SECTOR_SHIFT);
memset(buffer, 0, sizeof(buffer));
while (1) {
s = len > sizeof(buffer) ? sizeof(buffer) : len;
r = _write(fd, buffer, s);
r = _write(dev->fd, buffer, s);
if (r <= 0)
break;
@@ -244,6 +255,9 @@ int dev_zero(struct device *dev, uint64_t offset, int64_t len)
dev->flags |= DEV_ACCESSED_W;
if (!already_open && !dev_close(dev))
stack;
/* FIXME: Always display error */
return (len == 0);
}

View File

@@ -17,6 +17,7 @@
* MA 02111-1307, USA
*/
#if 0
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
@@ -24,9 +25,12 @@
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <linux/major.h>
#include <linux/genhd.h>
#include "dbg_malloc.h"
#include "log.h"
@@ -34,11 +38,6 @@
#include "metadata.h"
#include "device.h"
#include <linux/fs.h>
#include <linux/major.h>
#include <linux/genhd.h>
#if 0
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))

View File

@@ -9,6 +9,7 @@
#include "lvm-types.h"
#include "list.h"
#include "uuid.h"
#define DEV_ACCESSED_W 0x00000001 /* Device written to? */
@@ -17,12 +18,14 @@
* pointer comparisons are valid.
*/
struct device {
struct list aliases; /* struct str_list from lvm-types.h */
struct list aliases; /* struct str_list from lvm-types.h */
dev_t dev;
/* private */
int fd;
uint32_t flags;
char pvid[ID_LEN + 1];
};
struct device_list {
@@ -30,6 +33,12 @@ struct device_list {
struct device *dev;
};
struct device_area {
struct device *dev;
uint64_t start; /* Bytes */
uint64_t size; /* Bytes */
};
/*
* All io should use these routines.
*/
@@ -39,24 +48,36 @@ int dev_get_sectsize(struct device *dev, uint32_t *size);
int dev_open(struct device *dev, int flags);
int dev_close(struct device *dev);
static inline int dev_fd(struct device *dev)
{
return dev->fd;
}
int raw_read(int fd, void *buf, size_t count);
int64_t dev_read(struct device *dev,
uint64_t offset, int64_t len, void *buffer);
int64_t dev_write(struct device *dev,
uint64_t offset, int64_t len, void *buffer);
int dev_zero(struct device *dev, uint64_t offset, int64_t len);
static inline const char *dev_name(struct device *dev) {
static inline const char *dev_name(struct device *dev)
{
return (dev) ? list_item(dev->aliases.n, struct str_list)->str :
"unknown device";
"unknown device";
}
/* Return a valid device name from the alias list; NULL otherwise */
const char *dev_name_confirmed(struct device *dev);
static inline int is_lvm_partition(const char *name) {
static inline int is_lvm_partition(const char *name)
{
return 1;
}
#endif
static inline int dev_is_open(struct device *dev)
{
return dev->fd >= 0 ? 1 : 0;
}
#endif

View File

@@ -18,48 +18,203 @@
*
*/
#include "lib.h"
#include "metadata.h"
#include "dbg_malloc.h"
#include "log.h"
#include "display.h"
#include "activate.h"
#include "uuid.h"
#include "toolcontext.h"
#include <sys/types.h>
#include <string.h>
#define SIZE_BUF 128
char *display_size(uint64_t size, size_len_t sl)
static struct {
alloc_policy_t alloc;
const char *str;
} _policies[] = {
{
ALLOC_NEXT_FREE, "next free"}, {
ALLOC_CONTIGUOUS, "contiguous"}, {
ALLOC_DEFAULT, "next free (default)"}
};
static struct {
segment_type_t segtype;
const char *str;
} _segtypes[] = {
{
SEG_STRIPED, "striped"}, {
SEG_MIRROR, "mirror"}, {
SEG_SNAPSHOT, "snapshot"}
};
static int _num_policies = sizeof(_policies) / sizeof(*_policies);
static int _num_segtypes = sizeof(_segtypes) / sizeof(*_segtypes);
uint64_t units_to_bytes(const char *units, char *unit_type)
{
char *ptr;
uint64_t v;
ptr = (char *) units;
if (isdigit(*units)) {
v = (uint64_t) strtod(units, &ptr);
if (ptr == units)
return 0;
} else
v = 1;
if (v == 1)
*unit_type = *ptr;
else
*unit_type = 'U';
switch (*ptr) {
case 'h':
case 'H':
v = 1ULL;
*unit_type = *ptr;
break;
case 's':
v *= SECTOR_SIZE;
case 'b':
case 'B':
v *= 1ULL;
break;
case 'k':
v *= 1024ULL;
break;
case 'm':
v *= 1024ULL * 1024ULL;
break;
case 'g':
v *= 1024ULL * 1024ULL * 1024ULL;
break;
case 't':
v *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
break;
case 'K':
v *= 1000ULL;
break;
case 'M':
v *= 1000ULL * 1000ULL;
break;
case 'G':
v *= 1000ULL * 1000ULL * 1000ULL;
break;
case 'T':
v *= 1000ULL * 1000ULL * 1000ULL * 1000ULL;
break;
default:
return 0;
}
if (*(ptr + 1))
return 0;
return v;
}
const char *get_alloc_string(alloc_policy_t alloc)
{
int i;
for (i = 0; i < _num_policies; i++)
if (_policies[i].alloc == alloc)
return _policies[i].str;
return NULL;
}
const char *get_segtype_string(segment_type_t segtype)
{
int i;
for (i = 0; i < _num_segtypes; i++)
if (_segtypes[i].segtype == segtype)
return _segtypes[i].str;
return "unknown";
}
alloc_policy_t get_alloc_from_string(const char *str)
{
int i;
for (i = 0; i < _num_policies; i++)
if (!strcmp(_policies[i].str, str))
return _policies[i].alloc;
log_error("Unrecognised allocation policy - using default");
return ALLOC_DEFAULT;
}
segment_type_t get_segtype_from_string(const char *str)
{
int i;
for (i = 0; i < _num_segtypes; i++)
if (!strcmp(_segtypes[i].str, str))
return _segtypes[i].segtype;
log_error("Unrecognised segment type - using default (striped)");
return SEG_STRIPED;
}
const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
{
int s;
ulong byte = 1024 * 1024 * 1024;
int suffix = 1;
uint64_t byte;
uint64_t units = 1024ULL;
char *size_buf = NULL;
char *size_str[][2] = {
{"Terabyte", "TB"},
{"Gigabyte", "GB"},
{"Megabyte", "MB"},
{"Kilobyte", "KB"},
{"", ""}
char *size_str[][3] = {
{" Terabyte", " TB", "T"},
{" Gigabyte", " GB", "G"},
{" Megabyte", " MB", "M"},
{" Kilobyte", " KB", "K"},
{"", "", ""},
{" Byte ", " B ", "B"},
{" Units ", " Un", "U"},
{" Sectors ", " Se", "S"},
{" ", " ", " "},
};
if (!(size_buf = dbg_malloc(SIZE_BUF))) {
if (!(size_buf = pool_alloc(cmd->mem, SIZE_BUF))) {
log_error("no memory for size display buffer");
return NULL;
return "";
}
if (size == 0LL)
sprintf(size_buf, "0");
else {
suffix = cmd->current_settings.suffix;
for (s = 0; s < 8; s++)
if (toupper((int) cmd->current_settings.unit_type) ==
*size_str[s][2])
break;
if (size == 0ULL) {
sprintf(size_buf, "0%s", suffix ? size_str[s][sl] : "");
return size_buf;
}
if (s < 8) {
byte = cmd->current_settings.unit_factor;
size *= 1024ULL;
} else {
suffix = 1;
if (cmd->current_settings.unit_type == 'H')
units = 1000ULL;
else
units = 1024ULL;
byte = units * units * units;
s = 0;
while (size_str[s] && size < byte)
s++, byte /= 1024;
snprintf(size_buf, SIZE_BUF - 1,
"%.2f %s", (float) size / byte, size_str[s][sl]);
s++, byte /= units;
}
/* Caller to deallocate */
snprintf(size_buf, SIZE_BUF - 1, "%.2f%s", (float) size / byte,
suffix ? size_str[s][sl] : "");
return size_buf;
}
@@ -89,10 +244,12 @@ void pvdisplay_colons(struct physical_volume *pv)
return;
}
void pvdisplay_full(struct physical_volume *pv)
/* FIXME Include label fields */
void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
void *handle)
{
char uuid[64];
char *size, *size1; /*, *size2; */
const char *size;
uint64_t pe_free;
@@ -104,49 +261,30 @@ void pvdisplay_full(struct physical_volume *pv)
return;
}
/* Compat */
if(!pv->pe_size) {
size = display_size((uint64_t) pv->size / 2, SIZE_SHORT);
log_print("\"%s\" is a new physical volume of %s", dev_name(pv->dev), size);
dbg_free(size);
return;
}
set_cmd_name("");
init_msg_prefix("");
/****** FIXME Do we really need this conditional here? */
log_print("--- %sPhysical volume ---", pv->pe_size ? "" : "NEW ");
log_print("PV Name %s", dev_name(pv->dev));
log_print("VG Name %s%s", pv->vg_name,
pv->status & EXPORTED_VG ? " (exported)" : "");
size = display_size((uint64_t) pv->size / 2, SIZE_SHORT);
size = display_size(cmd, (uint64_t) pv->size / 2, SIZE_SHORT);
if (pv->pe_size && pv->pe_count) {
size1 = display_size((pv->size - pv->pe_count * pv->pe_size)
/ 2, SIZE_SHORT);
/******** FIXME display LVM on-disk data size - static for now...
/******** FIXME display LVM on-disk data size
size2 = display_size(pv->size / 2, SIZE_SHORT);
********/
log_print("PV Size %s [%llu secs]" " / not "
"usable %s [LVM: %s]",
size, (uint64_t) pv->size, size1, "151 KB");
/* , size2); */
log_print("PV Size %s" " / not usable %s", /* [LVM: %s]", */
size, display_size(cmd,
(pv->size -
pv->pe_count * pv->pe_size) / 2,
SIZE_SHORT));
dbg_free(size1);
/* dbg_free(size2); */
} else
log_print("PV Size %s", size);
dbg_free(size);
/******** FIXME anytime this *isn't* available? */
log_print("PV Status available");
/*********FIXME Anything use this?
log_print("PV# %u", pv->pv_number);
**********/
/* PV number not part of LVM2 design
log_print("PV# %u", pv->pv_number);
*/
pe_free = pv->pe_count - pv->pe_alloc_count;
if (pv->pe_count && (pv->status & ALLOCATABLE_PV))
@@ -155,18 +293,13 @@ void pvdisplay_full(struct physical_volume *pv)
else
log_print("Allocatable NO");
/*********FIXME Erm...where is this stored?
log_print("Cur LV %u", vg->lv_count);
*/
/* LV count is no longer available when displaying PV
log_print("Cur LV %u", vg->lv_count);
*/
log_print("PE Size (KByte) %" PRIu64, pv->pe_size / 2);
log_print("Total PE %u", pv->pe_count);
log_print("Free PE %" PRIu64, pe_free);
log_print("Allocated PE %u", pv->pe_alloc_count);
#ifdef LVM_FUTURE
printf("Stale PE %u", pv->pe_stale);
#endif
log_print("PV UUID %s", *uuid ? uuid : "none");
log_print(" ");
@@ -174,13 +307,21 @@ void pvdisplay_full(struct physical_volume *pv)
}
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
struct physical_volume *pv)
struct physical_volume *pv, void *handle)
{
char uuid[64];
if (!pv)
return 0;
if (!id_write_format(&pv->id, uuid, sizeof(uuid))) {
stack;
return 0;
}
log_print("PV Name %s ", dev_name(pv->dev));
/* FIXME pv->pv_number); */
log_print("PV UUID %s", *uuid ? uuid : "none");
log_print("PV Status %sallocatable",
(pv->status & ALLOCATABLE_PV) ? "" : "NOT ");
log_print("Total PE / Free PE %u / %u",
@@ -190,8 +331,6 @@ int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
return 0;
}
void lvdisplay_colons(struct logical_volume *lv)
{
int inkernel;
@@ -207,25 +346,20 @@ void lvdisplay_colons(struct logical_volume *lv)
/* FIXME lv->lv_number, */
inkernel ? info.open_count : 0, lv->size, lv->le_count,
/* FIXME Add num allocated to struct! lv->lv_allocated_le, */
((lv->status & ALLOC_STRICT) +
(lv->status & ALLOC_CONTIGUOUS) * 2), lv->read_ahead,
(lv->alloc == ALLOC_CONTIGUOUS ? 2 : 0), lv->read_ahead,
inkernel ? info.major : -1, inkernel ? info.minor : -1);
return;
}
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
void *handle)
{
char *size;
uint32_t alloc;
struct dm_info info;
int inkernel;
int inkernel, snap_active;
char uuid[64];
struct snapshot *snap;
struct stripe_segment *seg;
struct list *lvseg;
struct logical_volume *origin;
float snap_percent;
int snap_active;
struct snapshot *snap = NULL;
struct list *slh, *snaplist;
float snap_percent; /* fused, fsize; */
if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) {
stack;
@@ -234,171 +368,100 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
inkernel = lv_info(lv, &info) && info.exists;
set_cmd_name("");
init_msg_prefix("");
log_print("--- Logical volume ---");
log_print("LV Name %s%s/%s", lv->vg->cmd->dev_dir,
lv->vg->name, lv->name);
log_print("VG Name %s", lv->vg->name);
/* Not in LVM1 format
log_print("LV UUID %s", uuid);
**/
log_print("LV Write Access %s",
(lv->status & LVM_WRITE) ? "read/write" : "read only");
/* see if this LV is an origin for a snapshot */
if ((snap = find_origin(lv))) {
struct list *slh, *snaplist = find_snapshots(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_active = lv_snapshot_percent(snap->cow,
&snap_percent);
log_print(" %s%s/%s [%s]",
lv->vg->cmd->dev_dir, lv->vg->name,
snap->cow->name,
(snap_active > 0) ? "active" : "INACTIVE");
lv->vg->cmd->dev_dir, lv->vg->name,
snap->cow->name,
(snap_active > 0) ? "active" : "INACTIVE");
}
/* reset so we don't try to use this to display other snapshot
* related information. */
snap = NULL;
snap_active = 0;
}
/* Check to see if this LV is a COW target for a snapshot */
else if ((snap = find_cow(lv))) {
} else if ((snap = find_cow(lv))) {
snap_active = lv_snapshot_percent(lv, &snap_percent);
log_print("LV snapshot status %s destination for %s%s/%s",
(snap_active > 0) ? "active" : "INACTIVE",
(snap_active > 0) ? "active" : "INACTIVE",
lv->vg->cmd->dev_dir, lv->vg->name,
snap->origin->name);
}
if (inkernel && info.suspended)
log_print("LV Status suspended");
else
log_print("LV Status %savailable",
!inkernel || (snap && (snap_active < 1))
? "NOT " : "");
inkernel ? "" : "NOT ");
/********* FIXME lv_number - not sure that we're going to bother with this
/********* FIXME lv_number
log_print("LV # %u", lv->lv_number + 1);
************/
/* LVM1 lists the number of LVs open in this field, therefore, so do we. */
log_print("# open %u", lvs_in_vg_opened(lv->vg));
/* We're not going to use this count ATM, 'cause it's not what LVM1 does
if (inkernel)
log_print("# open %u", info.open_count);
*/
/********
#ifdef LVM_FUTURE
printf("Mirror copies %u\n", lv->lv_mirror_copies);
printf("Consistency recovery ");
if (lv->lv_recovery | LV_BADBLOCK_ON)
printf("bad blocks\n");
else
printf("none\n");
printf("Schedule %u\n", lv->lv_schedule);
#endif
********/
if(snap)
origin = snap->origin;
else
origin = lv;
size = display_size(origin->size / 2, SIZE_SHORT);
log_print("LV Size %s", size);
dbg_free(size);
log_print("LV Size %s",
display_size(cmd,
snap ? snap->origin->size / 2 : lv->size / 2,
SIZE_SHORT));
log_print("Current LE %u", origin->le_count);
/********** FIXME allocation - is there anytime the allocated LEs will not
* equal the current LEs? */
log_print("Allocated LE %u", origin->le_count);
/**********/
log_print("Current LE %u",
snap ? snap->origin->le_count : lv->le_count);
list_iterate(lvseg, &lv->segments) {
seg = list_item(lvseg, struct stripe_segment);
if(seg->stripes > 1) {
log_print("Stripes %u", seg->stripes);
log_print("Stripe size (KByte) %u",
seg->stripe_size/2);
}
/* only want the first segment for LVM1 format output */
break;
}
/********** FIXME allocation
log_print("Allocated LE %u", lv->allocated_le);
**********/
if(snap) {
float fused, fsize;
if(snap_percent == -1)
snap_percent=100;
size = display_size(snap->chunk_size / 2, SIZE_SHORT);
log_print("snapshot chunk size %s", size);
dbg_free(size);
size = display_size(lv->size / 2, SIZE_SHORT);
sscanf(size, "%f", &fsize);
fused = fsize * ( snap_percent / 100 );
log_print("Allocated to snapshot %2.2f%% [%2.2f/%s]",
snap_percent, fused, size);
dbg_free(size);
/* FIXME: Think this'll make them wonder?? */
log_print("Allocated to COW-table %s", "00.01 KB");
}
/** Not in LVM1 format output **
log_print("Segments %u", list_size(&lv->segments));
***/
/********* FIXME Stripes & stripesize for each segment
log_print("Stripe size (KByte) %u", lv->stripesize / 2);
***********/
/**************
#ifdef LVM_FUTURE
printf("Bad block ");
if (lv->lv_badblock == LV_BADBLOCK_ON)
printf("on\n");
else
printf("off\n");
#endif
***************/
if (snap) {
if (snap_percent == -1)
snap_percent = 100;
/* FIXME next free == ALLOC_SIMPLE */
alloc = lv->status & (ALLOC_STRICT | ALLOC_CONTIGUOUS);
log_print("Allocation %s%s%s%s",
!(alloc & (ALLOC_STRICT | ALLOC_CONTIGUOUS)) ? "next free" :
"", (alloc == ALLOC_STRICT) ? "strict" : "",
(alloc == ALLOC_CONTIGUOUS) ? "contiguous" : "",
(alloc ==
(ALLOC_STRICT | ALLOC_CONTIGUOUS)) ? "strict/contiguous" :
"");
log_print("Snapshot chunk size %s",
display_size(cmd, snap->chunk_size / 2, SIZE_SHORT));
/*
size = display_size(lv->size / 2, 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);
if (lv->status & FIXED_MINOR)
log_print("Persistent minor %d", lv->minor);
/****************
#ifdef LVM_FUTURE
printf("IO Timeout (seconds) ");
if (lv->lv_io_timeout == 0)
printf("default\n\n");
else
printf("%lu\n\n", lv->lv_io_timeout);
#endif
*************/
if (inkernel)
log_print("Block device %d:%d", info.major,
info.minor);
@@ -408,15 +471,15 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
return 0;
}
void _display_stripe(struct stripe_segment *seg, int s, const char *pre)
void _display_stripe(struct lv_segment *seg, int s, const char *pre)
{
uint32_t len = seg->len / seg->stripes;
log_print("%sphysical volume\t%s", pre,
log_print("%sPhysical volume\t%s", pre,
seg->area[s].pv ? dev_name(seg->area[s].pv->dev) : "Missing");
if (seg->area[s].pv)
log_print("%sphysical extents\t%d to %d", pre,
log_print("%sPhysical extents\t%d to %d", pre,
seg->area[s].pe, seg->area[s].pe + len - 1);
}
@@ -424,29 +487,42 @@ int lvdisplay_segments(struct logical_volume *lv)
{
int s;
struct list *segh;
struct stripe_segment *seg;
struct lv_segment *seg;
log_print("--- Segments ---");
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment);
seg = list_item(segh, struct lv_segment);
log_print("logical extent %d to %d:",
log_print("Logical extent %u to %u:",
seg->le, seg->le + seg->len - 1);
if (seg->stripes == 1)
_display_stripe(seg, 0, " ");
if (seg->type == SEG_STRIPED && seg->stripes == 1)
log_print(" Type\t\tlinear");
else
log_print(" Type\t\t%s",
get_segtype_string(seg->type));
else {
log_print(" stripes\t\t%d", seg->stripes);
log_print(" stripe size\t\t%d", seg->stripe_size);
switch (seg->type) {
case SEG_STRIPED:
if (seg->stripes == 1)
_display_stripe(seg, 0, " ");
else {
log_print(" Stripes\t\t%u", seg->stripes);
log_print(" Stripe size\t\t%u KB",
seg->stripe_size / 2);
for (s = 0; s < seg->stripes; s++) {
log_print(" stripe %d:", s);
_display_stripe(seg, s, " ");
for (s = 0; s < seg->stripes; s++) {
log_print(" Stripe %d:", s);
_display_stripe(seg, s, " ");
}
}
log_print(" ");
break;
case SEG_SNAPSHOT:
case SEG_MIRROR:
;
}
log_print(" ");
}
log_print(" ");
@@ -461,29 +537,23 @@ void vgdisplay_extents(struct volume_group *vg)
void vgdisplay_full(struct volume_group *vg)
{
uint32_t access;
char *s1;
char uuid[64];
uint32_t active_pvs;
struct list *pvlist;
char uuid[64];
set_cmd_name("");
init_msg_prefix("");
/* get the number of active PVs */
if(vg->status & PARTIAL_VG) {
active_pvs=0;
list_iterate(pvlist, &(vg->pvs)) {
active_pvs++;
}
}
if (vg->status & PARTIAL_VG)
active_pvs = list_size(&vg->pvs);
else
active_pvs=vg->pv_count;
active_pvs = vg->pv_count;
log_print("--- Volume group ---");
log_print("VG Name %s", vg->name);
/****** Not in LVM1 output, so we aren't outputing it here:
log_print("System ID %s", vg->system_id);
*******/
log_print("Format %s", vg->fid->fmt->name);
if (vg->fid->fmt->features & FMT_MDAS) {
log_print("Metadata Areas %d",
list_size(&vg->fid->metadata_areas));
log_print("Metadata Sequence No %d", vg->seqno);
}
access = vg->status & (LVM_READ | LVM_WRITE);
log_print("VG Access %s%s%s%s",
access == (LVM_READ | LVM_WRITE) ? "read/write" : "",
@@ -491,49 +561,55 @@ void vgdisplay_full(struct volume_group *vg)
access == LVM_WRITE ? "write" : "",
access == 0 ? "error" : "");
log_print("VG Status %s%sresizable",
vg->status & EXPORTED_VG ? "exported/" : "available/",
vg->status & EXPORTED_VG ? "exported/" : "",
vg->status & RESIZEABLE_VG ? "" : "NOT ");
/* vg number not part of LVM2 design
log_print ("VG # %u\n", vg->vg_number);
*/
if (vg->status & CLUSTERED) {
log_print("Clustered yes");
log_print("Shared %s",
vg->status & SHARED ? "yes" : "no");
}
/****** FIXME VG # - we aren't implementing this because people should
* use the UUID for this anyway
log_print("VG # %u", vg->vg_number);
*******/
log_print("MAX LV %u", vg->max_lv);
log_print("Cur LV %u", vg->lv_count);
log_print("Open LV %u", lvs_in_vg_opened(vg));
log_print("MAX LV Size 256 TB");
log_print("Open LV %u", lvs_in_vg_opened(vg));
/****** FIXME Max LV Size
log_print ( "MAX LV Size %s",
( s1 = display_size ( LVM_LV_SIZE_MAX(vg) / 2, SIZE_SHORT)));
free ( s1);
*********/
log_print("Max PV %u", vg->max_pv);
log_print("Cur PV %u", vg->pv_count);
log_print("Act PV %u", active_pvs);
log_print("Act PV %u", active_pvs);
s1 =
display_size((uint64_t) vg->extent_count * (vg->extent_size / 2),
SIZE_SHORT);
log_print("VG Size %s", s1);
dbg_free(s1);
log_print("VG Size %s",
display_size(vg->cmd,
(uint64_t) vg->extent_count * (vg->extent_size /
2), SIZE_SHORT));
s1 = display_size(vg->extent_size / 2, SIZE_SHORT);
log_print("PE Size %s", s1);
dbg_free(s1);
log_print("PE Size %s",
display_size(vg->cmd, vg->extent_size / 2, SIZE_SHORT));
log_print("Total PE %u", vg->extent_count);
s1 = display_size(((uint64_t)
vg->extent_count - vg->free_count) *
(vg->extent_size / 2), SIZE_SHORT);
log_print("Alloc PE / Size %u / %s",
vg->extent_count - vg->free_count, s1);
dbg_free(s1);
vg->extent_count - vg->free_count, display_size(vg->cmd,
((uint64_t)
vg->
extent_count
-
vg->
free_count) *
(vg->
extent_size /
2),
SIZE_SHORT));
s1 =
display_size((uint64_t) vg->free_count * (vg->extent_size / 2),
SIZE_SHORT);
log_print("Free PE / Size %u / %s", vg->free_count, s1);
dbg_free(s1);
log_print("Free PE / Size %u / %s", vg->free_count,
display_size(vg->cmd,
(uint64_t) vg->free_count * (vg->extent_size /
2), SIZE_SHORT));
if (!id_write_format(&vg->id, uuid, sizeof(uuid))) {
stack;
@@ -553,17 +629,15 @@ void vgdisplay_colons(struct volume_group *vg)
void vgdisplay_short(struct volume_group *vg)
{
char *s1, *s2, *s3;
s1 = display_size(vg->extent_count * vg->extent_size / 2, SIZE_SHORT);
s2 =
display_size((vg->extent_count - vg->free_count) * vg->extent_size /
2, SIZE_SHORT);
s3 = display_size(vg->free_count * vg->extent_size / 2, SIZE_SHORT);
log_print("\"%s\" %-9s [%-9s used / %s free]", vg->name,
/********* FIXME if "open" print "/used" else print "/idle"??? ******/
s1, s2, s3);
dbg_free(s1);
dbg_free(s2);
dbg_free(s3);
display_size(vg->cmd, vg->extent_count * vg->extent_size / 2,
SIZE_SHORT), display_size(vg->cmd,
(vg->extent_count -
vg->free_count) *
vg->extent_size / 2,
SIZE_SHORT),
display_size(vg->cmd, vg->free_count * vg->extent_size / 2,
SIZE_SHORT));
return;
}

View File

@@ -25,23 +25,40 @@
#include <stdint.h>
typedef enum {SIZE_LONG=0, SIZE_SHORT=1} size_len_t;
typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1, SIZE_UNIT = 2 } size_len_t;
uint64_t units_to_bytes(const char *units, char *unit_type);
/* Specify size in KB */
char *display_size(uint64_t size, size_len_t sl);
const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl);
char *display_uuid(char *uuidstr);
void pvdisplay_colons(struct physical_volume *pv);
void pvdisplay_full(struct physical_volume *pv);
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv);
void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
void *handle);
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
struct physical_volume *pv, void *handle);
void lvdisplay_colons(struct logical_volume *lv);
int lvdisplay_segments(struct logical_volume *lv);
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv);
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
void *handle);
void vgdisplay_extents(struct volume_group *vg);
void vgdisplay_full(struct volume_group *vg);
void vgdisplay_colons(struct volume_group *vg);
void vgdisplay_short(struct volume_group *vg);
/*
* Allocation policy display conversion routines.
*/
const char *get_alloc_string(alloc_policy_t alloc);
alloc_policy_t get_alloc_from_string(const char *str);
/*
* Segment type display conversion routines.
*/
segment_type_t get_segtype_from_string(const char *str);
const char *get_segtype_string(segment_type_t segtype);
#endif

View File

@@ -4,9 +4,8 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "filter-composite.h"
#include "dbg_malloc.h"
#include "log.h"
#include <stdarg.h>

View File

@@ -4,14 +4,12 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "config.h"
#include "dev-cache.h"
#include "hash.h"
#include "dbg_malloc.h"
#include "log.h"
#include "filter-persistent.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
@@ -43,10 +41,13 @@ int persistent_filter_wipe(struct dev_filter *f)
struct pfilter *pf = (struct pfilter *) f->private;
hash_wipe(pf->devices);
/* Trigger complete device scan */
dev_cache_scan(1);
return 1;
}
static int _read_array(struct pfilter *pf, struct config_file *cf,
static int _read_array(struct pfilter *pf, struct config_tree *cf,
const char *path, void *data)
{
struct config_node *cn;
@@ -72,6 +73,8 @@ static int _read_array(struct pfilter *pf, struct config_file *cf,
if (!hash_insert(pf->devices, cv->v.str, data))
log_verbose("Couldn't add '%s' to filter ... ignoring",
cv->v.str);
/* Populate dev_cache ourselves */
dev_cache_get(cv->v.str, NULL);
}
return 1;
}
@@ -81,32 +84,37 @@ int persistent_filter_load(struct dev_filter *f)
struct pfilter *pf = (struct pfilter *) f->private;
int r = 0;
struct config_file *cf;
struct config_tree *cf;
if (!(cf = create_config_file())) {
if (!(cf = create_config_tree())) {
stack;
return 0;
}
if (!read_config(cf, pf->file)) {
if (!read_config_file(cf, pf->file)) {
stack;
goto out;
}
_read_array(pf, cf, "persistent_filter_cache/valid_devices",
PF_GOOD_DEVICE);
_read_array(pf, cf, "persistent_filter_cache/invalid_devices",
PF_BAD_DEVICE);
/* We don't gain anything by holding invalid devices */
/* _read_array(pf, cf, "persistent_filter_cache/invalid_devices",
PF_BAD_DEVICE); */
if (hash_get_num_entries(pf->devices))
/* Did we find anything? */
if (hash_get_num_entries(pf->devices)) {
/* We populated dev_cache ourselves */
dev_cache_scan(0);
r = 1;
}
out:
destroy_config_file(cf);
destroy_config_tree(cf);
return r;
}
static void _write_array(struct pfilter *pf, FILE * fp, const char *path,
static void _write_array(struct pfilter *pf, FILE *fp, const char *path,
void *data)
{
void *d;
@@ -147,11 +155,18 @@ int persistent_filter_dump(struct dev_filter *f)
"- not writing to %s", pf->file);
return 0;
}
if (!dev_cache_has_scanned()) {
log_very_verbose("Device cache incomplete - not writing "
"to %s", pf->file);
return 0;
}
log_very_verbose("Dumping persistent device cache to %s", pf->file);
fp = fopen(pf->file, "w");
if (!fp) {
log_sys_error("fopen", pf->file);
if (errno != EROFS)
log_sys_error("fopen", pf->file);
return 0;
}
@@ -159,7 +174,8 @@ int persistent_filter_dump(struct dev_filter *f)
fprintf(fp, "persistent_filter_cache {\n");
_write_array(pf, fp, "valid_devices", PF_GOOD_DEVICE);
_write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE);
/* We don't gain anything by remembering invalid devices */
/* _write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE); */
fprintf(fp, "}\n");
fclose(fp);

View File

@@ -4,12 +4,12 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "pool.h"
#include "filter-regex.h"
#include "matcher.h"
#include "device.h"
#include "bitset.h"
#include "log.h"
#include "list.h"
struct rfilter {
@@ -137,7 +137,7 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
* build the matcher.
*/
if (!(rf->engine = matcher_create(rf->mem, (const char **) regex,
count)))
count)))
stack;
r = 1;

View File

@@ -18,18 +18,15 @@
*
*/
#include "dbg_malloc.h"
#include "log.h"
#include "lib.h"
#include "dev-cache.h"
#include "filter.h"
#include "lvm-string.h"
#include "config.h"
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <linux/kdev_t.h>
@@ -43,6 +40,12 @@ typedef struct {
static int _md_major = -1;
int md_major(void)
{
return _md_major;
}
/* This list can be supplemented with devices/types in the config file */
static device_info_t device_info[] = {
{"ide", 16}, /* IDE disk */
{"sd", 16}, /* SCSI disk */
@@ -58,10 +61,8 @@ static device_info_t device_info[] = {
{NULL, 0}
};
static int *scan_proc_dev(const char *proc);
static int passes_lvm_type_device_filter(struct dev_filter *f,
struct device *dev)
static int _passes_lvm_type_device_filter(struct dev_filter *f,
struct device *dev)
{
int fd;
const char *name = dev_name(dev);
@@ -81,48 +82,18 @@ static int passes_lvm_type_device_filter(struct dev_filter *f,
return 1;
}
struct dev_filter *lvm_type_filter_create(const char *proc)
{
struct dev_filter *f;
if (!(f = dbg_malloc(sizeof(struct dev_filter)))) {
log_error("LVM type filter allocation failed");
return NULL;
}
f->passes_filter = passes_lvm_type_device_filter;
f->destroy = lvm_type_filter_destroy;
if (!(f->private = scan_proc_dev(proc)))
return NULL;
return f;
}
int md_major(void)
{
return _md_major;
}
void lvm_type_filter_destroy(struct dev_filter *f)
{
dbg_free(f->private);
dbg_free(f);
return;
}
static int *scan_proc_dev(const char *proc)
static int *_scan_proc_dev(const char *proc, struct config_node *cn)
{
char line[80];
char proc_devices[PATH_MAX];
FILE *pd = NULL;
int ret = 0;
int i, j = 0;
int line_maj = 0;
int blocksection = 0;
int dev_len = 0;
struct config_value *cv;
int *max_partitions_by_major;
char *name;
if (!(max_partitions_by_major =
dbg_malloc(sizeof(int) * NUMBER_OF_MAJORS))) {
@@ -173,12 +144,44 @@ static int *scan_proc_dev(const char *proc)
for (j = 0; device_info[j].name != NULL; j++) {
dev_len = strlen(device_info[j].name);
if (dev_len <= strlen(line + i)
&& !strncmp(device_info[j].name, line + i, dev_len)
&& (line_maj < NUMBER_OF_MAJORS)) {
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] =
device_info[j].max_partitions;
ret++;
break;
}
}
if (max_partitions_by_major[line_maj] || !cn)
continue;
/* Check devices/types for local variations */
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != CFG_STRING) {
log_error("Expecting string in devices/types "
"in config file");
return NULL;
}
dev_len = strlen(cv->v.str);
name = cv->v.str;
cv = cv->next;
if (!cv || cv->type != CFG_INT) {
log_error("Max partition count missing for %s "
"in devices/types in config file",
name);
return NULL;
}
if (!cv->v.i) {
log_error("Zero partition count invalid for "
"%s in devices/types in config file",
name);
return NULL;
}
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;
break;
}
}
@@ -186,3 +189,29 @@ static int *scan_proc_dev(const char *proc)
fclose(pd);
return max_partitions_by_major;
}
struct dev_filter *lvm_type_filter_create(const char *proc,
struct config_node *cn)
{
struct dev_filter *f;
if (!(f = dbg_malloc(sizeof(struct dev_filter)))) {
log_error("LVM type filter allocation failed");
return NULL;
}
f->passes_filter = _passes_lvm_type_device_filter;
f->destroy = lvm_type_filter_destroy;
if (!(f->private = _scan_proc_dev(proc, cn)))
return NULL;
return f;
}
void lvm_type_filter_destroy(struct dev_filter *f)
{
dbg_free(f->private);
dbg_free(f);
return;
}

View File

@@ -21,11 +21,13 @@
#ifndef _LVM_FILTER_H
#define _LVM_FILTER_H
struct dev_filter *lvm_type_filter_create(const char *proc);
#include "config.h"
struct dev_filter *lvm_type_filter_create(const char *proc,
struct config_node *cn);
void lvm_type_filter_destroy(struct dev_filter *f);
int md_major(void);
#endif

7
lib/format1/.export.sym Normal file
View File

@@ -0,0 +1,7 @@
Base {
global:
init_format;
local:
*;
};

31
lib/format1/Makefile.in Normal file
View File

@@ -0,0 +1,31 @@
#
# Copyright (C) 2002 Sistina Software (UK) Limited.
#
# This file is released under the LGPL.
#
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
SOURCES=\
disk-rep.c \
format1.c \
import-export.c \
import-extents.c \
layout.c \
lvm1-label.c \
vg_number.c
TARGETS=liblvm2format1.so
include ../../make.tmpl
install: libformat1.so
$(INSTALL) -D -o $(OWNER) -g $(GROUP) -m 555 $(STRIP) $< \
$(libdir)/liblvm2format1.so.$(LIB_VERSION)
$(LN_S) -f liblvm2format1.so.$(LIB_VERSION) $(libdir)/liblvm2format1.so
.PHONY: install

View File

@@ -4,15 +4,13 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "disk-rep.h"
#include "dbg_malloc.h"
#include "pool.h"
#include "xlate.h"
#include "log.h"
#include "vgcache.h"
#include "filter.h"
#include "cache.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/kdev_t.h>
@@ -116,12 +114,12 @@ static int _munge_formats(struct pv_disk *pvd)
switch (pvd->version) {
case 1:
pvd->pe_start = ((pvd->pe_on_disk.base +
pvd->pe_on_disk.size) / SECTOR_SIZE);
pvd->pe_on_disk.size) >> SECTOR_SHIFT);
break;
case 2:
pvd->version = 1;
pe_start = pvd->pe_start * SECTOR_SIZE;
pe_start = pvd->pe_start << SECTOR_SHIFT;
pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base;
break;
@@ -132,7 +130,7 @@ static int _munge_formats(struct pv_disk *pvd)
return 1;
}
int read_pvd(struct device *dev, struct pv_disk *pvd)
static int _read_pvd(struct device *dev, struct pv_disk *pvd)
{
if (dev_read(dev, 0, sizeof(*pvd), pvd) != sizeof(*pvd)) {
log_very_verbose("Failed to read PV data from %s",
@@ -143,14 +141,14 @@ int read_pvd(struct device *dev, struct pv_disk *pvd)
_xlate_pvd(pvd);
if (pvd->id[0] != 'H' || pvd->id[1] != 'M') {
log_very_verbose("%s does not have a valid PV identifier",
log_very_verbose("%s does not have a valid LVM1 PV identifier",
dev_name(dev));
return 0;
}
if (!_munge_formats(pvd)) {
log_very_verbose("Unknown metadata version %d found on %s",
pvd->version, dev_name(dev));
log_very_verbose("format1: Unknown metadata version %d "
"found on %s", pvd->version, dev_name(dev));
return 0;
}
@@ -282,6 +280,7 @@ static struct disk_list *__read_disk(struct format_type *fmt,
{
struct disk_list *dl = pool_alloc(mem, sizeof(*dl));
const char *name = dev_name(dev);
struct cache_info *info;
if (!dl) {
stack;
@@ -293,11 +292,20 @@ static struct disk_list *__read_disk(struct format_type *fmt,
list_init(&dl->uuids);
list_init(&dl->lvds);
if (!read_pvd(dev, &dl->pvd)) {
if (!_read_pvd(dev, &dl->pvd)) {
stack;
goto bad;
}
if (!(info = cache_add(fmt->labeller, dl->pvd.pv_uuid, dev,
dl->pvd.vg_name, NULL)))
stack;
else {
info->device_size = xlate32(dl->pvd.pv_size) << SECTOR_SHIFT;
list_init(&info->mdas);
info->status &= ~CACHE_INVALID;
}
/*
* is it an orphan ?
*/
@@ -305,7 +313,7 @@ static struct disk_list *__read_disk(struct format_type *fmt,
log_very_verbose("%s is not a member of any format1 VG", name);
/* Update VG cache */
vgcache_add(dl->pvd.vg_name, NULL, dev, fmt);
/* vgcache_add(dl->pvd.vg_name, NULL, dev, fmt); */
return (vg_name) ? NULL : dl;
}
@@ -319,7 +327,7 @@ static struct disk_list *__read_disk(struct format_type *fmt,
_munge_exported_vg(dl);
/* Update VG cache with what we found */
vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt);
/* vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt); */
if (vg_name && strcmp(vg_name, dl->pvd.vg_name)) {
log_very_verbose("%s is not a member of the VG %s",
@@ -407,14 +415,15 @@ int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
struct dev_iter *iter;
struct device *dev;
struct disk_list *data = NULL;
struct list *pvdh, *pvdh2;
struct list *vgih;
struct cache_vginfo *vginfo;
/* Fast path if we already saw this VG and cached the list of PVs */
if ((pvdh = vgcache_find(vg_name))) {
list_iterate(pvdh2, pvdh) {
dev = list_item(pvdh2, struct pvdev_list)->dev;
if (!(data = read_disk(fmt, dev, mem, vg_name)))
if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) &&
vginfo->infos.n) {
list_iterate(vgih, &vginfo->infos) {
dev = list_item(vgih, struct cache_info)->dev;
if (dev && !(data = read_disk(fmt, dev, mem, vg_name)))
break;
_add_pv_to_list(head, data);
}
@@ -422,11 +431,12 @@ int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
/* Did we find the whole VG? */
if (!vg_name || !*vg_name ||
(data && *data->pvd.vg_name &&
list_size(head) == data->vgd.pv_cur)) return 1;
list_size(head) == data->vgd.pv_cur))
return 1;
/* Something changed. Remove the hints. */
/* Failed */
list_init(head);
vgcache_del(vg_name);
/* vgcache_del(vg_name); */
}
if (!(iter = dev_iter_create(filter))) {
@@ -514,8 +524,7 @@ static int _write_lvs(struct disk_list *data)
struct lvd_list *ll = list_item(lvh, struct lvd_list);
offset = sizeof(struct lv_disk) * ll->lvd.lv_number;
if (offset + sizeof(struct lv_disk) >
data->pvd.lv_on_disk.size) {
if (offset + sizeof(struct lv_disk) > data->pvd.lv_on_disk.size) {
log_error("lv_number %d too large", ll->lvd.lv_number);
return 0;
}
@@ -587,19 +596,19 @@ static int __write_all_pvd(struct format_type *fmt, struct disk_list *data)
return 0;
}
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt);
/* vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt); */
/*
* Stop here for orphan pv's.
*/
if (data->pvd.vg_name[0] == '\0') {
if (!test_mode())
vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt);
/* if (!test_mode())
vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt); */
return 1;
}
if (!test_mode())
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev,
fmt);
/* if (!test_mode())
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev,
fmt); */
if (!_write_vgd(data)) {
log_error("Failed to write VG data to %s", pv_name);

View File

@@ -11,21 +11,17 @@
#include "metadata.h"
#include "pool.h"
#define SECTOR_SIZE 512
#define MAX_PV 256
#define MAX_LV 256
#define MAX_VG 99
#define MAX_PV_SIZE ((uint32_t) -1) /* 2TB in sectors - 1 */
#define MIN_PE_SIZE (8192L / SECTOR_SIZE) /* 8 KB in sectors */
#define MAX_PE_SIZE (16L * 1024L * 1024L / SECTOR_SIZE * 1024)
#define PE_SIZE_PV_SIZE_REL 5 /* PV size must be at least 5 times PE size */
#define MAX_LE_TOTAL 65534 /* 2^16 - 2 */
#define MAX_PV_SIZE ((uint32_t) -1) /* 2TB in sectors - 1 */
#define MIN_PE_SIZE (8192L >> SECTOR_SHIFT) /* 8 KB in sectors */
#define MAX_PE_SIZE (16L * 1024L * (1024L >> SECTOR_SHIFT) * 1024L)
#define PE_SIZE_PV_SIZE_REL 5 /* PV size must be at least 5 times PE size */
#define MAX_LE_TOTAL 65534 /* 2^16 - 2 */
#define MAX_PE_TOTAL ((uint32_t) -2)
#define UNMAPPED_EXTENT 0
/* volume group */
@@ -60,86 +56,84 @@
#define EXPORTED_TAG "PV_EXP" /* Identifier for exported PV */
#define IMPORTED_TAG "PV_IMP" /* Identifier for imported PV */
struct data_area {
uint32_t base;
uint32_t size;
};
} __attribute__ ((packed));
struct pv_disk {
uint8_t id[2];
uint16_t version; /* lvm version */
struct data_area pv_on_disk;
struct data_area vg_on_disk;
struct data_area pv_uuidlist_on_disk;
struct data_area lv_on_disk;
struct data_area pe_on_disk;
uint8_t pv_uuid[NAME_LEN];
uint8_t vg_name[NAME_LEN];
uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */
uint32_t pv_major;
uint32_t pv_number;
uint32_t pv_status;
uint32_t pv_allocatable;
uint32_t pv_size;
uint32_t lv_cur;
uint32_t pe_size;
uint32_t pe_total;
uint32_t pe_allocated;
uint8_t id[2];
uint16_t version; /* lvm version */
struct data_area pv_on_disk;
struct data_area vg_on_disk;
struct data_area pv_uuidlist_on_disk;
struct data_area lv_on_disk;
struct data_area pe_on_disk;
uint8_t pv_uuid[NAME_LEN];
uint8_t vg_name[NAME_LEN];
uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */
uint32_t pv_major;
uint32_t pv_number;
uint32_t pv_status;
uint32_t pv_allocatable;
uint32_t pv_size;
uint32_t lv_cur;
uint32_t pe_size;
uint32_t pe_total;
uint32_t pe_allocated;
/* only present on version == 2 pv's */
uint32_t pe_start;
};
} __attribute__ ((packed));
struct lv_disk {
uint8_t lv_name[NAME_LEN];
uint8_t vg_name[NAME_LEN];
uint32_t lv_access;
uint32_t lv_status;
uint32_t lv_open;
uint32_t lv_dev;
uint32_t lv_number;
uint32_t lv_mirror_copies; /* for future use */
uint32_t lv_recovery; /* " */
uint32_t lv_schedule; /* " */
uint32_t lv_size;
uint32_t lv_snapshot_minor; /* minor number of original */
uint16_t lv_chunk_size; /* chunk size of snapshot */
uint16_t dummy;
uint32_t lv_allocated_le;
uint32_t lv_stripes;
uint32_t lv_stripesize;
uint32_t lv_badblock; /* for future use */
uint32_t lv_allocation;
uint32_t lv_io_timeout; /* for future use */
uint32_t lv_read_ahead;
};
uint8_t lv_name[NAME_LEN];
uint8_t vg_name[NAME_LEN];
uint32_t lv_access;
uint32_t lv_status;
uint32_t lv_open;
uint32_t lv_dev;
uint32_t lv_number;
uint32_t lv_mirror_copies; /* for future use */
uint32_t lv_recovery; /* " */
uint32_t lv_schedule; /* " */
uint32_t lv_size;
uint32_t lv_snapshot_minor; /* minor number of original */
uint16_t lv_chunk_size; /* chunk size of snapshot */
uint16_t dummy;
uint32_t lv_allocated_le;
uint32_t lv_stripes;
uint32_t lv_stripesize;
uint32_t lv_badblock; /* for future use */
uint32_t lv_allocation;
uint32_t lv_io_timeout; /* for future use */
uint32_t lv_read_ahead;
} __attribute__ ((packed));
struct vg_disk {
uint8_t vg_uuid[ID_LEN]; /* volume group UUID */
uint8_t vg_name_dummy[NAME_LEN - ID_LEN]; /* rest of v1 VG name */
uint32_t vg_number; /* volume group number */
uint32_t vg_access; /* read/write */
uint32_t vg_status; /* active or not */
uint32_t lv_max; /* maximum logical volumes */
uint32_t lv_cur; /* current logical volumes */
uint32_t lv_open; /* open logical volumes */
uint32_t pv_max; /* maximum physical volumes */
uint32_t pv_cur; /* current physical volumes FU */
uint32_t pv_act; /* active physical volumes */
uint32_t dummy;
uint32_t vgda; /* volume group descriptor arrays FU */
uint32_t pe_size; /* physical extent size in sectors */
uint32_t pe_total; /* total of physical extents */
uint32_t pe_allocated; /* allocated physical extents */
uint32_t pvg_total; /* physical volume groups FU */
};
uint8_t vg_uuid[ID_LEN]; /* volume group UUID */
uint8_t vg_name_dummy[NAME_LEN - ID_LEN]; /* rest of v1 VG name */
uint32_t vg_number; /* volume group number */
uint32_t vg_access; /* read/write */
uint32_t vg_status; /* active or not */
uint32_t lv_max; /* maximum logical volumes */
uint32_t lv_cur; /* current logical volumes */
uint32_t lv_open; /* open logical volumes */
uint32_t pv_max; /* maximum physical volumes */
uint32_t pv_cur; /* current physical volumes FU */
uint32_t pv_act; /* active physical volumes */
uint32_t dummy;
uint32_t vgda; /* volume group descriptor arrays FU */
uint32_t pe_size; /* physical extent size in sectors */
uint32_t pe_total; /* total of physical extents */
uint32_t pe_allocated; /* allocated physical extents */
uint32_t pvg_total; /* physical volume groups FU */
} __attribute__ ((packed));
struct pe_disk {
uint16_t lv_num;
uint16_t le_num;
};
} __attribute__ ((packed));
struct uuid_list {
struct list list;
@@ -163,7 +157,6 @@ struct disk_list {
struct pe_disk *extents;
};
/*
* Layout constants.
*/
@@ -173,19 +166,17 @@ struct disk_list {
#define PV_SIZE 1024UL
#define VG_SIZE 4096UL
/*
* Functions to calculate layout info.
*/
int calculate_layout(struct disk_list *dl);
int calculate_extent_count(struct physical_volume *pv);
int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size,
uint32_t max_extent_count);
/*
* Low level io routines which read/write
* disk_lists.
*/
int read_pvd(struct device *dev, struct pv_disk *pvd);
struct disk_list *read_disk(struct format_type *fmt, struct device *dev,
struct pool *mem, const char *vg_name);
@@ -196,7 +187,6 @@ int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
int write_disks(struct format_type *fmt, struct list *pvds);
/*
* Functions to translate to between disk and in
* core structures.
@@ -208,27 +198,21 @@ int export_pv(struct pool *mem, struct volume_group *vg,
struct pv_disk *pvd, struct physical_volume *pv);
int import_vg(struct pool *mem,
struct volume_group *vg, struct disk_list *dl,
int partial);
struct volume_group *vg, struct disk_list *dl, int partial);
int export_vg(struct vg_disk *vgd, struct volume_group *vg);
int import_lv(struct pool *mem, struct logical_volume *lv,
struct lv_disk *lvd);
void export_lv(struct lv_disk *lvd, struct volume_group *vg,
struct logical_volume *lv, const char *dev_dir);
int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd);
int import_extents(struct pool *mem, struct volume_group *vg,
struct list *pvds);
int export_extents(struct disk_list *dl, int lv_num,
struct logical_volume *lv,
struct physical_volume *pv);
struct logical_volume *lv, struct physical_volume *pv);
int import_pvs(struct format_instance *fid, struct pool *mem,
int import_pvs(struct format_type *fmt, struct pool *mem,
struct volume_group *vg,
struct list *pvds, struct list *results, int *count);
int import_lvs(struct pool *mem, struct volume_group *vg,
struct list *pvds);
int import_lvs(struct pool *mem, struct volume_group *vg, struct list *pvds);
int export_lvs(struct disk_list *dl, struct volume_group *vg,
struct physical_volume *pv, const char *dev_dir);
@@ -247,5 +231,4 @@ int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
int export_vg_number(struct format_instance *fid, struct list *pvds,
const char *vg_name, struct dev_filter *filter);
#endif

View File

@@ -4,15 +4,17 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "disk-rep.h"
#include "dbg_malloc.h"
#include "pool.h"
#include "hash.h"
#include "limits.h"
#include "list.h"
#include "log.h"
#include "display.h"
#include "toolcontext.h"
#include "cache.h"
#include "lvm1-label.h"
#include "format1.h"
/* VG consistency checks */
static int _check_vgs(struct list *pvs, int *partial)
@@ -113,7 +115,7 @@ static struct volume_group *_build_vg(struct format_instance *fid,
if (!import_vg(mem, vg, dl, partial))
goto bad;
if (!import_pvs(fid, mem, vg, pvs, &vg->pvs, &vg->pv_count))
if (!import_pvs(fid->fmt, mem, vg, pvs, &vg->pvs, &vg->pv_count))
goto bad;
if (!import_lvs(mem, vg, pvs))
@@ -134,7 +136,8 @@ static struct volume_group *_build_vg(struct format_instance *fid,
}
static struct volume_group *_vg_read(struct format_instance *fid,
const char *vg_name, void *mda)
const char *vg_name,
struct metadata_area *mda)
{
struct pool *mem = pool_create(1024 * 10);
struct list pvs;
@@ -185,8 +188,7 @@ static struct disk_list *_flatten_pv(struct pool *mem, struct volume_group *vg,
if (!export_pv(mem, vg, &dl->pvd, pv) ||
!export_vg(&dl->vgd, vg) ||
!export_uuids(dl, vg) ||
!export_lvs(dl, vg, pv, dev_dir) ||
!calculate_layout(dl)) {
!export_lvs(dl, vg, pv, dev_dir) || !calculate_layout(dl)) {
stack;
pool_free(mem, dl);
return NULL;
@@ -227,7 +229,7 @@ static int _flatten_vg(struct format_instance *fid, struct pool *mem,
}
static int _vg_write(struct format_instance *fid, struct volume_group *vg,
void *mdl)
struct metadata_area *mda)
{
struct pool *mem = pool_create(1024 * 10);
struct list pvds;
@@ -243,26 +245,28 @@ static int _vg_write(struct format_instance *fid, struct volume_group *vg,
r = (_flatten_vg(fid, mem, vg, &pvds, fid->fmt->cmd->dev_dir,
fid->fmt->cmd->filter) &&
write_disks(fid->fmt, &pvds));
cache_update_vg(vg);
pool_destroy(mem);
return r;
}
int _pv_read(struct format_type *fmt, const char *name,
struct physical_volume *pv)
int _pv_read(struct format_type *fmt, const char *pv_name,
struct physical_volume *pv, struct list *mdas)
{
struct pool *mem = pool_create(1024);
struct disk_list *dl;
struct device *dev;
int r = 0;
log_very_verbose("Reading physical volume data %s from disk", name);
log_very_verbose("Reading physical volume data %s from disk", pv_name);
if (!mem) {
stack;
return 0;
}
if (!(dev = dev_cache_get(name, fmt->cmd->filter))) {
if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) {
stack;
goto out;
}
@@ -277,7 +281,7 @@ int _pv_read(struct format_type *fmt, const char *name,
goto out;
}
pv->fid = fmt->ops->create_instance(fmt, NULL, NULL);
pv->fmt = fmt;
r = 1;
@@ -286,123 +290,42 @@ int _pv_read(struct format_type *fmt, const char *name,
return r;
}
static struct list *_get_pvs(struct format_type *fmt, struct list *results)
static int _pv_setup(struct format_type *fmt,
uint64_t pe_start, uint32_t extent_count,
uint32_t extent_size,
int pvmetadatacopies,
uint64_t pvmetadatasize, struct list *mdas,
struct physical_volume *pv, struct volume_group *vg)
{
struct pool *mem = pool_create(1024 * 10);
struct list pvs;
uint32_t count;
if (!mem) {
stack;
return NULL;
}
list_init(&pvs);
if (!read_pvs_in_vg(fmt, NULL, fmt->cmd->filter, mem, &pvs)) {
stack;
goto bad;
}
if (!import_pvs(NULL, fmt->cmd->mem, NULL, &pvs, results, &count)) {
stack;
goto bad;
}
pool_destroy(mem);
return results;
bad:
pool_destroy(mem);
return NULL;
}
static int _find_vg_name(struct list *names, const char *vg)
{
struct list *nh;
struct name_list *nl;
list_iterate(nh, names) {
nl = list_item(nh, struct name_list);
if (!strcmp(nl->name, vg))
return 1;
}
return 0;
}
static struct list *_get_vgs(struct format_type *fmt, struct list *names)
{
struct list *pvh;
struct list *pvs;
struct name_list *nl;
if (!(pvs = pool_alloc(fmt->cmd->mem, sizeof(*pvs)))) {
log_error("PV list allocation failed");
goto err;
}
list_init(pvs);
if (!_get_pvs(fmt, pvs)) {
stack;
goto err;
}
list_iterate(pvh, pvs) {
struct pv_list *pvl = list_item(pvh, struct pv_list);
if (!(*pvl->pv->vg_name) ||
_find_vg_name(names, pvl->pv->vg_name))
continue;
if (!(nl = pool_alloc(fmt->cmd->mem, sizeof(*nl)))) {
stack;
goto err;
}
if (!(nl->name = pool_strdup(fmt->cmd->mem, pvl->pv->vg_name))) {
stack;
goto err;
}
list_add(names, &nl->list);
}
if (list_empty(names))
pool_free(fmt->cmd->mem, pvs);
return names;
err:
pool_free(fmt->cmd->mem, pvs);
return NULL;
}
static int _pv_setup(struct format_instance *fid, struct physical_volume *pv,
struct volume_group *vg)
{
/* setup operations for the PV structure */
if (pv->size > MAX_PV_SIZE)
pv->size--;
if (pv->size > MAX_PV_SIZE) {
/* FIXME Limit hardcoded */
log_error("Physical volumes cannot be bigger than 2TB");
log_error("Physical volumes cannot be bigger than %s",
display_size(fmt->cmd, MAX_PV_SIZE / 2, SIZE_SHORT));
return 0;
}
/* Nothing more to do if pe_size isn't known */
if (!vg)
/* Nothing more to do if extent size isn't provided */
if (!extent_size)
return 1;
/*
* This works out pe_start and pe_count.
*/
if (!calculate_extent_count(pv)) {
if (!calculate_extent_count(pv, extent_size, extent_count)) {
stack;
return 0;
}
/* Retain existing extent locations exactly */
/* FIXME Relax this so a non-overlapping existing pe_start can also
* be used in place of the calculated one */
if (((pe_start || extent_count) && (pe_start != pv->pe_start)) ||
(extent_count && (extent_count != pv->pe_count))) {
log_error("Metadata would overwrite physical extents");
return 0;
}
return 1;
}
@@ -439,29 +362,36 @@ static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
return 0;
}
if (lv->size > max_size) {
char *dummy = display_size(max_size, SIZE_SHORT);
log_error("logical volumes cannot be larger than %s", dummy);
dbg_free(dummy);
log_error("logical volumes cannot be larger than %s",
display_size(fid->fmt->cmd, max_size / 2,
SIZE_SHORT));
return 0;
}
return 1;
}
static int _pv_write(struct format_instance *fid, struct physical_volume *pv,
void *mdl)
static int _pv_write(struct format_type *fmt, struct physical_volume *pv,
struct list *mdas, int64_t sector)
{
struct pool *mem;
struct disk_list *dl;
struct list pvs;
struct label *label;
struct cache_info *info;
list_init(&pvs);
if (*pv->vg_name || pv->pe_alloc_count) {
log_error("Assertion failed: can't _pv_write non-orphan PV "
"(in VG %s)", pv->vg_name);
if (!(info = cache_add(fmt->labeller, (char *) &pv->id, pv->dev,
pv->vg_name, NULL))) {
stack;
return 0;
}
label = info->label;
info->device_size = pv->size << SECTOR_SHIFT;
info->fmt = fmt;
list_init(&info->mdas);
list_init(&pvs);
/* Ensure any residual PE structure is gone */
pv->pe_size = pv->pe_count = 0;
@@ -488,10 +418,10 @@ static int _pv_write(struct format_instance *fid, struct physical_volume *pv,
dev_write in order to make other disk tools happy */
dl->pvd.pv_on_disk.base = METADATA_BASE;
dl->pvd.pv_on_disk.size = PV_SIZE;
dl->pvd.pe_on_disk.base = PE_ALIGN * SECTOR_SIZE;
dl->pvd.pe_on_disk.base = PE_ALIGN << SECTOR_SHIFT;
list_add(&pvs, &dl->list);
if (!write_disks(fid->fmt, &pvs)) {
if (!write_disks(fmt, &pvs)) {
stack;
goto bad;
}
@@ -514,22 +444,20 @@ int _vg_setup(struct format_instance *fid, struct volume_group *vg)
vg->max_pv = MAX_PV - 1;
if (vg->extent_size > MAX_PE_SIZE || vg->extent_size < MIN_PE_SIZE) {
char *dummy, *dummy2;
log_error("Extent size must be between %s and %s",
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)),
(dummy2 = display_size(MAX_PE_SIZE / 2, SIZE_SHORT)));
display_size(fid->fmt->cmd, MIN_PE_SIZE / 2,
SIZE_SHORT), display_size(fid->fmt->cmd,
MAX_PE_SIZE /
2,
SIZE_SHORT));
dbg_free(dummy);
dbg_free(dummy2);
return 0;
}
if (vg->extent_size % MIN_PE_SIZE) {
char *dummy;
log_error("Extent size must be multiple of %s",
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)));
dbg_free(dummy);
display_size(fid->fmt->cmd, MIN_PE_SIZE / 2,
SIZE_SHORT));
return 0;
}
@@ -542,6 +470,11 @@ int _vg_setup(struct format_instance *fid, struct volume_group *vg)
return 1;
}
static struct metadata_area_ops _metadata_format1_ops = {
vg_read:_vg_read,
vg_write:_vg_write,
};
struct format_instance *_create_instance(struct format_type *fmt,
const char *vgname, void *private)
{
@@ -563,6 +496,7 @@ struct format_instance *_create_instance(struct format_type *fmt,
return NULL;
}
mda->ops = &_metadata_format1_ops;
mda->metadata_locn = NULL;
list_add(&fid->metadata_areas, &mda->list);
@@ -580,21 +514,21 @@ void _destroy(struct format_type *fmt)
}
static struct format_handler _format1_ops = {
get_vgs: _get_vgs,
get_pvs: _get_pvs,
pv_read: _pv_read,
pv_setup: _pv_setup,
pv_write: _pv_write,
lv_setup: _lv_setup,
vg_read: _vg_read,
vg_setup: _vg_setup,
vg_write: _vg_write,
pv_read:_pv_read,
pv_setup:_pv_setup,
pv_write:_pv_write,
lv_setup:_lv_setup,
vg_setup:_vg_setup,
create_instance:_create_instance,
destroy_instance:_destroy_instance,
destroy: _destroy,
destroy:_destroy,
};
struct format_type *create_lvm1_format(struct cmd_context *cmd)
#ifdef LVM1_INTERNAL
struct format_type *init_lvm1_format(struct cmd_context *cmd)
#else /* Shared */
struct format_type *init_format(struct cmd_context *cmd)
#endif
{
struct format_type *fmt = dbg_malloc(sizeof(*fmt));
@@ -606,8 +540,19 @@ struct format_type *create_lvm1_format(struct cmd_context *cmd)
fmt->cmd = cmd;
fmt->ops = &_format1_ops;
fmt->name = FMT_LVM1_NAME;
fmt->alias = NULL;
fmt->features = 0;
fmt->private = NULL;
if (!(fmt->labeller = lvm1_labeller_create(fmt))) {
log_error("Couldn't create lvm1 label handler.");
return NULL;
}
if (!(label_register_handler(FMT_LVM1_NAME, fmt->labeller))) {
log_error("Couldn't register lvm1 label handler.");
return NULL;
}
return fmt;
}

View File

@@ -9,6 +9,10 @@
#include "metadata.h"
struct format_type *create_lvm1_format(struct cmd_context *cmd);
#define FMT_LVM1_NAME "lvm1"
#ifdef LVM1_INTERNAL
struct format_type *init_lvm1_format(struct cmd_context *cmd);
#endif
#endif

View File

@@ -6,12 +6,11 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "disk-rep.h"
#include "dbg_malloc.h"
#include "pool.h"
#include "hash.h"
#include "list.h"
#include "log.h"
#include "lvm-string.h"
#include <time.h>
@@ -57,9 +56,9 @@ int import_pv(struct pool *mem, struct device *dev,
if (vg &&
strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id)))
log_very_verbose("System ID %s on %s differs from %s for "
"volume group", pvd->system_id,
dev_name(pv->dev), vg->system_id);
log_very_verbose("System ID %s on %s differs from %s for "
"volume group", pvd->system_id,
dev_name(pv->dev), vg->system_id);
/*
* If exported, we still need to flag in pv->status too because
@@ -163,7 +162,7 @@ int export_pv(struct pool *mem, struct volume_group *vg,
if (vg &&
(!*vg->system_id ||
strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id))))
strncpy(vg->system_id, pvd->system_id, NAME_LEN);
strncpy(vg->system_id, pvd->system_id, NAME_LEN);
//pvd->pv_major = MAJOR(pv->dev);
@@ -172,7 +171,10 @@ int export_pv(struct pool *mem, struct volume_group *vg,
pvd->pv_size = pv->size;
pvd->lv_cur = 0; /* this is set when exporting the lv list */
pvd->pe_size = pv->pe_size;
if (vg)
pvd->pe_size = vg->extent_size;
else
pvd->pe_size = pv->pe_size;
pvd->pe_total = pv->pe_count;
pvd->pe_allocated = pv->pe_alloc_count;
pvd->pe_start = pv->pe_start;
@@ -278,6 +280,8 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
return 0;
}
lv->status |= VISIBLE_LV;
if (lvd->lv_status & LV_SPINDOWN)
lv->status |= SPINDOWN_LV;
@@ -296,13 +300,11 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
if (lvd->lv_badblock)
lv->status |= BADBLOCK_ON;
if (lvd->lv_allocation & LV_STRICT)
lv->status |= ALLOC_STRICT;
/* Drop the unused LV_STRICT here */
if (lvd->lv_allocation & LV_CONTIGUOUS)
lv->status |= ALLOC_CONTIGUOUS;
lv->alloc = ALLOC_CONTIGUOUS;
else
lv->status |= ALLOC_SIMPLE;
lv->alloc = ALLOC_NEXT_FREE;
lv->read_ahead = lvd->lv_read_ahead;
lv->size = lvd->lv_size;
@@ -313,15 +315,13 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
return 1;
}
void export_lv(struct lv_disk *lvd, struct volume_group *vg,
struct logical_volume *lv, const char *dev_dir)
static void _export_lv(struct lv_disk *lvd, struct volume_group *vg,
struct logical_volume *lv, const char *dev_dir)
{
memset(lvd, 0, sizeof(*lvd));
snprintf(lvd->lv_name, sizeof(lvd->lv_name), "%s%s/%s",
dev_dir, vg->name, lv->name);
/* FIXME: Add 'if' test */
_check_vg_name(vg->name);
strcpy(lvd->vg_name, vg->name);
if (lv->status & LVM_READ)
@@ -339,10 +339,9 @@ void export_lv(struct lv_disk *lvd, struct volume_group *vg,
}
lvd->lv_read_ahead = lv->read_ahead;
lvd->lv_stripes = list_item(lv->segments.n,
struct stripe_segment)->stripes;
lvd->lv_stripes = list_item(lv->segments.n, struct lv_segment)->stripes;
lvd->lv_stripesize = list_item(lv->segments.n,
struct stripe_segment)->stripe_size;
struct lv_segment)->stripe_size;
lvd->lv_size = lv->size;
lvd->lv_allocated_le = lv->le_count;
@@ -350,10 +349,7 @@ void export_lv(struct lv_disk *lvd, struct volume_group *vg,
if (lv->status & BADBLOCK_ON)
lvd->lv_badblock = LV_BADBLOCK_ON;
if (lv->status & ALLOC_STRICT)
lvd->lv_allocation |= LV_STRICT;
if (lv->status & ALLOC_CONTIGUOUS)
if (lv->alloc == ALLOC_CONTIGUOUS)
lvd->lv_allocation |= LV_CONTIGUOUS;
}
@@ -362,11 +358,11 @@ int export_extents(struct disk_list *dl, int lv_num,
{
struct list *segh;
struct pe_disk *ped;
struct stripe_segment *seg;
struct lv_segment *seg;
uint32_t pe, s;
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment);
seg = list_item(segh, struct lv_segment);
for (s = 0; s < seg->stripes; s++) {
if (seg->area[s].pv != pv)
@@ -384,7 +380,7 @@ int export_extents(struct disk_list *dl, int lv_num,
return 1;
}
int import_pvs(struct format_instance *fid, struct pool *mem,
int import_pvs(struct format_type *fmt, struct pool *mem,
struct volume_group *vg,
struct list *pvds, struct list *results, int *count)
{
@@ -408,7 +404,7 @@ int import_pvs(struct format_instance *fid, struct pool *mem,
return 0;
}
pvl->pv->fid = fid;
pvl->pv->fmt = fmt;
list_add(results, &pvl->list);
(*count)++;
}
@@ -477,6 +473,11 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
int lv_num, len;
struct hash_table *lvd_hash;
if (!_check_vg_name(vg->name)) {
stack;
return 0;
}
if (!(lvd_hash = hash_create(32))) {
stack;
return 0;
@@ -499,7 +500,7 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
goto out;
}
export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
_export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
lv_num = lvnum_from_lvid(&ll->lv->lvid);
@@ -616,7 +617,8 @@ int import_snapshots(struct pool *mem, struct volume_group *vg,
continue;
/* insert the snapshot */
if (!vg_add_snapshot(org, cow, 1, lvd->lv_chunk_size)) {
if (!vg_add_snapshot(org, cow, 1, NULL,
lvd->lv_chunk_size)) {
log_err("Couldn't add snapshot.");
return 0;
}

View File

@@ -4,10 +4,9 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "metadata.h"
#include "hash.h"
#include "dbg_malloc.h"
#include "log.h"
#include "pool.h"
#include "disk-rep.h"
@@ -192,9 +191,9 @@ static int _check_maps_are_complete(struct hash_table *maps)
return 1;
}
static struct stripe_segment *_alloc_seg(struct pool *mem, uint32_t stripes)
static struct lv_segment *_alloc_seg(struct pool *mem, uint32_t stripes)
{
struct stripe_segment *seg;
struct lv_segment *seg;
uint32_t len = sizeof(*seg) + (stripes * sizeof(seg->area[0]));
if (!(seg = pool_zalloc(mem, len))) {
@@ -208,12 +207,13 @@ static struct stripe_segment *_alloc_seg(struct pool *mem, uint32_t stripes)
static int _read_linear(struct pool *mem, struct lv_map *lvm)
{
uint32_t le = 0;
struct stripe_segment *seg;
struct lv_segment *seg;
while (le < lvm->lv->le_count) {
seg = _alloc_seg(mem, 1);
seg->lv = lvm->lv;
seg->type = SEG_STRIPED;
seg->le = le;
seg->len = 0;
seg->stripe_size = 0;
@@ -226,7 +226,8 @@ static int _read_linear(struct pool *mem, struct lv_map *lvm)
seg->len++;
while ((lvm->map[le + seg->len].pv == seg->area[0].pv) &&
(lvm->map[le + seg->len].pe == seg->area[0].pe +
(seg->area[0].pv &&
lvm->map[le + seg->len].pe == seg->area[0].pe +
seg->len));
le += seg->len;
@@ -237,7 +238,7 @@ static int _read_linear(struct pool *mem, struct lv_map *lvm)
return 1;
}
static int _check_stripe(struct lv_map *lvm, struct stripe_segment *seg,
static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg,
uint32_t base_le, uint32_t len)
{
uint32_t le, st;
@@ -249,7 +250,8 @@ static int _check_stripe(struct lv_map *lvm, struct stripe_segment *seg,
*/
for (st = 0; st < seg->stripes; st++)
if ((lvm->map[le + st * len].pv != seg->area[st].pv) ||
(lvm->map[le + st * len].pe != seg->area[st].pe + seg->len))
(seg->area[st].pv &&
lvm->map[le + st * len].pe != seg->area[st].pe + seg->len))
return 0;
return 1;
@@ -258,7 +260,7 @@ static int _check_stripe(struct lv_map *lvm, struct stripe_segment *seg,
static int _read_stripes(struct pool *mem, struct lv_map *lvm)
{
uint32_t st, le = 0, len;
struct stripe_segment *seg;
struct lv_segment *seg;
/*
* Work out overall striped length
@@ -277,6 +279,7 @@ static int _read_stripes(struct pool *mem, struct lv_map *lvm)
}
seg->lv = lvm->lv;
seg->type = SEG_STRIPED;
seg->stripe_size = lvm->stripe_size;
seg->stripes = lvm->stripes;
seg->le = seg->stripes * le;

View File

@@ -4,9 +4,8 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "disk-rep.h"
#include "log.h"
#include "dbg_malloc.h"
/*
* Only works with powers of 2.
@@ -36,7 +35,7 @@ static uint32_t _next_base(struct data_area *area)
*/
static int _adjust_pe_on_disk(struct pv_disk *pvd)
{
uint32_t pe_start = pvd->pe_start * SECTOR_SIZE;
uint32_t pe_start = pvd->pe_start << SECTOR_SHIFT;
if (pe_start < pvd->pe_on_disk.base + pvd->pe_on_disk.size)
return 0;
@@ -103,11 +102,10 @@ int calculate_layout(struct disk_list *dl)
}
/*
* It may seem strange to have a struct physical_volume in here,
* but the number of extents that can fit on a disk *is* metadata
* format dependant.
* The number of extents that can fit on a disk is metadata format dependant.
*/
int calculate_extent_count(struct physical_volume *pv)
int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size,
uint32_t max_extent_count)
{
struct pv_disk *pvd = dbg_malloc(sizeof(*pvd));
uint32_t end;
@@ -122,10 +120,13 @@ int calculate_extent_count(struct physical_volume *pv)
* one is going to be knocked off at the start of the
* next loop.
*/
pvd->pe_total = (pv->size / pv->pe_size);
if (max_extent_count)
pvd->pe_total = max_extent_count + 1;
else
pvd->pe_total = (pv->size / extent_size);
if (pvd->pe_total < PE_SIZE_PV_SIZE_REL) {
log_error("Insufficient space for extents on %s",
log_error("Too few extents on %s. Try smaller extent size.",
dev_name(pv->dev));
dbg_free(pvd);
return 0;
@@ -135,11 +136,12 @@ int calculate_extent_count(struct physical_volume *pv)
pvd->pe_total--;
_calc_simple_layout(pvd);
end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size +
SECTOR_SIZE - 1) / SECTOR_SIZE);
SECTOR_SIZE - 1) >> SECTOR_SHIFT);
pvd->pe_start = _round_up(end, PE_ALIGN);
} while ((pvd->pe_start + (pvd->pe_total * pv->pe_size)) > pv->size);
} while ((pvd->pe_start + (pvd->pe_total * extent_size))
> pv->size);
if (pvd->pe_total > MAX_PE_TOTAL) {
log_error("Metadata extent limit (%u) exceeded for %s - "
@@ -151,6 +153,7 @@ int calculate_extent_count(struct physical_volume *pv)
pv->pe_count = pvd->pe_total;
pv->pe_start = pvd->pe_start;
/* We can't set pe_size here without breaking LVM1 compatibility */
dbg_free(pvd);
return 1;
}

106
lib/format1/lvm1-label.c Normal file
View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#include "lib.h"
#include "lvm1-label.h"
#include "disk-rep.h"
#include "label.h"
#include "metadata.h"
#include "xlate.h"
#include "cache.h"
#include <sys/stat.h>
#include <fcntl.h>
static void _not_supported(const char *op)
{
log_err("The '%s' operation is not supported for the lvm1 labeller.",
op);
}
static int _can_handle(struct labeller *l, char *buf, uint64_t sector)
{
struct pv_disk *pvd = (struct pv_disk *) buf;
uint32_t version;
/* LVM1 label must always be in first sector */
if (sector)
return 0;
version = xlate16(pvd->version);
if (pvd->id[0] == 'H' && pvd->id[1] == 'M' &&
(version == 1 || version == 2))
return 1;
return 0;
}
static int _write(struct label *label, char *buf)
{
_not_supported("write");
return 0;
}
static int _read(struct labeller *l, struct device *dev, char *buf,
struct label **label)
{
struct pv_disk *pvd = (struct pv_disk *) buf;
struct cache_info *info;
if (!(info = cache_add(l, pvd->pv_uuid, dev, pvd->vg_name, NULL)))
return 0;
*label = info->label;
info->device_size = xlate32(pvd->pv_size) << SECTOR_SHIFT;
list_init(&info->mdas);
info->status &= ~CACHE_INVALID;
return 1;
}
static int _initialise_label(struct labeller *l, struct label *label)
{
strcpy(label->type, "LVM1");
return 1;
}
static void _destroy_label(struct labeller *l, struct label *label)
{
return;
}
static void _destroy(struct labeller *l)
{
dbg_free(l);
}
struct label_ops _lvm1_ops = {
can_handle:_can_handle,
write:_write,
read:_read,
verify:_can_handle,
initialise_label:_initialise_label,
destroy_label:_destroy_label,
destroy:_destroy
};
struct labeller *lvm1_labeller_create(struct format_type *fmt)
{
struct labeller *l;
if (!(l = dbg_malloc(sizeof(*l)))) {
log_err("Couldn't allocate labeller object.");
return NULL;
}
l->ops = &_lvm1_ops;
l->private = (void *) fmt;
return l;
}

14
lib/format1/lvm1-label.h Normal file
View File

@@ -0,0 +1,14 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#ifndef _LVM_LVM1_LABEL_H
#define _LVM_LVM1_LABEL_H
#include "metadata.h"
struct labeller *lvm1_labeller_create(struct format_type *fmt);
#endif

View File

@@ -1,143 +0,0 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#include "lvm1_label.h"
#include "dbg_malloc.h"
#include "disk-rep.h"
#include "log.h"
#include "label.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
static void _not_supported(const char *op)
{
log_err("The '%s' operation is not supported for the lvm1 labeller.",
op);
}
static int _can_handle(struct labeller *l, struct device *dev)
{
struct pv_disk pvd;
int r;
if (!dev_open(dev, O_RDONLY)) {
stack;
return 0;
}
r = read_pvd(dev, &pvd);
if (!dev_close(dev))
stack;
return r;
}
static int _write(struct labeller *l, struct device *dev, struct label *label)
{
_not_supported("write");
return 0;
}
static int _remove(struct labeller *l, struct device *dev)
{
_not_supported("remove");
return 0;
}
static struct label *_to_label(struct pv_disk *pvd)
{
struct label *l;
struct lvm_label_info *info;
if (!(l = dbg_malloc(sizeof(*l)))) {
log_err("Couldn't allocate label.");
return NULL;
}
if (!(info = (struct lvm_label_info *) dbg_strdup(pvd->vg_name))) {
dbg_free(l);
return NULL;
}
memcpy(&l->id, &pvd->pv_uuid, sizeof(l->id));
strcpy(l->volume_type, "lvm");
l->version[0] = 1;
l->version[0] = 0;
l->version[0] = 0;
l->extra_info = info;
return l;
}
static int _read(struct labeller *l, struct device *dev, struct label **label)
{
struct pv_disk pvd;
int r = 0;
if (!dev_open(dev, O_RDONLY)) {
stack;
return 0;
}
r = read_pvd(dev, &pvd);
if (!dev_close(dev))
stack;
if (!r) {
stack;
return 0;
}
/*
* Convert the disk_list into a label structure.
*/
if (!(*label = _to_label(&pvd))) {
stack;
return 0;
}
return 1;
}
static void _destroy_label(struct labeller *l, struct label *label)
{
dbg_free(label->extra_info);
dbg_free(label);
}
static void _destroy(struct labeller *l)
{
dbg_free(l);
}
struct label_ops _lvm1_ops = {
can_handle: _can_handle,
write: _write,
remove: _remove,
read: _read,
verify: _can_handle,
destroy_label: _destroy_label,
destroy: _destroy
};
struct labeller *lvm1_labeller_create(void)
{
struct labeller *l;
if (!(l = dbg_malloc(sizeof(*l)))) {
log_err("Couldn't allocate labeller object.");
return NULL;
}
l->ops = &_lvm1_ops;
l->private = NULL;
return l;
}

View File

@@ -1,21 +0,0 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#ifndef _LVM_LVM1_LABEL_H
#define _LVM_LVM1_LABEL_H
/*
* This is what the 'extra_info' field of the label will point to
* if the label type is lvm1.
*/
struct lvm_label_info {
char volume_group[0];
};
struct labeller *lvm1_labeller_create(void);
#endif

View File

@@ -4,7 +4,7 @@
* This file is released under the LGPL.
*/
#include "log.h"
#include "lib.h"
#include "pool.h"
#include "disk-rep.h"

View File

@@ -4,9 +4,9 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "format-text.h"
#include "log.h"
#include "pool.h"
#include "config.h"
#include "hash.h"
@@ -17,7 +17,6 @@
#include <dirent.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>
@@ -52,7 +51,7 @@ struct archive_file {
* Extract vg name and version number from a filename.
*/
static int _split_vg(const char *filename, char *vg, size_t vg_size,
uint32_t * index)
uint32_t *index)
{
int len, vg_len;
char *dot, *underscore;
@@ -202,7 +201,7 @@ static void _remove_expired(struct list *archives, uint32_t archives_size,
return;
/* Convert retain_days into the time after which we must retain */
retain_time = time(NULL) - (time_t) retain_days * SECS_PER_DAY;
retain_time = time(NULL) - (time_t) retain_days *SECS_PER_DAY;
/* Assume list is ordered oldest first (by index) */
list_iterate(bh, archives) {
@@ -252,7 +251,7 @@ int archive_vg(struct volume_group *vg,
return 0;
}
if (!text_vg_export(fp, vg, desc)) {
if (!text_vg_export_file(vg, desc, fp)) {
stack;
fclose(fp);
return 0;
@@ -297,8 +296,7 @@ int archive_vg(struct volume_group *vg,
return 1;
}
static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
struct archive_file *af)
static void _display_archive(struct cmd_context *cmd, struct archive_file *af)
{
struct volume_group *vg = NULL;
struct format_instance *tf;
@@ -308,8 +306,9 @@ static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
log_print("path:\t\t%s", af->path);
if (!(context = create_text_context(cmd->fmtt, af->path, NULL)) ||
!(tf = cmd->fmtt->ops->create_instance(cmd->fmtt, NULL, context))) {
if (!(context = create_text_context(cmd, af->path, NULL)) ||
!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
context))) {
log_error("Couldn't create text instance object.");
return;
}
@@ -319,7 +318,7 @@ static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
* retrieve the archive time and description.
*/
/* FIXME Use variation on _vg_read */
if (!(vg = text_vg_import(tf, af->path, um, &when, &desc))) {
if (!(vg = text_vg_import_file(tf, af->path, &when, &desc))) {
log_print("Unable to read archive file.");
tf->fmt->ops->destroy_instance(tf);
return;
@@ -332,8 +331,7 @@ static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
tf->fmt->ops->destroy_instance(tf);
}
int archive_list(struct cmd_context *cmd, struct uuid_map *um,
const char *dir, const char *vg)
int archive_list(struct cmd_context *cmd, const char *dir, const char *vg)
{
struct list *archives, *ah;
struct archive_file *af;
@@ -349,7 +347,7 @@ int archive_list(struct cmd_context *cmd, struct uuid_map *um,
list_iterate(ah, archives) {
af = list_item(ah, struct archive_file);
_display_archive(cmd, um, af);
_display_archive(cmd, af);
log_print(" ");
}

View File

@@ -4,18 +4,22 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "import-export.h"
#include "metadata.h"
#include "log.h"
#include "hash.h"
#include "pool.h"
#include "dbg_malloc.h"
#include "display.h"
#include "lvm-string.h"
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#include <sys/utsname.h>
struct formatter;
typedef int (*out_with_comment_fn) (struct formatter * f, const char *comment,
const char *fmt, va_list ap);
typedef void (*nl_fn) (struct formatter * f);
/*
* The first half of this file deals with
* exporting the vg, ie. writing it to a file.
@@ -24,22 +28,50 @@ struct formatter {
struct pool *mem; /* pv names allocated from here */
struct hash_table *pv_names; /* dev_name -> pv_name (eg, pv1) */
FILE *fp; /* where we're writing to */
int indent; /* current level of indentation */
union {
FILE *fp; /* where we're writing to */
struct {
char *buf;
uint32_t size;
uint32_t used;
} buf;
} data;
out_with_comment_fn out_with_comment;
nl_fn nl;
int indent; /* current level of indentation */
int error;
int header; /* 1 => comments at start; 0 => end */
};
static struct utsname _utsname;
static void _init(void)
{
static int _initialised = 0;
if (_initialised)
return;
if (uname(&_utsname)) {
log_error("uname failed: %s", strerror(errno));
memset(&_utsname, 0, sizeof(_utsname));
}
_initialised = 1;
}
/*
* Formatting functions.
*/
static void _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
__attribute__ ((format(printf, 3, 4)));
static void _out_hint(struct formatter *f, const char *fmt, ...)
static int _out_hint(struct formatter *f, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
static void _out(struct formatter *f, const char *fmt, ...)
static int _out(struct formatter *f, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
#define MAX_INDENT 5
@@ -60,26 +92,39 @@ static void _dec_indent(struct formatter *f)
/*
* Newline function for prettier layout.
*/
static void _nl(struct formatter *f)
static void _nl_file(struct formatter *f)
{
fprintf(f->fp, "\n");
fprintf(f->data.fp, "\n");
}
static void _nl_raw(struct formatter *f)
{
if (f->data.buf.used >= f->data.buf.size - 1)
return;
*f->data.buf.buf = '\n';
f->data.buf.buf += 1;
f->data.buf.used += 1;
*f->data.buf.buf = '\0';
return;
}
#define COMMENT_TAB 6
static void _out_with_comment(struct formatter *f, const char *comment,
const char *fmt, va_list ap)
static int _out_with_comment_file(struct formatter *f, const char *comment,
const char *fmt, va_list ap)
{
int i;
char white_space[MAX_INDENT + 1];
if (ferror(f->fp))
return;
if (ferror(f->data.fp))
return 0;
for (i = 0; i < f->indent; i++)
white_space[i] = '\t';
white_space[i] = '\0';
fprintf(f->fp, white_space);
i = vfprintf(f->fp, fmt, ap);
fprintf(f->data.fp, white_space);
i = vfprintf(f->data.fp, fmt, ap);
if (comment) {
/*
@@ -90,13 +135,34 @@ static void _out_with_comment(struct formatter *f, const char *comment,
i++;
do
fputc('\t', f->fp);
fputc('\t', f->data.fp);
while (++i < COMMENT_TAB);
fprintf(f->fp, comment);
fprintf(f->data.fp, comment);
}
fputc('\n', f->fp);
fputc('\n', f->data.fp);
return 1;
}
static int _out_with_comment_raw(struct formatter *f, const char *comment,
const char *fmt, va_list ap)
{
int n;
n = vsnprintf(f->data.buf.buf, f->data.buf.size - f->data.buf.used,
fmt, ap);
if (n < 0 || (n > f->data.buf.size - f->data.buf.used - 1))
return 0;
f->data.buf.buf += n;
f->data.buf.used += n;
f->nl(f);
return 1;
}
/*
@@ -111,7 +177,7 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
"Kilobytes",
"Megabytes",
"Gigabytes",
"Terrabytes",
"Terabytes",
NULL
};
@@ -131,43 +197,55 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
* Appends a comment giving a size in more easily
* readable form (eg, 4M instead of 8096).
*/
static void _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
{
char buffer[64];
va_list ap;
int r;
_sectors_to_units(size, buffer, sizeof(buffer));
if (!_sectors_to_units(size, buffer, sizeof(buffer)))
return 0;
va_start(ap, fmt);
_out_with_comment(f, buffer, fmt, ap);
r = f->out_with_comment(f, buffer, fmt, ap);
va_end(ap);
return r;
}
/*
* Appends a comment indicating that the line is
* only a hint.
*/
static void _out_hint(struct formatter *f, const char *fmt, ...)
static int _out_hint(struct formatter *f, const char *fmt, ...)
{
va_list ap;
int r;
va_start(ap, fmt);
_out_with_comment(f, "# Hint only", fmt, ap);
r = f->out_with_comment(f, "# Hint only", fmt, ap);
va_end(ap);
return r;
}
/*
* The normal output function.
*/
static void _out(struct formatter *f, const char *fmt, ...)
static int _out(struct formatter *f, const char *fmt, ...)
{
va_list ap;
int r;
va_start(ap, fmt);
_out_with_comment(f, NULL, fmt, ap);
r = f->out_with_comment(f, NULL, fmt, ap);
va_end(ap);
return r;
}
#define _outf(args...) do {if (!_out(args)) {stack; return 0;}} while (0)
static int _print_header(struct formatter *f,
struct volume_group *vg, const char *desc)
{
@@ -175,12 +253,17 @@ static int _print_header(struct formatter *f,
t = time(NULL);
_out(f,
"# This file was originally generated by the LVM2 library\n"
"# Generated: %s\n", ctime(&t));
_outf(f, "# Generated by LVM2: %s", ctime(&t));
_outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
_outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE);
f->nl(f);
_out(f, "description = \"%s\"", desc);
_out(f, "creation_time = %lu\n", t);
_outf(f, "description = \"%s\"", desc);
f->nl(f);
_outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
_utsname.sysname, _utsname.nodename, _utsname.release,
_utsname.version, _utsname.machine);
_outf(f, "creation_time = %lu\t# %s", t, ctime(&t));
return 1;
}
@@ -194,20 +277,23 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
return 0;
}
_out(f, "id = \"%s\"", buffer);
_outf(f, "id = \"%s\"", buffer);
_out(f, "seqno = %u", vg->seqno);
_outf(f, "seqno = %u", vg->seqno);
if (!print_flags(vg->status, VG_FLAGS, buffer, sizeof(buffer))) {
stack;
return 0;
}
_out(f, "status = %s", buffer);
_outf(f, "status = %s", buffer);
if (vg->system_id && *vg->system_id)
_out(f, "system_id = \"%s\"", vg->system_id);
_out_size(f, vg->extent_size, "extent_size = %u", vg->extent_size);
_out(f, "max_lv = %u", vg->max_lv);
_out(f, "max_pv = %u", vg->max_pv);
_outf(f, "system_id = \"%s\"", vg->system_id);
if (!_out_size(f, vg->extent_size, "extent_size = %u", vg->extent_size)) {
stack;
return 0;
}
_outf(f, "max_lv = %u", vg->max_lv);
_outf(f, "max_pv = %u", vg->max_pv);
return 1;
}
@@ -230,7 +316,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
char buffer[256];
const char *name;
_out(f, "physical_volumes {");
_outf(f, "physical_volumes {");
_inc_indent(f);
list_iterate(pvh, &vg->pvs) {
@@ -242,8 +328,8 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
return 0;
}
_nl(f);
_out(f, "%s {", name);
f->nl(f);
_outf(f, "%s {", name);
_inc_indent(f);
if (!id_write_format(&pv->id, buffer, sizeof(buffer))) {
@@ -251,65 +337,93 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
return 0;
}
_out(f, "id = \"%s\"", buffer);
_out_hint(f, "device = \"%s\"", dev_name(pv->dev));
_nl(f);
_outf(f, "id = \"%s\"", buffer);
if (!_out_hint(f, "device = \"%s\"", dev_name(pv->dev))) {
stack;
return 0;
}
f->nl(f);
if (!print_flags(pv->status, PV_FLAGS, buffer, sizeof(buffer))) {
stack;
return 0;
}
_out(f, "status = %s", buffer);
_out(f, "pe_start = %llu", pv->pe_start);
_out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
"pe_count = %u", pv->pe_count);
_dec_indent(f);
_out(f, "}");
}
_dec_indent(f);
_out(f, "}");
return 1;
}
static int _print_segment(struct formatter *f, struct volume_group *vg,
int count, struct stripe_segment *seg)
{
int s;
const char *name;
_out(f, "segment%u {", count);
_inc_indent(f);
_out(f, "start_extent = %u", seg->le);
_out_size(f, seg->len * vg->extent_size, "extent_count = %u", seg->len);
_out(f, "stripes = %u", seg->stripes);
if (seg->stripes > 1)
_out_size(f, seg->stripe_size,
"stripe_size = %u", seg->stripe_size);
_nl(f);
_out(f, "areas = [");
_inc_indent(f);
for (s = 0; s < seg->stripes; s++) {
if (!(name = _get_pv_name(f, seg->area[s].pv))) {
_outf(f, "status = %s", buffer);
_outf(f, "pe_start = %" PRIu64, pv->pe_start);
if (!_out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
"pe_count = %u", pv->pe_count)) {
stack;
return 0;
}
_out(f, "\"%s\", %u%s", name, seg->area[s].pe,
(s == seg->stripes - 1) ? "" : ",");
_dec_indent(f);
_outf(f, "}");
}
_dec_indent(f);
_out(f, "]");
_outf(f, "}");
return 1;
}
static int _print_segment(struct formatter *f, struct volume_group *vg,
int count, struct lv_segment *seg)
{
int s;
const char *name;
_outf(f, "segment%u {", count);
_inc_indent(f);
_outf(f, "start_extent = %u", seg->le);
if (!_out_size(f, seg->len * vg->extent_size, "extent_count = %u",
seg->len)) {
stack;
return 0;
}
f->nl(f);
_outf(f, "type = \"%s\"", get_segtype_string(seg->type));
switch (seg->type) {
case SEG_STRIPED:
_outf(f, "stripe_count = %u%s", seg->stripes,
(seg->stripes == 1) ? "\t# linear" : "");
if (seg->stripes > 1)
_out_size(f, seg->stripe_size,
"stripe_size = %u", seg->stripe_size);
f->nl(f);
_outf(f, "stripes = [");
_inc_indent(f);
for (s = 0; s < seg->stripes; s++) {
if (!(name = _get_pv_name(f, seg->area[s].pv))) {
stack;
return 0;
}
_outf(f, "\"%s\", %u%s", name, seg->area[s].pe,
(s == seg->stripes - 1) ? "" : ",");
}
_dec_indent(f);
_outf(f, "]");
break;
case SEG_SNAPSHOT:
_outf(f, "chunk_size = %u", seg->chunk_size);
_outf(f, "origin = \"%s\"", seg->origin->name);
_outf(f, "cow_store = \"%s\"", seg->cow->name);
break;
case SEG_MIRROR:
/* mirrors = [ "lvol1", 10, ... ] */
;
}
_dec_indent(f);
_out(f, "}");
_outf(f, "}");
return 1;
}
@@ -325,83 +439,48 @@ static int _count_segments(struct logical_volume *lv)
return r;
}
static int _print_lvs(struct formatter *f, struct volume_group *vg)
static int _print_snapshot(struct formatter *f, struct snapshot *snap,
unsigned int count)
{
struct list *lvh, *segh;
struct logical_volume *lv;
struct stripe_segment *seg;
char buffer[256];
int seg_count;
struct lv_segment seg;
/*
* Don't bother with an lv section if there are no lvs.
*/
if (list_empty(&vg->lvs))
return 1;
f->nl(f);
_out(f, "logical_volumes {");
_outf(f, "snapshot%u {", count);
_inc_indent(f);
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if (!id_write_format(&snap->id, buffer, sizeof(buffer))) {
stack;
return 0;
}
_nl(f);
_out(f, "%s {", lv->name);
_inc_indent(f);
_outf(f, "id = \"%s\"", buffer);
if (!print_flags(LVM_READ | LVM_WRITE | VISIBLE_LV, LV_FLAGS,
buffer, sizeof(buffer))) {
stack;
return 0;
}
/* FIXME: Write full lvid */
if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) {
stack;
return 0;
}
_outf(f, "status = %s", buffer);
_outf(f, "segment_count = 1");
_out(f, "id = \"%s\"", buffer);
f->nl(f);
if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
stack;
return 0;
}
seg.type = SEG_SNAPSHOT;
seg.le = 0;
seg.len = snap->origin->le_count;
seg.origin = snap->origin;
seg.cow = snap->cow;
seg.chunk_size = snap->chunk_size;
_out(f, "status = %s", buffer);
_out(f, "read_ahead = %u", lv->read_ahead);
if (lv->minor >= 0)
_out(f, "minor = %d", lv->minor);
_out(f, "segment_count = %u", _count_segments(lv));
_nl(f);
seg_count = 1;
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment);
if (!_print_segment(f, vg, seg_count++, seg)) {
stack;
return 0;
}
}
_dec_indent(f);
_out(f, "}");
if (!_print_segment(f, snap->origin->vg, 1, &seg)) {
stack;
return 0;
}
_dec_indent(f);
_out(f, "}");
return 1;
}
static int _print_snapshot(struct formatter *f, struct snapshot *s,
unsigned int count)
{
_nl(f);
_out(f, "snapshot%u {", count);
_inc_indent(f);
_out(f, "chunk_size = %u", s->chunk_size);
_out(f, "origin = \"%s\"", s->origin->name);
_out(f, "cow_store = \"%s\"", s->cow->name);
_dec_indent(f);
_out(f, "}");
_outf(f, "}");
return 1;
}
@@ -412,16 +491,6 @@ static int _print_snapshots(struct formatter *f, struct volume_group *vg)
struct snapshot *s;
unsigned int count = 0;
/*
* Don't bother with a snapshot section if there are no
* snapshots.
*/
if (list_empty(&vg->snapshots))
return 1;
_out(f, "snapshots {");
_inc_indent(f);
list_iterate(sh, &vg->snapshots) {
s = list_item(sh, struct snapshot_list)->snapshot;
@@ -431,8 +500,78 @@ static int _print_snapshots(struct formatter *f, struct volume_group *vg)
}
}
return 1;
}
static int _print_lvs(struct formatter *f, struct volume_group *vg)
{
struct list *lvh, *segh;
struct logical_volume *lv;
struct lv_segment *seg;
char buffer[256];
int seg_count;
/*
* Don't bother with an lv section if there are no lvs.
*/
if (list_empty(&vg->lvs))
return 1;
_outf(f, "logical_volumes {");
_inc_indent(f);
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
f->nl(f);
_outf(f, "%s {", lv->name);
_inc_indent(f);
/* FIXME: Write full lvid */
if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) {
stack;
return 0;
}
_outf(f, "id = \"%s\"", buffer);
if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
stack;
return 0;
}
_outf(f, "status = %s", buffer);
if (lv->alloc != ALLOC_DEFAULT)
_outf(f, "allocation_policy = \"%s\"",
get_alloc_string(lv->alloc));
if (lv->read_ahead)
_outf(f, "read_ahead = %u", lv->read_ahead);
if (lv->minor >= 0)
_outf(f, "minor = %d", lv->minor);
_outf(f, "segment_count = %u", _count_segments(lv));
f->nl(f);
seg_count = 1;
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct lv_segment);
if (!_print_segment(f, vg, seg_count++, seg)) {
stack;
return 0;
}
}
_dec_indent(f);
_outf(f, "}");
}
if (!_print_snapshots(f, vg)) {
stack;
return 0;
}
_dec_indent(f);
_out(f, "}");
_outf(f, "}");
return 1;
}
@@ -490,19 +629,10 @@ static int _build_pv_names(struct formatter *f, struct volume_group *vg)
return 0;
}
int text_vg_export(FILE * fp, struct volume_group *vg, const char *desc)
static int _text_vg_export(struct formatter *f,
struct volume_group *vg, const char *desc)
{
int r = 0;
struct formatter *f;
if (!(f = dbg_malloc(sizeof(*f)))) {
stack;
return 0;
}
memset(f, 0, sizeof(*f));
f->fp = fp;
f->indent = 0;
if (!_build_pv_names(f, vg)) {
stack;
@@ -510,32 +640,34 @@ int text_vg_export(FILE * fp, struct volume_group *vg, const char *desc)
}
#define fail do {stack; goto out;} while(0)
if (!_print_header(f, vg, desc))
if (f->header && !_print_header(f, vg, desc))
fail;
if (!_out(f, "%s {", vg->name))
fail;
_out(f, "%s {", vg->name);
_inc_indent(f);
if (!_print_vg(f, vg))
fail;
_nl(f);
f->nl(f);
if (!_print_pvs(f, vg))
fail;
_nl(f);
f->nl(f);
if (!_print_lvs(f, vg))
fail;
_nl(f);
if (!_print_snapshots(f, vg))
_dec_indent(f);
if (!_out(f, "}"))
fail;
if (!f->header && !_print_header(f, vg, desc))
fail;
#undef fail
_dec_indent(f);
_out(f, "}");
r = !ferror(f->fp);
r = 1;
out:
if (f->mem)
@@ -544,6 +676,68 @@ int text_vg_export(FILE * fp, struct volume_group *vg, const char *desc)
if (f->pv_names)
hash_destroy(f->pv_names);
return r;
}
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp)
{
struct formatter *f;
int r;
_init();
if (!(f = dbg_malloc(sizeof(*f)))) {
stack;
return 0;
}
memset(f, 0, sizeof(*f));
f->data.fp = fp;
f->indent = 0;
f->header = 1;
f->out_with_comment = &_out_with_comment_file;
f->nl = &_nl_file;
r = _text_vg_export(f, vg, desc);
if (r)
r = !ferror(f->data.fp);
dbg_free(f);
return r;
}
/* Returns amount of buffer used incl. terminating NUL */
int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
uint32_t size)
{
struct formatter *f;
int r;
_init();
if (!(f = dbg_malloc(sizeof(*f)))) {
stack;
return 0;
}
memset(f, 0, sizeof(*f));
f->data.buf.buf = buf;
f->data.buf.size = size;
f->indent = 0;
f->header = 0;
f->out_with_comment = &_out_with_comment_raw;
f->nl = &_nl_raw;
if (!_text_vg_export(f, vg, desc)) {
stack;
r = 0;
goto out;
}
r = f->data.buf.used + 1;
out:
dbg_free(f);
return r;
}
#undef _outf

View File

@@ -4,7 +4,7 @@
* This file is released under the LGPL.
*/
#include "log.h"
#include "lib.h"
#include "metadata.h"
#include "import-export.h"
#include "lvm-string.h"
@@ -38,10 +38,8 @@ static struct flag _pv_flags[] = {
static struct flag _lv_flags[] = {
{LVM_READ, "READ"},
{LVM_WRITE, "WRITE"},
{ALLOC_SIMPLE, "ALLOC_SIMPLE"},
{ALLOC_STRICT, "ALLOC_STRICT"},
{ALLOC_CONTIGUOUS, "ALLOC_CONTIGUOUS"},
{FIXED_MINOR, "FIXED_MINOR"},
{VISIBLE_LV, "VISIBLE"},
{0, NULL}
};
@@ -62,7 +60,7 @@ static struct flag *_get_flags(int type)
return NULL;
}
static int _emit(char **buffer, size_t * size, const char *fmt, ...)
static int _emit(char **buffer, size_t *size, const char *fmt, ...)
{
size_t n;
va_list ap;
@@ -124,7 +122,7 @@ int print_flags(uint32_t status, int type, char *buffer, size_t size)
return 1;
}
int read_flags(uint32_t * status, int type, struct config_value *cv)
int read_flags(uint32_t *status, int type, struct config_value *cv)
{
int f;
uint32_t s = 0;
@@ -135,6 +133,9 @@ int read_flags(uint32_t * status, int type, struct config_value *cv)
return 0;
}
if (cv->type == CFG_EMPTY_ARRAY)
goto out;
while (cv) {
if (cv->type != CFG_STRING) {
log_err("Status value is not a string.");
@@ -155,6 +156,7 @@ int read_flags(uint32_t * status, int type, struct config_value *cv)
cv = cv->next;
}
out:
*status = s;
return 1;
}

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,10 @@
#include "lvm-types.h"
#include "metadata.h"
#include "uuid-map.h"
#include "pool.h"
#define FMT_TEXT_NAME "lvm2"
#define FMT_TEXT_ALIAS "text"
/*
* Archives a vg config. 'retain_days' is the minimum number of
@@ -19,21 +22,33 @@
*/
int archive_vg(struct volume_group *vg,
const char *dir,
const char *desc,
uint32_t retain_days,
uint32_t min_archive);
const char *desc, uint32_t retain_days, uint32_t min_archive);
/*
* Displays a list of vg backups in a particular archive directory.
*/
int archive_list(struct cmd_context *cmd, struct uuid_map *um,
const char *dir, const char *vg);
int archive_list(struct cmd_context *cmd, const char *dir, const char *vg);
/*
* The text format can read and write a volume_group to a file.
*/
struct format_type *create_text_format(struct cmd_context *cmd);
void *create_text_context(struct format_type *fmt, const char *path,
void *create_text_context(struct cmd_context *cmd, const char *path,
const char *desc);
struct labeller *text_labeller_create(struct format_type *fmt);
int pvhdr_read(struct device *dev, char *buf);
int add_da(struct format_type *fmt, struct pool *mem, struct list *das,
uint64_t start, uint64_t size);
void del_das(struct list *das);
int add_mda(struct format_type *fmt, struct pool *mem, struct list *mdas,
struct device *dev, uint64_t start, uint64_t size);
void del_mdas(struct list *mdas);
int vgname_from_mda(struct format_type *fmt, struct device_area *dev_area,
char *buf, uint32_t size);
#endif

View File

@@ -10,24 +10,55 @@
#include "config.h"
#include "lvm-types.h"
#include "metadata.h"
#include "uuid-map.h"
#include "pool.h"
#include <stdio.h>
/*
* Constants to identify files this code can parse.
*/
#define CONTENTS_FIELD "contents"
#define CONTENTS_VALUE "Text Format Volume Group"
#define FORMAT_VERSION_FIELD "version"
#define FORMAT_VERSION_VALUE 1
/*
* VGs, PVs and LVs all have status bitsets, we gather together
* common code for reading and writing them.
*/
enum {
VG_FLAGS,
PV_FLAGS,
LV_FLAGS
};
struct text_vg_version_ops {
int (*check_version) (struct config_tree * cf);
struct volume_group *(*read_vg) (struct format_instance * fid,
struct config_tree * cf);
void (*read_desc) (struct pool * mem, struct config_tree * cf,
time_t *when, char **desc);
};
struct text_vg_version_ops *text_vg_vsn1_init(void);
int print_flags(uint32_t status, int type, char *buffer, size_t size);
int read_flags(uint32_t *status, int type, struct config_value *cv);
int text_vg_export(FILE *fp, struct volume_group *vg, const char *desc);
struct volume_group *text_vg_import(struct format_instance *fid,
const char *file,
struct uuid_map *um,
time_t *when, char **desc);
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
uint32_t size);
struct volume_group *text_vg_import_file(struct format_instance *fid,
const char *file,
time_t *when, char **desc);
struct volume_group *text_vg_import_fd(struct format_instance *fid,
const char *file,
int fd,
off_t offset, uint32_t size,
off_t offset2, uint32_t size2,
checksum_fn_t checksum_fn,
uint32_t checksum,
time_t *when, char **desc);
#endif

View File

@@ -4,674 +4,80 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "metadata.h"
#include "import-export.h"
#include "pool.h"
#include "log.h"
#include "uuid.h"
#include "display.h"
#include "hash.h"
#include "toolcontext.h"
typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
struct volume_group * vg, struct config_node * pvn,
struct config_node * vgn,
struct hash_table * pv_hash, struct uuid_map * um);
#define _read_int32(root, path, result) \
get_config_uint32(root, path, '/', result)
#define _read_uint32(root, path, result) \
get_config_uint32(root, path, '/', result)
#define _read_int64(root, path, result) \
get_config_uint64(root, path, '/', result)
static int _read_id(struct id *id, struct config_node *cn, const char *path)
{
struct config_value *cv;
if (!(cn = find_config_node(cn, path, '/'))) {
log_err("Couldn't find uuid.");
return 0;
}
cv = cn->v;
if (!cv || !cv->v.str) {
log_err("uuid must be a string.");
return 0;
}
if (!id_read_format(id, cv->v.str)) {
log_err("Invalid uuid.");
return 0;
}
return 1;
}
static int _read_pv(struct format_instance *fid, struct pool *mem,
struct volume_group *vg, struct config_node *pvn,
struct config_node *vgn,
struct hash_table *pv_hash, struct uuid_map *um)
{
struct physical_volume *pv;
struct pv_list *pvl;
struct config_node *cn;
if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) ||
!(pvl->pv = pool_zalloc(mem, sizeof(*pvl->pv)))) {
stack;
return 0;
}
pv = pvl->pv;
/*
* Add the pv to the pv hash for quick lookup when we read
* the lv segments.
*/
if (!hash_insert(pv_hash, pvn->key, pv)) {
stack;
return 0;
}
if (!(pvn = pvn->child)) {
log_err("Empty pv section.");
return 0;
}
if (!_read_id(&pv->id, pvn, "id")) {
log_err("Couldn't read uuid for volume group.");
return 0;
}
/*
* Use the uuid map to convert the uuid into a device.
*/
if (!(pv->dev = uuid_map_lookup(um, &pv->id))) {
char buffer[64];
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
log_err("Couldn't find device.");
else
log_err("Couldn't find device with uuid '%s'.", buffer);
if (partial_mode())
vg->status |= PARTIAL_VG;
else
return 0;
}
if (!(pv->vg_name = pool_strdup(mem, vg->name))) {
stack;
return 0;
}
if (!(cn = find_config_node(pvn, "status", '/'))) {
log_err("Couldn't find status flags for physical volume.");
return 0;
}
if (!(read_flags(&pv->status, PV_FLAGS, cn->v))) {
log_err("Couldn't read status flags for physical volume.");
return 0;
}
if (!_read_int64(pvn, "pe_start", &pv->pe_start)) {
log_err("Couldn't read extent size for volume group.");
return 0;
}
if (!_read_int32(pvn, "pe_count", &pv->pe_count)) {
log_err("Couldn't find extent count (pe_count) for "
"physical volume.");
return 0;
}
/* adjust the volume group. */
vg->extent_count += pv->pe_count;
vg->free_count += pv->pe_count;
pv->pe_size = vg->extent_size;
pv->size = pv->pe_size * (uint64_t) pv->pe_count;
pv->pe_alloc_count = 0;
pv->fid = fid;
vg->pv_count++;
list_add(&vg->pvs, &pvl->list);
return 1;
}
static void _insert_segment(struct logical_volume *lv,
struct stripe_segment *seg)
{
struct list *segh;
struct stripe_segment *comp;
list_iterate(segh, &lv->segments) {
comp = list_item(segh, struct stripe_segment);
if (comp->le > seg->le) {
list_add(&comp->list, &seg->list);
return;
}
}
lv->le_count += seg->len;
list_add(&lv->segments, &seg->list);
}
static int _read_segment(struct pool *mem, struct volume_group *vg,
struct logical_volume *lv, struct config_node *sn,
struct hash_table *pv_hash)
{
int s;
uint32_t stripes;
struct stripe_segment *seg;
struct config_node *cn;
struct config_value *cv;
const char *seg_name = sn->key;
if (!(sn = sn->child)) {
log_err("Empty segment section.");
return 0;
}
if (!_read_int32(sn, "stripes", &stripes)) {
log_err("Couldn't read 'stripes' for segment '%s'.", sn->key);
return 0;
}
if (!(seg = pool_zalloc(mem, sizeof(*seg) +
(sizeof(seg->area[0]) * stripes)))) {
stack;
return 0;
}
seg->stripes = stripes;
seg->lv = lv;
if (!_read_int32(sn, "start_extent", &seg->le)) {
log_err("Couldn't read 'start_extent' for segment '%s'.",
sn->key);
return 0;
}
if (!_read_int32(sn, "extent_count", &seg->len)) {
log_err("Couldn't read 'extent_count' for segment '%s'.",
sn->key);
return 0;
}
if (seg->stripes == 0) {
log_err("Zero stripes is *not* allowed for segment '%s'.",
sn->key);
return 0;
}
if ((seg->stripes != 1) &&
!_read_int32(sn, "stripe_size", &seg->stripe_size)) {
log_err("Couldn't read 'stripe_size' for segment '%s'.",
sn->key);
return 0;
}
if (!(cn = find_config_node(sn, "areas", '/'))) {
log_err("Couldn't find 'areas' array for segment '%s'.",
sn->key);
return 0;
}
/*
* Read the stripes from the 'areas' array.
* FIXME: we could move this to a separate function.
*/
for (cv = cn->v, s = 0; cv && s < seg->stripes; s++, cv = cv->next) {
/* first we read the pv */
const char *bad = "Badly formed areas array for segment '%s'.";
struct physical_volume *pv;
uint32_t allocated;
if (cv->type != CFG_STRING) {
log_err(bad, sn->key);
return 0;
}
if (!(pv = hash_lookup(pv_hash, cv->v.str))) {
log_err("Couldn't find physical volume '%s' for "
"segment '%s'.",
cn->v->v.str ? cn->v->v.str : "NULL", seg_name);
return 0;
}
seg->area[s].pv = pv;
if (!(cv = cv->next)) {
log_err(bad, sn->key);
return 0;
}
if (cv->type != CFG_INT) {
log_err(bad, sn->key);
return 0;
}
seg->area[s].pe = cv->v.i;
/*
* Adjust the extent counts in the pv and vg.
*/
allocated = seg->len / seg->stripes;
pv->pe_alloc_count += allocated;
vg->free_count -= allocated;
}
/*
* Check we read the correct number of stripes.
*/
if (cv || (s < seg->stripes)) {
log_err("Incorrect number of stripes in 'area' array "
"for segment '%s'.", seg_name);
return 0;
}
/*
* Insert into correct part of segment list.
*/
_insert_segment(lv, seg);
return 1;
}
static int _read_segments(struct pool *mem, struct volume_group *vg,
struct logical_volume *lv, struct config_node *lvn,
struct hash_table *pv_hash)
{
struct config_node *sn;
int count = 0, seg_count;
for (sn = lvn; sn; sn = sn->sib) {
/*
* All sub-sections are assumed to be segments.
*/
if (!sn->v) {
if (!_read_segment(mem, vg, lv, sn, pv_hash)) {
stack;
return 0;
}
count++;
}
}
if (!_read_int32(lvn, "segment_count", &seg_count)) {
log_err("Couldn't read segment count for logical volume.");
return 0;
}
if (seg_count != count) {
log_err("segment_count and actual number of segments "
"disagree.");
return 0;
}
/*
* Check there are no gaps or overlaps in the lv.
*/
if (!lv_check_segments(lv)) {
stack;
return 0;
}
/*
* Merge segments in case someones been editing things by hand.
*/
if (!lv_merge_segments(lv)) {
stack;
return 0;
}
return 1;
}
static int _read_lv(struct format_instance *fid, struct pool *mem,
struct volume_group *vg, struct config_node *lvn,
struct config_node *vgn, struct hash_table *pv_hash,
struct uuid_map *um)
{
struct logical_volume *lv;
struct lv_list *lvl;
struct config_node *cn;
if (!(lvl = pool_zalloc(mem, sizeof(*lvl))) ||
!(lvl->lv = pool_zalloc(mem, sizeof(*lvl->lv)))) {
stack;
return 0;
}
lv = lvl->lv;
if (!(lv->name = pool_strdup(mem, lvn->key))) {
stack;
return 0;
}
if (!(lvn = lvn->child)) {
log_err("Empty logical volume section.");
return 0;
}
lv->vg = vg;
/* FIXME: read full lvid */
if (!_read_id(&lv->lvid.id[1], lvn, "id")) {
log_err("Couldn't read uuid for logical volume %s.", lv->name);
return 0;
}
memcpy(&lv->lvid.id[0], &lv->vg->id, sizeof(lv->lvid.id[0]));
if (!(cn = find_config_node(lvn, "status", '/'))) {
log_err("Couldn't find status flags for logical volume.");
return 0;
}
if (!(read_flags(&lv->status, LV_FLAGS, cn->v))) {
log_err("Couldn't read status flags for logical volume.");
return 0;
}
lv->minor = -1;
if ((lv->status & FIXED_MINOR) &&
!_read_int32(lvn, "minor", &lv->minor)) {
log_error("Couldn't read 'minor' value for logical volume.");
return 0;
}
if (!_read_int32(lvn, "read_ahead", &lv->read_ahead)) {
log_err("Couldn't read 'read_ahead' value for "
"logical volume.");
return 0;
}
list_init(&lv->segments);
if (!_read_segments(mem, vg, lv, lvn, pv_hash)) {
stack;
return 0;
}
lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size;
vg->lv_count++;
list_add(&vg->lvs, &lvl->list);
return 1;
}
static int _read_snapshot(struct format_instance *fid, struct pool *mem,
struct volume_group *vg, struct config_node *sn,
struct config_node *vgn, struct hash_table *pv_hash,
struct uuid_map *um)
{
uint32_t chunk_size;
const char *org_name, *cow_name;
struct logical_volume *org, *cow;
if (!(sn = sn->child)) {
log_err("Empty snapshot section.");
return 0;
}
if (!_read_uint32(sn, "chunk_size", &chunk_size)) {
log_err("Couldn't read chunk size for snapshot.");
return 0;
}
if (!(cow_name = find_config_str(sn, "cow_store", '/', NULL))) {
log_err("Snapshot cow storage not specified.");
return 0;
}
if (!(org_name = find_config_str(sn, "origin", '/', NULL))) {
log_err("Snapshot origin not specified.");
return 0;
}
if (!(cow = find_lv(vg, cow_name))) {
log_err("Unknown logical volume specified for "
"snapshot cow store.");
return 0;
}
if (!(org = find_lv(vg, org_name))) {
log_err("Unknown logical volume specified for "
"snapshot origin.");
return 0;
}
if (!vg_add_snapshot(org, cow, 1, chunk_size)) {
stack;
return 0;
}
return 1;
}
static int _read_sections(struct format_instance *fid,
const char *section, section_fn fn,
struct pool *mem,
struct volume_group *vg, struct config_node *vgn,
struct hash_table *pv_hash,
struct uuid_map *um, int optional)
{
struct config_node *n;
if (!(n = find_config_node(vgn, section, '/'))) {
if (!optional) {
log_err("Couldn't find section '%s'.", section);
return 0;
}
return 1;
}
for (n = n->child; n; n = n->sib) {
if (!fn(fid, mem, vg, n, vgn, pv_hash, um)) {
stack;
return 0;
}
}
return 1;
}
static struct volume_group *_read_vg(struct format_instance *fid,
struct config_file *cf,
struct uuid_map *um)
{
struct config_node *vgn, *cn;
struct volume_group *vg;
struct hash_table *pv_hash = NULL;
struct pool *mem = fid->fmt->cmd->mem;
/* skip any top-level values */
for (vgn = cf->root; (vgn && vgn->v); vgn = vgn->sib) ;
if (!vgn) {
log_err("Couldn't find volume group in file.");
return NULL;
}
if (!(vg = pool_zalloc(mem, sizeof(*vg)))) {
stack;
return NULL;
}
vg->cmd = fid->fmt->cmd;
/* FIXME Determine format type from file contents */
/* eg Set to instance of fmt1 here if reading a format1 backup? */
vg->fid = fid;
if (!(vg->name = pool_strdup(mem, vgn->key))) {
stack;
goto bad;
}
if (!(vg->system_id = pool_zalloc(mem, NAME_LEN))) {
stack;
goto bad;
}
vgn = vgn->child;
if ((cn = find_config_node(vgn, "system_id", '/')) && cn->v) {
if (!cn->v->v.str) {
log_error("system_id must be a string");
goto bad;
}
strncpy(vg->system_id, cn->v->v.str, NAME_LEN);
}
if (!_read_id(&vg->id, vgn, "id")) {
log_err("Couldn't read uuid for volume group %s.", vg->name);
goto bad;
}
if (!_read_int32(vgn, "seqno", &vg->seqno)) {
log_err("Couldn't read 'seqno' for volume group %s.", vg->name);
goto bad;
}
if (!(cn = find_config_node(vgn, "status", '/'))) {
log_err("Couldn't find status flags for volume group %s.",
vg->name);
goto bad;
}
if (!(read_flags(&vg->status, VG_FLAGS, cn->v))) {
log_err("Couldn't read status flags for volume group %s.",
vg->name);
goto bad;
}
if (!_read_int32(vgn, "extent_size", &vg->extent_size)) {
log_err("Couldn't read extent size for volume group %s.",
vg->name);
goto bad;
}
/*
* 'extent_count' and 'free_count' get filled in
* implicitly when reading in the pv's and lv's.
*/
if (!_read_int32(vgn, "max_lv", &vg->max_lv)) {
log_err("Couldn't read 'max_lv' for volume group %s.",
vg->name);
goto bad;
}
if (!_read_int32(vgn, "max_pv", &vg->max_pv)) {
log_err("Couldn't read 'max_pv' for volume group %s.",
vg->name);
goto bad;
}
/*
* The pv hash memoises the pv section names -> pv
* structures.
*/
if (!(pv_hash = hash_create(32))) {
log_err("Couldn't create hash table.");
goto bad;
}
list_init(&vg->pvs);
if (!_read_sections(fid, "physical_volumes", _read_pv, mem, vg,
vgn, pv_hash, um, 0)) {
log_err("Couldn't find all physical volumes for volume "
"group %s.", vg->name);
goto bad;
}
list_init(&vg->lvs);
if (!_read_sections(fid, "logical_volumes", _read_lv, mem, vg,
vgn, pv_hash, um, 1)) {
log_err("Couldn't read all logical volumes for volume "
"group %s.", vg->name);
goto bad;
}
list_init(&vg->snapshots);
if (!_read_sections(fid, "snapshots", _read_snapshot, mem, vg,
vgn, pv_hash, um, 1)) {
log_err("Couldn't read all snapshots for volume group %s.",
vg->name);
goto bad;
}
hash_destroy(pv_hash);
if (vg->status & PARTIAL_VG) {
vg->status &= ~LVM_WRITE;
vg->status |= LVM_READ;
}
/*
* Finished.
*/
return vg;
bad:
if (pv_hash)
hash_destroy(pv_hash);
pool_free(mem, vg);
return NULL;
}
static void _read_desc(struct pool *mem,
struct config_file *cf, time_t * when, char **desc)
{
const char *d;
unsigned int u = 0u;
d = find_config_str(cf->root, "description", '/', "");
*desc = pool_strdup(mem, d);
get_config_uint32(cf->root, "creation_time", '/', &u);
*when = u;
}
struct volume_group *text_vg_import(struct format_instance *fid,
const char *file,
struct uuid_map *um,
time_t * when, char **desc)
#include "cache.h"
/* FIXME Use tidier inclusion method */
static struct text_vg_version_ops *(_text_vsn_list[2]);
struct volume_group *text_vg_import_fd(struct format_instance *fid,
const char *file,
int fd,
off_t offset, uint32_t size,
off_t offset2, uint32_t size2,
checksum_fn_t checksum_fn,
uint32_t checksum,
time_t *when, char **desc)
{
struct volume_group *vg = NULL;
struct config_file *cf;
struct config_tree *cf;
struct text_vg_version_ops **vsn;
static int _initialised = 0;
if (!_initialised) {
_text_vsn_list[0] = text_vg_vsn1_init();
_text_vsn_list[1] = NULL;
_initialised = 1;
}
*desc = NULL;
*when = 0;
if (!(cf = create_config_file())) {
if (!(cf = create_config_tree())) {
stack;
goto out;
}
if (!read_config(cf, file)) {
log_error("Couldn't read volume group file.");
if ((fd == -1 && !read_config_file(cf, file)) ||
(fd != -1 && !read_config_fd(cf, fd, file, offset, size,
offset2, size2, checksum_fn,
checksum))) {
log_error("Couldn't read volume group metadata.");
goto out;
}
if (!(vg = _read_vg(fid, cf, um))) {
stack;
goto out;
}
/*
* Find a set of version functions that can read this file
*/
for (vsn = &_text_vsn_list[0]; *vsn; vsn++) {
if (!(*vsn)->check_version(cf))
continue;
_read_desc(fid->fmt->cmd->mem, cf, when, desc);
if (!(vg = (*vsn)->read_vg(fid, cf))) {
stack;
goto out;
}
(*vsn)->read_desc(fid->fmt->cmd->mem, cf, when, desc);
break;
}
out:
destroy_config_file(cf);
destroy_config_tree(cf);
return vg;
}
struct volume_group *text_vg_import_file(struct format_instance *fid,
const char *file,
time_t *when, char **desc)
{
return text_vg_import_fd(fid, file, -1, 0, 0, 0, 0, NULL, 0,
when, desc);
}

View File

@@ -0,0 +1,735 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#include "lib.h"
#include "metadata.h"
#include "import-export.h"
#include "pool.h"
#include "display.h"
#include "hash.h"
#include "toolcontext.h"
#include "cache.h"
typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
struct volume_group * vg, struct config_node * pvn,
struct config_node * vgn,
struct hash_table * pv_hash);
#define _read_int32(root, path, result) \
get_config_uint32(root, path, '/', result)
#define _read_uint32(root, path, result) \
get_config_uint32(root, path, '/', result)
#define _read_int64(root, path, result) \
get_config_uint64(root, path, '/', result)
/*
* Logs an attempt to read an invalid format file.
*/
static void _invalid_format(const char *str)
{
log_error("Can't process text format file - %s.", str);
}
/*
* Checks that the config file contains vg metadata, and that it
* we recognise the version number,
*/
static int _check_version(struct config_tree *cf)
{
struct config_node *cn;
struct config_value *cv;
/*
* Check the contents field.
*/
if (!(cn = find_config_node(cf->root, CONTENTS_FIELD, '/'))) {
_invalid_format("missing contents field");
return 0;
}
cv = cn->v;
if (!cv || cv->type != CFG_STRING || strcmp(cv->v.str, CONTENTS_VALUE)) {
_invalid_format("unrecognised contents field");
return 0;
}
/*
* Check the version number.
*/
if (!(cn = find_config_node(cf->root, FORMAT_VERSION_FIELD, '/'))) {
_invalid_format("missing version number");
return 0;
}
cv = cn->v;
if (!cv || cv->type != CFG_INT || cv->v.i != FORMAT_VERSION_VALUE) {
_invalid_format("unrecognised version number");
return 0;
}
return 1;
}
static int _read_id(struct id *id, struct config_node *cn, const char *path)
{
struct config_value *cv;
if (!(cn = find_config_node(cn, path, '/'))) {
log_error("Couldn't find uuid.");
return 0;
}
cv = cn->v;
if (!cv || !cv->v.str) {
log_error("uuid must be a string.");
return 0;
}
if (!id_read_format(id, cv->v.str)) {
log_error("Invalid uuid.");
return 0;
}
return 1;
}
static int _read_pv(struct format_instance *fid, struct pool *mem,
struct volume_group *vg, struct config_node *pvn,
struct config_node *vgn, struct hash_table *pv_hash)
{
struct physical_volume *pv;
struct pv_list *pvl;
struct config_node *cn;
if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) ||
!(pvl->pv = pool_zalloc(mem, sizeof(*pvl->pv)))) {
stack;
return 0;
}
pv = pvl->pv;
/*
* Add the pv to the pv hash for quick lookup when we read
* the lv segments.
*/
if (!hash_insert(pv_hash, pvn->key, pv)) {
stack;
return 0;
}
if (!(pvn = pvn->child)) {
log_error("Empty pv section.");
return 0;
}
if (!_read_id(&pv->id, pvn, "id")) {
log_error("Couldn't read uuid for volume group.");
return 0;
}
/*
* Convert the uuid into a device.
*/
if (!(pv->dev = device_from_pvid(fid->fmt->cmd, &pv->id))) {
char buffer[64];
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
log_error("Couldn't find device.");
else
log_error("Couldn't find device with uuid '%s'.",
buffer);
if (partial_mode())
vg->status |= PARTIAL_VG;
else
return 0;
}
if (!(pv->vg_name = pool_strdup(mem, vg->name))) {
stack;
return 0;
}
if (!(cn = find_config_node(pvn, "status", '/'))) {
log_error("Couldn't find status flags for physical volume.");
return 0;
}
if (!(read_flags(&pv->status, PV_FLAGS, cn->v))) {
log_error("Couldn't read status flags for physical volume.");
return 0;
}
if (!_read_int64(pvn, "pe_start", &pv->pe_start)) {
log_error("Couldn't read extent size for volume group.");
return 0;
}
if (!_read_int32(pvn, "pe_count", &pv->pe_count)) {
log_error("Couldn't find extent count (pe_count) for "
"physical volume.");
return 0;
}
/* adjust the volume group. */
vg->extent_count += pv->pe_count;
vg->free_count += pv->pe_count;
pv->pe_size = vg->extent_size;
pv->size = vg->extent_size * (uint64_t) pv->pe_count;
pv->pe_alloc_count = 0;
pv->fmt = fid->fmt;
vg->pv_count++;
list_add(&vg->pvs, &pvl->list);
return 1;
}
static void _insert_segment(struct logical_volume *lv, struct lv_segment *seg)
{
struct list *segh;
struct lv_segment *comp;
list_iterate(segh, &lv->segments) {
comp = list_item(segh, struct lv_segment);
if (comp->le > seg->le) {
list_add(&comp->list, &seg->list);
return;
}
}
lv->le_count += seg->len;
list_add(&lv->segments, &seg->list);
}
static int _read_segment(struct pool *mem, struct volume_group *vg,
struct logical_volume *lv, struct config_node *sn,
struct hash_table *pv_hash)
{
int s;
uint32_t stripes = 0;
struct lv_segment *seg;
struct config_node *cn;
struct config_value *cv;
const char *seg_name = sn->key;
uint32_t start_extent, extent_count;
uint32_t chunk_size;
const char *org_name, *cow_name;
struct logical_volume *org, *cow;
segment_type_t segtype;
if (!(sn = sn->child)) {
log_error("Empty segment section.");
return 0;
}
if (!_read_int32(sn, "start_extent", &start_extent)) {
log_error("Couldn't read 'start_extent' for segment '%s'.",
sn->key);
return 0;
}
if (!_read_int32(sn, "extent_count", &extent_count)) {
log_error("Couldn't read 'extent_count' for segment '%s'.",
sn->key);
return 0;
}
segtype = SEG_STRIPED; /* Default */
if ((cn = find_config_node(sn, "type", '/'))) {
cv = cn->v;
if (!cv || !cv->v.str) {
log_error("Segment type must be a string.");
return 0;
}
segtype = get_segtype_from_string(cv->v.str);
}
if (segtype == SEG_STRIPED) {
if (!_read_int32(sn, "stripe_count", &stripes)) {
log_error("Couldn't read 'stripe_count' for "
"segment '%s'.", sn->key);
return 0;
}
}
if (!(seg = pool_zalloc(mem, sizeof(*seg) +
(sizeof(seg->area[0]) * stripes)))) {
stack;
return 0;
}
seg->lv = lv;
seg->le = start_extent;
seg->len = extent_count;
switch (segtype) {
case SEG_MIRROR:
case SEG_SNAPSHOT:
lv->status |= SNAPSHOT;
if (!_read_uint32(sn, "chunk_size", &chunk_size)) {
log_error("Couldn't read chunk size for snapshot.");
return 0;
}
log_suppress(1);
if (!(cow_name = find_config_str(sn, "cow_store", '/', NULL))) {
log_suppress(0);
log_error("Snapshot cow storage not specified.");
return 0;
}
if (!(org_name = find_config_str(sn, "origin", '/', NULL))) {
log_suppress(0);
log_error("Snapshot origin not specified.");
return 0;
}
log_suppress(0);
if (!(cow = find_lv(vg, cow_name))) {
log_error("Unknown logical volume specified for "
"snapshot cow store.");
return 0;
}
if (!(org = find_lv(vg, org_name))) {
log_error("Unknown logical volume specified for "
"snapshot origin.");
return 0;
}
if (!vg_add_snapshot(org, cow, 1, &lv->lvid.id[1], chunk_size)) {
stack;
return 0;
}
break;
case SEG_STRIPED:
seg->stripes = stripes;
if (!seg->stripes) {
log_error("Zero stripes *not* allowed for segment '%s'",
sn->key);
return 0;
}
if ((seg->stripes != 1) &&
!_read_int32(sn, "stripe_size", &seg->stripe_size)) {
log_error("Couldn't read stripe_size for segment '%s'.",
sn->key);
return 0;
}
if (!(cn = find_config_node(sn, "stripes", '/'))) {
log_error("Couldn't find stripes array for segment "
"'%s'.", sn->key);
return 0;
}
for (cv = cn->v, s = 0; cv && s < seg->stripes;
s++, cv = cv->next) {
/* first we read the pv */
const char *bad = "Badly formed areas array for "
"segment '%s'.";
struct physical_volume *pv;
uint32_t allocated;
if (cv->type != CFG_STRING) {
log_error(bad, sn->key);
return 0;
}
if (!(pv = hash_lookup(pv_hash, cv->v.str))) {
log_error("Couldn't find physical volume '%s' "
"for segment '%s'.",
cv->v.str ? cv->v.str : "NULL",
seg_name);
return 0;
}
seg->area[s].pv = pv;
if (!(cv = cv->next)) {
log_error(bad, sn->key);
return 0;
}
if (cv->type != CFG_INT) {
log_error(bad, sn->key);
return 0;
}
seg->area[s].pe = cv->v.i;
/*
* Adjust the extent counts in the pv and vg.
*/
allocated = seg->len / seg->stripes;
pv->pe_alloc_count += allocated;
vg->free_count -= allocated;
}
/*
* Check we read the correct number of stripes.
*/
if (cv || (s < seg->stripes)) {
log_error("Incorrect number of stripes in 'area' array "
"for segment '%s'.", seg_name);
return 0;
}
}
/*
* Insert into correct part of segment list.
*/
_insert_segment(lv, seg);
return 1;
}
static int _read_segments(struct pool *mem, struct volume_group *vg,
struct logical_volume *lv, struct config_node *lvn,
struct hash_table *pv_hash)
{
struct config_node *sn;
int count = 0, seg_count;
for (sn = lvn; sn; sn = sn->sib) {
/*
* All sub-sections are assumed to be segments.
*/
if (!sn->v) {
if (!_read_segment(mem, vg, lv, sn, pv_hash)) {
stack;
return 0;
}
count++;
}
/* FIXME Remove this restriction */
if ((lv->status & SNAPSHOT) && count > 1) {
log_error("Only one segment permitted for snapshot");
return 0;
}
}
if (!_read_int32(lvn, "segment_count", &seg_count)) {
log_error("Couldn't read segment count for logical volume.");
return 0;
}
if (seg_count != count) {
log_error("segment_count and actual number of segments "
"disagree.");
return 0;
}
/*
* Check there are no gaps or overlaps in the lv.
*/
if (!lv_check_segments(lv)) {
stack;
return 0;
}
/*
* Merge segments in case someones been editing things by hand.
*/
if (!lv_merge_segments(lv)) {
stack;
return 0;
}
return 1;
}
static int _read_lv(struct format_instance *fid, struct pool *mem,
struct volume_group *vg, struct config_node *lvn,
struct config_node *vgn, struct hash_table *pv_hash)
{
struct logical_volume *lv;
struct lv_list *lvl;
struct config_node *cn;
if (!(lvl = pool_zalloc(mem, sizeof(*lvl))) ||
!(lvl->lv = pool_zalloc(mem, sizeof(*lvl->lv)))) {
stack;
return 0;
}
lv = lvl->lv;
if (!(lv->name = pool_strdup(mem, lvn->key))) {
stack;
return 0;
}
if (!(lvn = lvn->child)) {
log_error("Empty logical volume section.");
return 0;
}
lv->vg = vg;
/* FIXME: read full lvid */
if (!_read_id(&lv->lvid.id[1], lvn, "id")) {
log_error("Couldn't read uuid for logical volume %s.",
lv->name);
return 0;
}
memcpy(&lv->lvid.id[0], &lv->vg->id, sizeof(lv->lvid.id[0]));
if (!(cn = find_config_node(lvn, "status", '/'))) {
log_error("Couldn't find status flags for logical volume.");
return 0;
}
if (!(read_flags(&lv->status, LV_FLAGS, cn->v))) {
log_error("Couldn't read status flags for logical volume.");
return 0;
}
list_init(&lv->segments);
if (!_read_segments(mem, vg, lv, lvn, pv_hash)) {
stack;
return 0;
}
lv->alloc = ALLOC_DEFAULT;
if ((cn = find_config_node(lvn, "allocation_policy", '/'))) {
struct config_value *cv = cn->v;
if (!cv || !cv->v.str) {
log_error("allocation_policy must be a string.");
return 0;
}
lv->alloc = get_alloc_from_string(cv->v.str);
}
/* read_ahead defaults to 0 */
if (!_read_int32(lvn, "read_ahead", &lv->read_ahead))
lv->read_ahead = 0;
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.");
return 0;
}
vg->lv_count++;
list_add(&vg->lvs, &lvl->list);
}
return 1;
}
static int _read_sections(struct format_instance *fid,
const char *section, section_fn fn,
struct pool *mem,
struct volume_group *vg, struct config_node *vgn,
struct hash_table *pv_hash, int optional)
{
struct config_node *n;
if (!(n = find_config_node(vgn, section, '/'))) {
if (!optional) {
log_error("Couldn't find section '%s'.", section);
return 0;
}
return 1;
}
for (n = n->child; n; n = n->sib) {
if (!fn(fid, mem, vg, n, vgn, pv_hash)) {
stack;
return 0;
}
}
return 1;
}
static struct volume_group *_read_vg(struct format_instance *fid,
struct config_tree *cf)
{
struct config_node *vgn, *cn;
struct volume_group *vg;
struct hash_table *pv_hash = NULL;
struct pool *mem = fid->fmt->cmd->mem;
/* skip any top-level values */
for (vgn = cf->root; (vgn && vgn->v); vgn = vgn->sib) ;
if (!vgn) {
log_error("Couldn't find volume group in file.");
return NULL;
}
if (!(vg = pool_zalloc(mem, sizeof(*vg)))) {
stack;
return NULL;
}
vg->cmd = fid->fmt->cmd;
/* FIXME Determine format type from file contents */
/* eg Set to instance of fmt1 here if reading a format1 backup? */
vg->fid = fid;
if (!(vg->name = pool_strdup(mem, vgn->key))) {
stack;
goto bad;
}
if (!(vg->system_id = pool_zalloc(mem, NAME_LEN))) {
stack;
goto bad;
}
vgn = vgn->child;
if ((cn = find_config_node(vgn, "system_id", '/')) && cn->v) {
if (!cn->v->v.str) {
log_error("system_id must be a string");
goto bad;
}
strncpy(vg->system_id, cn->v->v.str, NAME_LEN);
}
if (!_read_id(&vg->id, vgn, "id")) {
log_error("Couldn't read uuid for volume group %s.", vg->name);
goto bad;
}
if (!_read_int32(vgn, "seqno", &vg->seqno)) {
log_error("Couldn't read 'seqno' for volume group %s.",
vg->name);
goto bad;
}
if (!(cn = find_config_node(vgn, "status", '/'))) {
log_error("Couldn't find status flags for volume group %s.",
vg->name);
goto bad;
}
if (!(read_flags(&vg->status, VG_FLAGS, cn->v))) {
log_error("Couldn't read status flags for volume group %s.",
vg->name);
goto bad;
}
if (!_read_int32(vgn, "extent_size", &vg->extent_size)) {
log_error("Couldn't read extent size for volume group %s.",
vg->name);
goto bad;
}
/*
* 'extent_count' and 'free_count' get filled in
* implicitly when reading in the pv's and lv's.
*/
if (!_read_int32(vgn, "max_lv", &vg->max_lv)) {
log_error("Couldn't read 'max_lv' for volume group %s.",
vg->name);
goto bad;
}
if (!_read_int32(vgn, "max_pv", &vg->max_pv)) {
log_error("Couldn't read 'max_pv' for volume group %s.",
vg->name);
goto bad;
}
/*
* The pv hash memoises the pv section names -> pv
* structures.
*/
if (!(pv_hash = hash_create(32))) {
log_error("Couldn't create hash table.");
goto bad;
}
list_init(&vg->pvs);
if (!_read_sections(fid, "physical_volumes", _read_pv, mem, vg,
vgn, pv_hash, 0)) {
log_error("Couldn't find all physical volumes for volume "
"group %s.", vg->name);
goto bad;
}
list_init(&vg->lvs);
list_init(&vg->snapshots);
if (!_read_sections(fid, "logical_volumes", _read_lv, mem, vg,
vgn, pv_hash, 1)) {
log_error("Couldn't read all logical volumes for volume "
"group %s.", vg->name);
goto bad;
}
hash_destroy(pv_hash);
if (vg->status & PARTIAL_VG) {
vg->status &= ~LVM_WRITE;
vg->status |= LVM_READ;
}
/*
* Finished.
*/
return vg;
bad:
if (pv_hash)
hash_destroy(pv_hash);
pool_free(mem, vg);
return NULL;
}
static void _read_desc(struct pool *mem,
struct config_tree *cf, time_t *when, char **desc)
{
const char *d;
unsigned int u = 0u;
log_suppress(1);
d = find_config_str(cf->root, "description", '/', "");
log_suppress(0);
*desc = pool_strdup(mem, d);
get_config_uint32(cf->root, "creation_time", '/', &u);
*when = u;
}
static struct text_vg_version_ops _vsn1_ops = {
check_version:_check_version,
read_vg:_read_vg,
read_desc:_read_desc
};
struct text_vg_version_ops *text_vg_vsn1_init(void)
{
return &_vsn1_ops;
};

76
lib/format_text/layout.h Normal file
View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#ifndef _LVM_TEXT_LAYOUT_H
#define _LVM_TEXT_LAYOUT_H
#include "config.h"
#include "lvm-types.h"
#include "metadata.h"
#include "uuid.h"
/* On disk */
struct disk_locn {
uint64_t offset; /* Offset in bytes to start sector */
uint64_t size; /* Bytes */
} __attribute__ ((packed));
/* Data areas (holding PEs) */
struct data_area_list {
struct list list;
struct disk_locn disk_locn;
};
/* Fields with the suffix _xl should be xlate'd wherever they appear */
/* On disk */
struct pv_header {
uint8_t pv_uuid[ID_LEN];
uint64_t device_size_xl; /* Bytes */
/* NULL-terminated list of data areas followed by */
/* NULL-terminated list of metadata area headers */
struct disk_locn disk_areas_xl[0]; /* Two lists */
} __attribute__ ((packed));
/* On disk */
struct raw_locn {
uint64_t offset; /* Offset in bytes to start sector */
uint64_t size; /* Bytes */
uint32_t checksum;
uint32_t filler;
} __attribute__ ((packed));
/* On disk */
/* Structure size limited to one sector */
struct mda_header {
uint32_t checksum_xl; /* Checksum of rest of mda_header */
uint8_t magic[16]; /* To aid scans for metadata */
uint32_t version;
uint64_t start; /* Absolute start byte of mda_header */
uint64_t size; /* Size of metadata area */
struct raw_locn raw_locns[0]; /* NULL-terminated list */
} __attribute__ ((packed));
struct mda_lists {
struct list dirs;
struct list raws;
struct metadata_area_ops *file_ops;
struct metadata_area_ops *raw_ops;
};
struct mda_context {
struct device_area area;
struct raw_locn rlocn; /* Store inbetween write and commit */
};
/* FIXME Convert this at runtime */
#define FMTT_MAGIC "\040\114\126\115\062\040\170\133\065\101\045\162\060\116\052\076"
#define FMTT_VERSION 1
#define MDA_HEADER_SIZE 512
#define LVM2_LABEL "LVM2 001"
#endif

View File

@@ -1,67 +0,0 @@
# An example volume group
# YYYY-MM-DD HH:MM:SS
output_date = "2001-12-11 11:35:12"
sample_volume_group {
id = "ksjdlfksjldskjlsk"
status = ["ACTIVE"]
extent_size = 8192 # 4 Megabytes
max_lv = 99
max_pv = 255
physical_volumes {
pv1 {
id = "lksjdflksdlsk"
device = "/dev/hda1" # Hint only
status = ["ALLOCATABLE"]
pe_start = 8192
pe_count = 2048 # 8 Gigabytes
}
pv2 {
id = "lksjdflksdlsk"
device = "/dev/hda2" # Hint only
status = ["ALLOCATABLE"]
pe_start = 8192
pe_count = 1024 # 4 Gigabytes
}
}
logical_volumes {
music {
status = ["ACTIVE"]
read_ahead = 1024
segment_count = 2
segment1 {
start_extent = 0
extent_count = 1024 # 4 Gigabytes
stripes = 1
areas = [
"pv1", 0
]
}
segment2 {
start_extent = 1024
extent_count = 2048 # 8 Gigabytes
stripes = 2
stripe_size = 32 # 16 Kilobytes
areas = [
"pv1", 1024,
"pv2", 0
]
}
}
}

View File

@@ -0,0 +1,280 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#include "lib.h"
#include "format-text.h"
#include "layout.h"
#include "label.h"
#include "xlate.h"
#include <sys/stat.h>
#include <fcntl.h>
static int _can_handle(struct labeller *l, char *buf, uint64_t sector)
{
struct label_header *lh = (struct label_header *) buf;
if (!strncmp(lh->type, LVM2_LABEL, sizeof(lh->type)))
return 1;
return 0;
}
static int _write(struct label *label, char *buf)
{
struct label_header *lh = (struct label_header *) buf;
struct pv_header *pvhdr;
struct cache_info *info;
struct disk_locn *pvh_dlocn_xl;
struct list *mdash, *dash;
struct metadata_area *mda;
struct mda_context *mdac;
struct data_area_list *da;
/* FIXME Move to where label is created */
strncpy(label->type, LVM2_LABEL, sizeof(label->type));
strncpy(lh->type, label->type, sizeof(label->type));
pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl));
info = (struct cache_info *) label->info;
pvhdr->device_size_xl = xlate64(info->device_size);
memcpy(pvhdr->pv_uuid, &info->dev->pvid, sizeof(struct id));
pvh_dlocn_xl = &pvhdr->disk_areas_xl[0];
/* List of data areas (holding PEs) */
list_iterate(dash, &info->das) {
da = list_item(dash, struct data_area_list);
pvh_dlocn_xl->offset = xlate64(da->disk_locn.offset);
pvh_dlocn_xl->size = xlate64(da->disk_locn.size);
pvh_dlocn_xl++;
}
/* NULL-termination */
pvh_dlocn_xl->offset = xlate64(0);
pvh_dlocn_xl->size = xlate64(0);
pvh_dlocn_xl++;
/* List of metadata area header locations */
list_iterate(mdash, &info->mdas) {
mda = list_item(mdash, struct metadata_area);
mdac = (struct mda_context *) mda->metadata_locn;
if (mdac->area.dev != info->dev)
continue;
pvh_dlocn_xl->offset = xlate64(mdac->area.start);
pvh_dlocn_xl->size = xlate64(mdac->area.size);
pvh_dlocn_xl++;
}
/* NULL-termination */
pvh_dlocn_xl->offset = xlate64(0);
pvh_dlocn_xl->size = xlate64(0);
return 1;
}
int add_da(struct format_type *fmt, struct pool *mem, struct list *das,
uint64_t start, uint64_t size)
{
struct data_area_list *dal;
if (!mem) {
if (!(dal = dbg_malloc(sizeof(*dal)))) {
log_error("struct data_area_list allocation failed");
return 0;
}
} else {
if (!(dal = pool_alloc(mem, sizeof(*dal)))) {
log_error("struct data_area_list allocation failed");
return 0;
}
}
dal->disk_locn.offset = start;
dal->disk_locn.size = size;
list_add(das, &dal->list);
return 1;
}
void del_das(struct list *das)
{
struct list *dah, *tmp;
struct data_area_list *da;
list_iterate_safe(dah, tmp, das) {
da = list_item(dah, struct data_area_list);
list_del(&da->list);
dbg_free(da);
}
}
int add_mda(struct format_type *fmt, struct pool *mem, struct list *mdas,
struct device *dev, uint64_t start, uint64_t size)
{
/* FIXME List size restricted by pv_header SECTOR_SIZE */
struct metadata_area *mdal;
struct mda_lists *mda_lists = (struct mda_lists *) fmt->private;
struct mda_context *mdac;
if (!mem) {
if (!(mdal = dbg_malloc(sizeof(struct metadata_area)))) {
log_error("struct mda_list allocation failed");
return 0;
}
if (!(mdac = dbg_malloc(sizeof(struct mda_context)))) {
log_error("struct mda_context allocation failed");
dbg_free(mdal);
return 0;
}
} else {
if (!(mdal = pool_alloc(mem, sizeof(struct metadata_area)))) {
log_error("struct mda_list allocation failed");
return 0;
}
if (!(mdac = pool_alloc(mem, sizeof(struct mda_context)))) {
log_error("struct mda_context allocation failed");
return 0;
}
}
mdal->ops = mda_lists->raw_ops;
mdal->metadata_locn = mdac;
mdac->area.dev = dev;
mdac->area.start = start;
mdac->area.size = size;
memset(&mdac->rlocn, 0, sizeof(mdac->rlocn));
list_add(mdas, &mdal->list);
return 1;
}
void del_mdas(struct list *mdas)
{
struct list *mdah, *tmp;
struct metadata_area *mda;
list_iterate_safe(mdah, tmp, mdas) {
mda = list_item(mdah, struct metadata_area);
dbg_free(mda->metadata_locn);
list_del(&mda->list);
dbg_free(mda);
}
}
static int _initialise_label(struct labeller *l, struct label *label)
{
strncpy(label->type, LVM2_LABEL, sizeof(label->type));
return 1;
}
static int _read(struct labeller *l, struct device *dev, char *buf,
struct label **label)
{
struct label_header *lh = (struct label_header *) buf;
struct pv_header *pvhdr;
struct cache_info *info;
struct disk_locn *dlocn_xl;
uint64_t offset;
struct list *mdah;
struct metadata_area *mda;
char vgnamebuf[NAME_LEN + 2];
struct mda_context *mdac;
pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl));
if (!(info = cache_add(l, pvhdr->pv_uuid, dev, NULL, NULL)))
return 0;
*label = info->label;
info->device_size = xlate64(pvhdr->device_size_xl);
if (info->das.n)
del_das(&info->das);
list_init(&info->das);
if (info->mdas.n)
del_mdas(&info->mdas);
list_init(&info->mdas);
/* Data areas holding the PEs */
dlocn_xl = pvhdr->disk_areas_xl;
while ((offset = xlate64(dlocn_xl->offset))) {
add_da(info->fmt, NULL, &info->das, offset,
xlate64(dlocn_xl->size));
dlocn_xl++;
}
/* Metadata area headers */
dlocn_xl++;
while ((offset = xlate64(dlocn_xl->offset))) {
add_mda(info->fmt, NULL, &info->mdas, dev, offset,
xlate64(dlocn_xl->size));
dlocn_xl++;
}
list_iterate(mdah, &info->mdas) {
mda = list_item(mdah, struct metadata_area);
mdac = (struct mda_context *) mda->metadata_locn;
if (vgname_from_mda(info->fmt, &mdac->area, vgnamebuf,
sizeof(vgnamebuf))) {
cache_update_vgname(info, vgnamebuf);
}
}
info->status &= ~CACHE_INVALID;
return 1;
}
static void _destroy_label(struct labeller *l, struct label *label)
{
struct cache_info *info = (struct cache_info *) label->info;
if (info->mdas.n)
del_mdas(&info->mdas);
if (info->das.n)
del_das(&info->das);
}
static void _destroy(struct labeller *l)
{
dbg_free(l);
}
struct label_ops _text_ops = {
can_handle:_can_handle,
write:_write,
read:_read,
verify:_can_handle,
initialise_label:_initialise_label,
destroy_label:_destroy_label,
destroy:_destroy
};
struct labeller *text_labeller_create(struct format_type *fmt)
{
struct labeller *l;
if (!(l = dbg_malloc(sizeof(*l)))) {
log_err("Couldn't allocate labeller object.");
return NULL;
}
l->ops = &_text_ops;
l->private = (void *) fmt;
return l;
}

View File

@@ -4,10 +4,18 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "label.h"
#include "list.h"
#include "dbg_malloc.h"
#include "log.h"
#include "crc.h"
#include "xlate.h"
#include "cache.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
/* FIXME Allow for larger labels? Restricted to single sector currently */
/*
* Internal labeller struct.
@@ -58,6 +66,7 @@ void label_exit(void)
for (c = _labellers.n; c != &_labellers; c = n) {
n = c->n;
li = list_item(c, struct labeller_i);
li->l->ops->destroy(li->l);
_free_li(li);
}
}
@@ -89,64 +98,257 @@ struct labeller *label_get_handler(const char *name)
return NULL;
}
static struct labeller *_find_labeller(struct device *dev)
static struct labeller *_find_labeller(struct device *dev, char *buf,
uint64_t *label_sector)
{
struct list *lih;
struct labeller_i *li;
struct labeller *r = NULL;
int already_open;
struct label_header *lh;
uint64_t sector;
int found = 0;
char readbuf[LABEL_SCAN_SIZE];
list_iterate(lih, &_labellers) {
li = list_item(lih, struct labeller_i);
if (li->l->ops->can_handle(li->l, dev))
return li->l;
already_open = dev_is_open(dev);
if (!already_open && !dev_open(dev, O_RDONLY)) {
stack;
return NULL;
}
log_debug("No label on device '%s'.", dev_name(dev));
return NULL;
if (dev_read(dev, 0, LABEL_SCAN_SIZE, readbuf) != LABEL_SCAN_SIZE) {
log_debug("%s: Failed to read label area", dev_name(dev));
goto out;
}
/* Scan first few sectors for a valid label */
for (sector = 0; sector < LABEL_SCAN_SECTORS;
sector += LABEL_SIZE >> SECTOR_SHIFT) {
lh = (struct label_header *) (readbuf +
(sector << SECTOR_SHIFT));
if (!strncmp(lh->id, LABEL_ID, sizeof(lh->id))) {
if (found) {
log_error("Ignoring additional label on %s at "
"sector %" PRIu64, dev_name(dev),
sector);
}
if (xlate64(lh->sector_xl) != sector) {
log_info("%s: Label for sector %" PRIu64
" found at sector %" PRIu64
" - ignoring", dev_name(dev),
xlate64(lh->sector_xl), sector);
continue;
}
if (calc_crc(INITIAL_CRC, &lh->offset_xl, LABEL_SIZE -
((void *) &lh->offset_xl - (void *) lh)) !=
xlate32(lh->crc_xl)) {
log_info("Label checksum incorrect on %s - "
"ignoring", dev_name(dev));
continue;
}
if (found)
continue;
}
list_iterate(lih, &_labellers) {
li = list_item(lih, struct labeller_i);
if (li->l->ops->can_handle(li->l, (char *) lh, sector)) {
log_very_verbose("%s: %s label detected",
dev_name(dev), li->name);
if (found) {
log_error("Ignoring additional label "
"on %s at sector %" PRIu64,
dev_name(dev), sector);
continue;
}
r = li->l;
memcpy(buf, lh, LABEL_SIZE);
if (label_sector)
*label_sector = sector;
found = 1;
break;
}
}
}
if (!found)
log_very_verbose("%s: No label detected", dev_name(dev));
out:
if (!already_open && !dev_close(dev))
stack;
return r;
}
/* FIXME Also wipe associated metadata area headers? */
int label_remove(struct device *dev)
{
struct labeller *l;
char buf[LABEL_SIZE];
char readbuf[LABEL_SCAN_SIZE];
int r = 1;
uint64_t sector;
int wipe;
struct list *lih;
struct labeller_i *li;
struct label_header *lh;
if (!(l = _find_labeller(dev))) {
memset(buf, 0, LABEL_SIZE);
log_very_verbose("Scanning for labels to wipe from %s", dev_name(dev));
if (!dev_open(dev, O_RDWR)) {
stack;
return 0;
}
return l->ops->remove(l, dev);
}
if (dev_read(dev, 0, LABEL_SCAN_SIZE, readbuf) != LABEL_SCAN_SIZE) {
log_debug("%s: Failed to read label area", dev_name(dev));
goto out;
}
int label_read(struct device *dev, struct label **result)
{
int r;
struct list *lih;
struct labeller_i *li;
/* Scan first few sectors for anything looking like a label */
for (sector = 0; sector < LABEL_SCAN_SECTORS;
sector += LABEL_SIZE >> SECTOR_SHIFT) {
lh = (struct label_header *) (readbuf +
(sector << SECTOR_SHIFT));
list_iterate(lih, &_labellers) {
li = list_item(lih, struct labeller_i);
if ((r = li->l->ops->read(li->l, dev, result))) {
(*result)->labeller = li->l;
return r;
wipe = 0;
if (!strncmp(lh->id, LABEL_ID, sizeof(lh->id))) {
if (xlate64(lh->sector_xl) == sector)
wipe = 1;
} else {
list_iterate(lih, &_labellers) {
li = list_item(lih, struct labeller_i);
if (li->l->ops->can_handle(li->l, (char *) lh,
sector)) {
wipe = 1;
break;
}
}
}
if (wipe) {
log_info("%s: Wiping label at sector %" PRIu64,
dev_name(dev), sector);
if (dev_write(dev, sector << SECTOR_SHIFT, LABEL_SIZE,
buf) != LABEL_SIZE) {
log_error("Failed to remove label from %s at "
"sector %" PRIu64, dev_name(dev),
sector);
r = 0;
}
}
}
log_debug("No label on device '%s'.", dev_name(dev));
return 0;
out:
if (!dev_close(dev))
stack;
return r;
}
/* FIXME Avoid repeated re-reading if cache lock held */
int label_read(struct device *dev, struct label **result)
{
char buf[LABEL_SIZE];
struct labeller *l;
uint64_t sector;
int r;
if (!(l = _find_labeller(dev, buf, &sector))) {
stack;
return 0;
}
if ((r = l->ops->read(l, dev, buf, result)) && result && *result)
(*result)->sector = sector;
return r;
}
/* Caller may need to use label_get_handler to create label struct! */
int label_write(struct device *dev, struct label *label)
{
char buf[LABEL_SIZE];
struct label_header *lh = (struct label_header *) buf;
int r = 1;
int already_open;
if ((LABEL_SIZE + (label->sector << SECTOR_SHIFT)) > LABEL_SCAN_SIZE) {
log_error("Label sector %" PRIu64 " beyond range (%ld)",
label->sector, LABEL_SCAN_SECTORS);
return 0;
}
memset(buf, 0, LABEL_SIZE);
strncpy(lh->id, LABEL_ID, sizeof(lh->id));
lh->sector_xl = xlate64(label->sector);
lh->offset_xl = xlate32(sizeof(*lh));
if (!label->labeller->ops->write(label, buf))
return 0;
lh->crc_xl = xlate32(calc_crc(INITIAL_CRC, &lh->offset_xl, LABEL_SIZE -
((void *) &lh->offset_xl - (void *) lh)));
already_open = dev_is_open(dev);
if (!already_open && dev_open(dev, O_RDWR)) {
stack;
return 0;
}
log_info("%s: Writing label to sector %" PRIu64, dev_name(dev),
label->sector);
if (dev_write(dev, label->sector << SECTOR_SHIFT, LABEL_SIZE, buf) !=
LABEL_SIZE) {
log_debug("Failed to write label to %s", dev_name(dev));
r = 0;
}
if (!already_open && dev_close(dev))
stack;
return r;
}
int label_verify(struct device *dev)
{
struct labeller *l;
char buf[LABEL_SIZE];
uint64_t sector;
if (!(l = _find_labeller(dev))) {
if (!(l = _find_labeller(dev, buf, &sector))) {
stack;
return 0;
}
return l->ops->verify(l, dev);
return l->ops->verify(l, buf, sector);
}
void label_destroy(struct label *lab)
void label_destroy(struct label *label)
{
lab->labeller->ops->destroy_label(lab->labeller, lab);
label->labeller->ops->destroy_label(label->labeller, label);
dbg_free(label);
}
struct label *label_create(struct labeller *labeller)
{
struct label *label;
if (!(label = dbg_malloc(sizeof(*label)))) {
log_error("label allocaction failed");
return NULL;
}
memset(label, 0, sizeof(*label));
label->labeller = labeller;
labeller->ops->initialise_label(labeller, label);
return label;
}

View File

@@ -7,18 +7,31 @@
#ifndef _LVM_LABEL_H
#define _LVM_LABEL_H
#include "cache.h"
#include "lvm-types.h"
#include "uuid.h"
#include "device.h"
#define LABEL_ID "LABELONE"
#define LABEL_SIZE SECTOR_SIZE /* Think very carefully before changing this */
#define LABEL_SCAN_SECTORS 4L
#define LABEL_SCAN_SIZE (LABEL_SCAN_SECTORS << SECTOR_SHIFT)
/* On disk - 32 bytes */
struct label_header {
uint8_t id[8]; /* LABELONE */
uint64_t sector_xl; /* Sector number of this label */
uint32_t crc_xl; /* From next field to end of sector */
uint32_t offset_xl; /* Offset from start of struct to contents */
uint8_t type[8]; /* LVM2 001 */
} __attribute__ ((packed));
/* In core */
struct label {
struct id id;
char volume_type[32];
uint32_t version[3];
void *extra_info;
char type[8];
uint64_t sector;
struct labeller *labeller;
void *info;
};
struct labeller;
@@ -27,39 +40,38 @@ struct label_ops {
/*
* Is the device labelled with this format ?
*/
int (*can_handle)(struct labeller *l, struct device *dev);
int (*can_handle) (struct labeller * l, char *buf, uint64_t sector);
/*
* Write a label to a volume.
*/
int (*write)(struct labeller *l,
struct device *dev, struct label *label);
/*
* Remove a label from a device.
*/
int (*remove)(struct labeller *l, struct device *dev);
int (*write) (struct label * label, char *buf);
/*
* Read a label from a volume.
*/
int (*read)(struct labeller *l,
struct device *dev, struct label **label);
int (*read) (struct labeller * l, struct device * dev,
char *buf, struct label ** label);
/*
* Additional consistency checks for the paranoid.
*/
int (*verify)(struct labeller *l, struct device *dev);
int (*verify) (struct labeller * l, char *buf, uint64_t sector);
/*
* Populate label_type etc.
*/
int (*initialise_label) (struct labeller * l, struct label * label);
/*
* Destroy a previously read label.
*/
void (*destroy_label)(struct labeller *l, struct label *label);
void (*destroy_label) (struct labeller * l, struct label * label);
/*
* Destructor.
*/
void (*destroy)(struct labeller *l);
void (*destroy) (struct labeller * l);
};
struct labeller {
@@ -67,7 +79,6 @@ struct labeller {
void *private;
};
int label_init(void);
void label_exit(void);
@@ -77,14 +88,9 @@ struct labeller *label_get_handler(const char *name);
int label_remove(struct device *dev);
int label_read(struct device *dev, struct label **result);
int label_write(struct device *dev, struct label *label);
int label_verify(struct device *dev);
void label_destroy(struct label *lab);
/*
* We'll support two label types: the 'pretend the
* LVM1 pv structure at the begining of the disk
* is a label' hack, and pjc's 1 sector labels at
* the front and back of the device.
*/
struct label *label_create(struct labeller *labeller);
void label_destroy(struct label *label);
#endif

View File

@@ -1,569 +0,0 @@
/*
* Copyright (C) 2001-2002 Sistina Software
*
* This file is released under the LGPL.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include "device.h"
#include "dev-cache.h"
#include "log.h"
#include "pool.h"
#include "dbg_malloc.h"
#include "filter.h"
#include "label.h"
#include "lvm2_label.h"
#include "xlate.h"
/* Label Magic is "LnXl" - error: imagination failure */
#define LABEL_MAGIC 0x6c586e4c
/* Size of blocks that dev_get_size() returns the number of */
#define BLOCK_SIZE 512
/* This is just the "struct lvm2_label" with the data pointer removed */
struct label_ondisk {
uint32_t magic;
uint32_t crc;
uint64_t label1_loc;
uint64_t label2_loc;
uint16_t datalen;
uint16_t pad;
uint32_t version[3];
char disk_type[32];
};
struct filter_private {
void *mem;
char disk_type[32];
uint32_t version[3];
int version_match;
};
/* Calculate CRC32 of a buffer */
static uint32_t crc32(uint32_t initial, const unsigned char *databuf,
size_t datalen)
{
static const u_int crctab[] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};
uint32_t idx, crc = initial;
for (idx = 0; idx < datalen; idx++) {
crc ^= *databuf++;
crc = (crc >> 4) ^ crctab[crc & 0xf];
crc = (crc >> 4) ^ crctab[crc & 0xf];
}
return crc;
}
/* Calculate crc */
static uint32_t calc_crc(struct label_ondisk *label, char *data)
{
uint32_t crcval = 0xffffffff;
crcval = crc32(crcval, (char *) &label->magic, sizeof(label->magic));
crcval =
crc32(crcval, (char *) &label->label1_loc,
sizeof(label->label1_loc));
crcval =
crc32(crcval, (char *) &label->label2_loc,
sizeof(label->label2_loc));
crcval =
crc32(crcval, (char *) &label->datalen, sizeof(label->datalen));
crcval =
crc32(crcval, (char *) &label->version, sizeof(label->version));
crcval =
crc32(crcval, (char *) label->disk_type, strlen(label->disk_type));
crcval = crc32(crcval, (char *) data, label->datalen);
return crcval;
}
/* Calculate the locations we should find the labels in */
static inline void get_label_locations(uint64_t size, uint32_t sectsize,
long *first, long *second)
{
*first = sectsize;
*second = size * BLOCK_SIZE - sectsize;
}
/* Read a label off disk */
static int lvm2_label_read(struct labeller *l, struct device *dev,
struct label **label)
{
uint64_t size;
uint32_t sectsize;
char *block;
struct label_ondisk *ondisk;
int status;
int iter;
long offset[2];
if (!dev_get_size(dev, &size))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
return 0;
if (!dev_open(dev, O_RDONLY))
return 0;
block = dbg_malloc(sectsize);
if (!block) {
stack;
return 0;
}
ondisk = (struct label_ondisk *) block;
get_label_locations(size, sectsize, &offset[0], &offset[1]);
/* If the first label is bad then use the second */
for (iter = 0; iter <= 1; iter++) {
status = dev_read(dev, offset[iter], sectsize, block);
if (status) {
struct label *incore;
int i;
int found_nul;
/* If the MAGIC doesn't match there's no point in
carrying on */
if (xlate32(ondisk->magic) != LABEL_MAGIC)
continue;
/* Look for a NUL in the disk_type string so we don't
SEGV is something has gone horribly wrong */
found_nul = 0;
for (i = 0; i < sizeof(ondisk->disk_type); i++)
if (ondisk->disk_type[i] == '\0')
found_nul = 1;
if (!found_nul)
continue;
incore = dbg_malloc(sizeof(struct label));
if (incore == NULL) {
return 0;
}
/* Copy and convert endianness */
strncpy(incore->volume_type, ondisk->disk_type,
sizeof(incore->volume_type));
incore->version[0] = xlate32(ondisk->version[0]);
incore->version[1] = xlate32(ondisk->version[1]);
incore->version[2] = xlate32(ondisk->version[2]);
incore->extra_len = xlate16(ondisk->datalen);
incore->extra_info =
block + sizeof(struct label_ondisk);
/* Make sure datalen is a sensible size too */
if (incore->extra_len > sectsize)
continue;
/* Check Crc */
if (xlate32(ondisk->crc) !=
calc_crc(ondisk, incore->extra_info)) {
log_error
("Crc %d on device %s does not match. got %x, expected %x",
iter, dev_name(dev), xlate32(ondisk->crc),
calc_crc(ondisk, incore->extra_info));
continue;
}
/* Check label locations match our view of the device */
if (xlate64(ondisk->label1_loc) != offset[0])
log_error
("Label 1 location is wrong in label %d - check block size of the device\n",
iter);
if (xlate64(ondisk->label2_loc) != offset[1])
log_error
("Label 2 location is wrong in label %d - the size of the device must have changed\n",
iter);
/* Copy to user's data area */
*label = incore;
incore->extra_info = dbg_malloc(incore->extra_len);
if (!incore->extra_info) {
stack;
return 0;
}
memcpy(incore->extra_info,
block + sizeof(struct label_ondisk),
incore->extra_len);
dbg_free(block);
dev_close(dev);
return 1;
}
}
dbg_free(block);
dev_close(dev);
return 0;
}
/* Write a label to a device */
static int lvm2_label_write(struct labeller *l, struct device *dev,
struct label *label)
{
uint64_t size;
uint32_t sectsize;
char *block;
struct label_ondisk *ondisk;
int status1, status2;
long offset[2];
if (!dev_get_size(dev, &size))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
return 0;
/* Can the metata fit in the remaining space ? */
if (label->extra_len > sectsize - sizeof(struct label_ondisk))
return 0;
block = dbg_malloc(sizeof(struct label_ondisk) + label->extra_len);
if (!block) {
stack;
return 0;
}
ondisk = (struct label_ondisk *) block;
get_label_locations(size, sectsize, &offset[0], &offset[1]);
/* Make into ondisk format */
ondisk->magic = xlate32(LABEL_MAGIC);
ondisk->version[0] = xlate32(label->version[0]);
ondisk->version[1] = xlate32(label->version[1]);
ondisk->version[2] = xlate32(label->version[2]);
ondisk->label1_loc = xlate64(offset[0]);
ondisk->label2_loc = xlate64(offset[1]);
ondisk->datalen = xlate16(label->extra_len);
strncpy(ondisk->disk_type, label->volume_type,
sizeof(ondisk->disk_type));
memcpy(block + sizeof(struct label_ondisk), label->extra_info,
label->extra_len);
ondisk->crc = xlate32(calc_crc(ondisk, label->extra_info));
/* Write metadata to disk */
if (!dev_open(dev, O_RDWR)) {
dbg_free(block);
return 0;
}
status1 =
dev_write(dev, offset[0],
sizeof(struct label_ondisk) + label->extra_len, block);
if (!status1)
log_error("Error writing label 1\n");
/* Write another at the end of the device */
status2 =
dev_write(dev, offset[1],
sizeof(struct label_ondisk) + label->extra_len, block);
if (!status2) {
char zerobuf[sizeof(struct label_ondisk)];
log_error("Error writing label 2\n");
/* Wipe the first label so it doesn't get confusing */
memset(zerobuf, 0, sizeof(struct label_ondisk));
if (!dev_write
(dev, offset[0], sizeof(struct label_ondisk),
zerobuf)) log_error("Error erasing label 1\n");
}
dbg_free(block);
dev_close(dev);
return ((status1 != 0) && (status2 != 0));
}
/* Return 1 for Yes, 0 for No */
static int lvm2_is_labelled(struct labeller *l, struct device *dev)
{
struct label *label;
int status;
status = lvm2_label_read(l, dev, &label);
if (status)
label_free(label);
return status;
}
/* Check the device is labelled and has the right format_type */
static int _accept_format(struct dev_filter *f, struct device *dev)
{
struct label *l;
int status;
struct filter_private *fp = (struct filter_private *) f->private;
status = lvm2_label_read(NULL, dev, &l);
if (status) {
if (strcmp(l->volume_type, fp->disk_type) == 0) {
switch (fp->version_match) {
case VERSION_MATCH_EQUAL:
if (l->version[0] == fp->version[0] &&
l->version[1] == fp->version[1] &&
l->version[2] == fp->version[2])
return 1;
break;
case VERSION_MATCH_LESSTHAN:
if (l->version[0] == fp->version[0] &&
l->version[1] < fp->version[1])
return 1;
break;
case VERSION_MATCH_LESSEQUAL:
if (l->version[0] == fp->version[0] &&
l->version[1] <= fp->version[1])
return 1;
break;
case VERSION_MATCH_ANY:
return 1;
}
}
label_free(l);
}
return 0;
}
/* We just want to know if it's labelled or not */
static int _accept_label(struct dev_filter *f, struct device *dev)
{
return lvm2_is_labelled(NULL, dev);
}
static void _destroy(struct dev_filter *f)
{
struct filter_private *fp = (struct filter_private *) f->private;
}
/* A filter to find devices with a particular label type on them */
struct dev_filter *lvm2_label_format_filter_create(char *disk_type,
uint32_t version[3],
int match_type)
{
struct pool *mem;
struct filter_private *fp;
struct dev_filter *f;
/* Validate the match type */
if (match_type != VERSION_MATCH_EQUAL &&
match_type != VERSION_MATCH_LESSTHAN &&
match_type != VERSION_MATCH_LESSEQUAL &&
match_type != VERSION_MATCH_ANY)
return 0;
mem = pool_create(10 * 1024);
if (!mem) {
stack;
return NULL;
}
if (!(f = pool_zalloc(mem, sizeof(*f)))) {
stack;
goto bad;
}
if (!(fp = pool_zalloc(mem, sizeof(*fp)))) {
stack;
goto bad;
}
fp->mem = mem;
strcpy(fp->disk_type, disk_type);
fp->version[0] = version[0];
fp->version[1] = version[1];
fp->version[2] = version[2];
fp->version_match = match_type;
f->passes_filter = _accept_format;
f->destroy = _destroy;
f->private = fp;
return f;
bad:
pool_destroy(mem);
return NULL;
}
/* A filter to find devices with any label on them */
struct dev_filter *lvm2_label_filter_create()
{
struct pool *mem = pool_create(10 * 1024);
struct filter_private *fp;
struct dev_filter *f;
if (!mem) {
stack;
return NULL;
}
if (!(f = pool_zalloc(mem, sizeof(*f)))) {
stack;
goto bad;
}
if (!(fp = pool_zalloc(mem, sizeof(*fp)))) {
stack;
goto bad;
}
fp->mem = mem;
f->passes_filter = _accept_label;
f->destroy = _destroy;
f->private = fp;
return f;
bad:
pool_destroy(mem);
return NULL;
}
/* Return 1 if both labels are identical, 0 if not or there was an error */
static int lvm2_labels_match(struct labeller *l, struct device *dev)
{
uint64_t size;
uint32_t sectsize;
char *block1;
char *block2;
struct label_ondisk *ondisk1;
struct label_ondisk *ondisk2;
int status = 0;
long offset[2];
if (!dev_get_size(dev, &size))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
return 0;
/* Allocate some space for the blocks we are going to read in */
block1 = dbg_malloc(sectsize);
if (!block1) {
stack;
return 0;
}
block2 = dbg_malloc(sectsize);
if (!block2) {
stack;
dbg_free(block1);
return 0;
}
ondisk1 = (struct label_ondisk *) block1;
ondisk2 = (struct label_ondisk *) block2;
get_label_locations(size, sectsize, &offset[0], &offset[1]);
/* Fetch em */
if (!dev_open(dev, O_RDONLY))
goto finish;
if (!dev_read(dev, offset[0], sectsize, block1))
goto finish;
if (!dev_read(dev, offset[1], sectsize, block2))
goto finish;
dev_close(dev);
/* Is it labelled? */
if (xlate32(ondisk1->magic) != LABEL_MAGIC)
goto finish;
/* Compare the whole structs */
if (memcmp(ondisk1, ondisk2, sizeof(struct label_ondisk)) != 0)
goto finish;
/* OK, check the data area */
if (memcmp(block1 + sizeof(struct label_ondisk),
block2 + sizeof(struct label_ondisk),
xlate16(ondisk1->datalen)) != 0)
goto finish;
/* They match !! */
status = 1;
finish:
dbg_free(block2);
dbg_free(block1);
return status;
}
static int lvm2_label_remove(struct labeller *l, struct device *dev)
{
uint64_t size;
uint32_t sectsize;
char block[BLOCK_SIZE];
int status1, status2;
long offset[2];
if (!dev_get_size(dev, &size))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
return 0;
if (!dev_open(dev, O_RDWR)) {
dbg_free(block);
return 0;
}
get_label_locations(size, sectsize, &offset[0], &offset[1]);
memset(block, 0, BLOCK_SIZE);
/* Blank out the first label */
status1 = dev_write(dev, offset[0], BLOCK_SIZE, block);
if (!status1)
log_error("Error erasing label 1\n");
/* ...and the other at the end of the device */
status2 = dev_write(dev, offset[1], BLOCK_SIZE, block);
if (!status2)
log_error("Error erasing label 2\n");
dev_close(dev);
return ((status1 != 0) && (status2 != 0));
}
static void lvm2_label_destroy(struct labeller *l)
{
}
static struct label_ops handler_ops = {
can_handle: lvm2_is_labelled,
write: lvm2_label_write,
remove: lvm2_label_remove,
read: lvm2_label_read,
verify: lvm2_labels_match,
destroy: lvm2_label_destroy,
};
static struct labeller this_labeller = {
private: NULL,
ops: &handler_ops,
};
/* Don't know how this gets called... */
void lvm2_label_init()
{
label_register_handler("LVM2", &this_labeller);
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
*/
struct lvm2_label
{
uint32_t magic;
uint32_t crc;
uint64_t label1_loc;
uint64_t label2_loc;
uint16_t datalen;
char disk_type[32];
uint32_t version[3];
char *data;
};
#define VERSION_MATCH_EQUAL 1
#define VERSION_MATCH_LESSTHAN 2
#define VERSION_MATCH_LESSEQUAL 3
#define VERSION_MATCH_ANY 4
extern struct dev_filter *lvm2_label_filter_create();
extern struct dev_filter *lvm2_label_format_filter_create(char *disk_type, uint32_t version[3], int match_type);

View File

@@ -1,99 +0,0 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#ifndef _LVM_UUID_MAP_H
#define _LVM_UUID_MAP_H
#include "uuid-map.h"
#include "dev-cache.h"
#include "dbg_malloc.h"
#include "log.h"
#include "label.h"
#include "pool.h"
struct uuid_map {
struct dev_filter *filter;
};
struct uuid_map *uuid_map_create(struct dev_filter *devices)
{
struct uuid_map *um;
if (!(um = dbg_malloc(sizeof(*um)))) {
log_err("Couldn't allocate uuid_map object.");
return NULL;
}
um->filter = devices;
return um;
}
void uuid_map_destroy(struct uuid_map *um)
{
dbg_free(um);
}
/*
* Simple, non-caching implementation to start with.
*/
struct device *uuid_map_lookup(struct uuid_map *um, struct id *id)
{
struct dev_iter *iter;
struct device *dev;
struct label *lab;
if (!(iter = dev_iter_create(um->filter))) {
stack;
return NULL;
}
while ((dev = dev_iter_get(iter))) {
if (!label_read(dev, &lab))
continue;
if (id_equal(id, &lab->id)) {
label_destroy(lab);
break;
}
label_destroy(lab);
}
dev_iter_destroy(iter);
return dev;
}
struct id *uuid_map_lookup_label(struct pool *mem, struct uuid_map *um,
const char *name)
{
struct device *dev;
struct label *lab;
struct id *id;
if (!(dev = dev_cache_get(name, um->filter))) {
stack;
return NULL;
}
if (!label_read(dev, &lab)) {
stack;
return NULL;
}
if (!(id = pool_alloc(mem, sizeof(*id)))) {
stack;
label_destroy(lab);
return NULL;
}
memcpy(id, &lab->id, sizeof(*id));
label_destroy(lab);
return id;
}
#endif

View File

@@ -1,29 +0,0 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#ifndef _LVM_UUID_MAP_H
#define _LVM_UUID_MAP_H
#include "uuid.h"
#include "dev-cache.h"
#include "pool.h"
/*
* Holds a mapping from uuid -> device.
*/
struct uuid_map;
struct uuid_map *uuid_map_create(struct dev_filter *devices);
void uuid_map_destroy(struct uuid_map *um);
/*
* Find the device with a particular uuid.
*/
struct device *uuid_map_lookup(struct uuid_map *um, struct id *id);
struct id *uuid_map_lookup_label(struct pool *mem, struct uuid_map *um,
const char *name);
#endif

View File

@@ -5,111 +5,72 @@
*
*/
#include "log.h"
#include "locking.h"
#include "lib.h"
#include "locking_types.h"
#include "activate.h"
#include "config.h"
#include "defaults.h"
#include "lvm-file.h"
#include "lvm-string.h"
#include "dbg_malloc.h"
#include "sharedlib.h"
#include <limits.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <signal.h>
static void *locking_module = NULL;
static void (*end_fn) (void) = NULL;
static int (*lock_fn) (struct cmd_context * cmd, const char *resource,
int flags) = NULL;
static int (*init_fn) (int type, struct config_file * cf) = NULL;
static void *_locking_lib = NULL;
static void (*_end_fn) (void) = NULL;
static int (*_lock_fn) (struct cmd_context * cmd, const char *resource,
int flags) = NULL;
static int (*_init_fn) (int type, struct config_tree * cf) = NULL;
static int lock_resource(struct cmd_context *cmd, const char *resource,
int flags)
static int _lock_resource(struct cmd_context *cmd, const char *resource,
int flags)
{
if (lock_fn)
return lock_fn(cmd, resource, flags);
if (_lock_fn)
return _lock_fn(cmd, resource, flags);
else
return 0;
}
static void fin_external_locking(void)
static void _fin_external_locking(void)
{
if (end_fn)
end_fn();
if (_end_fn)
_end_fn();
dlclose(locking_module);
dlclose(_locking_lib);
locking_module = NULL;
end_fn = NULL;
lock_fn = NULL;
_locking_lib = NULL;
_init_fn = NULL;
_end_fn = NULL;
_lock_fn = NULL;
}
int init_external_locking(struct locking_type *locking, struct config_file *cf)
int init_external_locking(struct locking_type *locking, struct config_tree *cf)
{
char _lock_lib[PATH_MAX];
const char *libname;
if (locking_module) {
if (_locking_lib) {
log_error("External locking already initialised");
return 1;
}
locking->lock_resource = lock_resource;
locking->fin_locking = fin_external_locking;
/* Get locking module name from config file */
strncpy(_lock_lib, find_config_str(cf->root, "global/locking_library",
'/', "lvm2_locking.so"),
sizeof(_lock_lib));
locking->lock_resource = _lock_resource;
locking->fin_locking = _fin_external_locking;
/* If there is a module_dir in the config file then
look for the locking module in there first and then
using the normal dlopen(3) mechanism of looking
down LD_LIBRARY_PATH and /lib, /usr/lib.
If course, if the library name starts with a slash then
just use the name... */
if (_lock_lib[0] != '/') {
struct stat st;
char _lock_lib1[PATH_MAX];
libname = find_config_str(cf->root, "global/locking_library", '/',
DEFAULT_LOCKING_LIB);
lvm_snprintf(_lock_lib1, sizeof(_lock_lib1),
"%s/%s",
find_config_str(cf->root, "global/module_dir",
'/', "RUBBISH"), _lock_lib);
/* Does it exist ? */
if (stat(_lock_lib1, &st) == 0) {
strcpy(_lock_lib, _lock_lib1);
}
}
log_very_verbose("Opening locking library %s", _lock_lib);
locking_module = dlopen(_lock_lib, RTLD_LAZY);
if (!locking_module) {
log_error("Unable to open external locking module %s",
_lock_lib);
if (!(_locking_lib = load_shared_library(cf, libname, "locking"))) {
stack;
return 0;
}
/* Get the functions we need */
init_fn = dlsym(locking_module, "init_locking");
lock_fn = dlsym(locking_module, "lock_resource");
end_fn = dlsym(locking_module, "end_locking");
/* Are they all there ? */
if (!end_fn || !init_fn || !lock_fn) {
log_error ("Shared library %s does not contain locking "
"functions", _lock_lib);
dlclose(locking_module);
if (!(_init_fn = dlsym(_locking_lib, "init_locking")) ||
!(_lock_fn = dlsym(_locking_lib, "lock_resource")) ||
!(_end_fn = dlsym(_locking_lib, "end_locking"))) {
log_error("Shared library %s does not contain locking "
"functions", libname);
dlclose(_locking_lib);
_locking_lib = NULL;
return 0;
}
log_verbose("Opened external locking module %s", _lock_lib);
return init_fn(2, cf);
log_verbose("Loaded external locking library %s", libname);
return _init_fn(2, cf);
}

View File

@@ -5,7 +5,7 @@
*
*/
#include "log.h"
#include "lib.h"
#include "locking.h"
#include "locking_types.h"
#include "activate.h"
@@ -13,11 +13,9 @@
#include "defaults.h"
#include "lvm-file.h"
#include "lvm-string.h"
#include "dbg_malloc.h"
#include <limits.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>
@@ -117,13 +115,16 @@ static int _lock_file(const char *file, int flags)
struct lock_list *ll;
struct stat buf1, buf2;
char state;
switch (flags & LCK_TYPE_MASK) {
case LCK_READ:
operation = LOCK_SH;
state = 'R';
break;
case LCK_WRITE:
operation = LOCK_EX;
state = 'W';
break;
case LCK_UNLOCK:
return _release_lock(file);
@@ -142,7 +143,8 @@ static int _lock_file(const char *file, int flags)
ll->lf = -1;
log_very_verbose("Locking %s", ll->res);
log_very_verbose("Locking %s %c%c", ll->res, state,
flags & LCK_NONBLOCK ? ' ' : 'B');
do {
if (ll->lf > -1)
close(ll->lf);
@@ -181,7 +183,7 @@ static int _lock_file(const char *file, int flags)
return 0;
}
int lock_resource(struct cmd_context *cmd, const char *resource, int flags)
int file_lock_resource(struct cmd_context *cmd, const char *resource, int flags)
{
char lockfile[PATH_MAX];
@@ -197,10 +199,6 @@ int lock_resource(struct cmd_context *cmd, const char *resource, int flags)
return 0;
break;
case LCK_LV:
/* Skip if driver isn't loaded */
/* FIXME Use /proc/misc instead? */
if (!driver_version(NULL, 0))
return 1;
switch (flags & LCK_TYPE_MASK) {
case LCK_UNLOCK:
if (!lv_resume_if_active(cmd, resource))
@@ -231,9 +229,9 @@ int lock_resource(struct cmd_context *cmd, const char *resource, int flags)
return 1;
}
int init_file_locking(struct locking_type *locking, struct config_file *cf)
int init_file_locking(struct locking_type *locking, struct config_tree *cf)
{
locking->lock_resource = lock_resource;
locking->lock_resource = file_lock_resource;
locking->fin_locking = fin_file_locking;
/* Get lockfile directory from config file */
@@ -244,6 +242,10 @@ int init_file_locking(struct locking_type *locking, struct config_file *cf)
if (!create_dir(_lock_dir))
return 0;
/* Trap a read-only file system */
if ((access(_lock_dir, R_OK | W_OK | X_OK) == -1) && (errno == EROFS))
return 0;
list_init(&_lock_list);
if (sigfillset(&_intsigset) || sigfillset(&_fullsigset)) {

View File

@@ -5,13 +5,16 @@
*
*/
#include "log.h"
#include "lib.h"
#include "locking.h"
#include "locking_types.h"
#include "lvm-string.h"
#include "activate.h"
#include "toolcontext.h"
#include <signal.h>
#include <sys/stat.h>
#include <limits.h>
static struct locking_type _locking;
static sigset_t _oldset;
@@ -68,31 +71,40 @@ static inline void _update_lock_count(int flags)
/*
* Select a locking type
*/
int init_locking(int type, struct config_file *cf)
int init_locking(int type, struct config_tree *cf)
{
switch (type) {
case 0:
init_no_locking(&_locking, cf);
log_print("WARNING: Locking disabled. Be careful! "
"This could corrupt your metadata.");
break;
return 1;
case 1:
if (!init_file_locking(&_locking, cf))
return 0;
break;
log_very_verbose("File-based locking enabled.");
break;
return 1;
case 2:
if (!init_external_locking(&_locking, cf))
return 0;
break;
log_very_verbose("External locking enabled.");
break;
return 1;
default:
log_error("Unknown locking type requested.");
return 0;
}
if (!ignorelockingfailure())
return 0;
/* FIXME Ensure only read ops are permitted */
log_verbose("Locking disabled - only read operations permitted.");
init_no_locking(&_locking, cf);
return 1;
}
@@ -101,6 +113,36 @@ void fin_locking(void)
_locking.fin_locking();
}
/*
* Does the LVM1 driver know of this VG name?
*/
int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname)
{
struct stat info;
char path[PATH_MAX];
/* We'll allow operations on orphans */
if (!*vgname)
return 1;
if (lvm_snprintf(path, sizeof(path), "%s/lvm/VGs/%s", cmd->proc_dir,
vgname) < 0) {
log_error("LVM1 proc VG pathname too long for %s", vgname);
return 0;
}
if (stat(path, &info) == 0) {
log_error("%s exists: Is the original LVM driver using "
"this volume group?", path);
return 0;
} else if (errno != ENOENT && errno != ENOTDIR) {
log_sys_error("stat", path);
return 0;
}
return 1;
}
/*
* VG locking is by VG name.
* FIXME This should become VG uuid.
@@ -125,8 +167,13 @@ int lock_vol(struct cmd_context *cmd, const char *vol, int flags)
char resource[258];
switch (flags & LCK_SCOPE_MASK) {
case LCK_VG: /* Lock VG to change on-disk metadata. */
case LCK_LV: /* Suspends LV if it's active. */
case LCK_VG:
/* Lock VG to change on-disk metadata. */
/* If LVM1 driver knows about the VG, it can't be accessed. */
if (!check_lvm1_vg_inactive(cmd, vol))
return 0;
case LCK_LV:
/* Suspend LV if it's active. */
strncpy(resource, (char *) vol, sizeof(resource));
break;
default:

View File

@@ -9,7 +9,7 @@
#include "uuid.h"
#include "config.h"
int init_locking(int type, struct config_file *cf);
int init_locking(int type, struct config_tree *cf);
void fin_locking(void);
/*
@@ -24,18 +24,23 @@ void fin_locking(void);
*/
int lock_vol(struct cmd_context *cmd, const char *vol, int flags);
/*
* Does the LVM1 driver have this VG active?
*/
int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
/*
* Lock type - these numbers are the same as VMS and the IBM DLM
*/
#define LCK_TYPE_MASK 0x000000FF
#define LCK_NULL 0x00000000 /* LCK$_NLMODE */
#define LCK_READ 0x00000001 /* LCK$_CRMODE */
/* LCK$_CWMODE */
/* LCK$_PRMODE */
#define LCK_WRITE 0x00000004 /* LCK$_PWMODE */
#define LCK_EXCL 0x00000005 /* LCK$_EXMODE */
#define LCK_UNLOCK 0x00000010 /* This is ours */
#define LCK_NULL 0x00000000 /* LCK$_NLMODE */
#define LCK_READ 0x00000001 /* LCK$_CRMODE */
/* LCK$_CWMODE */
/* LCK$_PRMODE */
#define LCK_WRITE 0x00000004 /* LCK$_PWMODE */
#define LCK_EXCL 0x00000005 /* LCK$_EXMODE */
#define LCK_UNLOCK 0x00000010 /* This is ours */
/*
* Lock scope
@@ -64,4 +69,3 @@ int lock_vol(struct cmd_context *cmd, const char *vol, int flags);
#define unlock_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_UNLOCK)
#define unlock_vg(cmd, vol) lock_vol(cmd, vol, LCK_VG_UNLOCK)

View File

@@ -24,9 +24,9 @@ struct locking_type {
/*
* Locking types
*/
int init_no_locking(struct locking_type *locking, struct config_file *cf);
int init_no_locking(struct locking_type *locking, struct config_tree *cf);
int init_file_locking(struct locking_type *locking, struct config_file *cf);
int init_file_locking(struct locking_type *locking, struct config_tree *cf);
int init_external_locking(struct locking_type *locking, struct config_file *cf);
int init_external_locking(struct locking_type *locking, struct config_tree *cf);

View File

@@ -5,7 +5,7 @@
*
*/
#include "log.h"
#include "lib.h"
#include "locking.h"
#include "locking_types.h"
#include "lvm-string.h"
@@ -51,7 +51,7 @@ static int _no_lock_resource(struct cmd_context *cmd, const char *resource,
return 1;
}
int init_no_locking(struct locking_type *locking, struct config_file *cf)
int init_no_locking(struct locking_type *locking, struct config_tree *cf)
{
locking->lock_resource = _no_lock_resource;
locking->fin_locking = _no_fin_locking;

View File

@@ -4,7 +4,8 @@
* This file is released under the LGPL.
*/
#include "log.h"
#include "lib.h"
#include <stdarg.h>
#include <syslog.h>
@@ -18,10 +19,11 @@ static int _syslog = 0;
static int _indent = 1;
static int _log_cmd_name = 0;
static int _log_suppress = 0;
static int _ignorelockingfailure = 0;
static char _cmd_name[30] = "";
static char _msg_prefix[30] = " ";
void init_log(FILE * fp)
void init_log(FILE *fp)
{
_log = fp;
}
@@ -56,9 +58,9 @@ void init_verbose(int level)
void init_test(int level)
{
if (!_test && level)
log_print("Test mode: Metadata will NOT be updated.");
_test = level;
if (_test)
log_print("Test mode. Metadata will NOT be updated.");
}
void init_partial(int level)
@@ -66,6 +68,11 @@ void init_partial(int level)
_partial = level;
}
void init_ignorelockingfailure(int level)
{
_ignorelockingfailure = level;
}
void init_cmd_name(int status)
{
_log_cmd_name = status;
@@ -100,6 +107,11 @@ int partial_mode()
return _partial;
}
int ignorelockingfailure()
{
return _ignorelockingfailure;
}
void init_debug(int level)
{
_debug_level = level;

View File

@@ -28,8 +28,8 @@
*
*/
#include <stdio.h>
#include <string.h>
#include <stdio.h> /* FILE */
#include <string.h> /* strerror() */
#include <errno.h>
#define _LOG_DEBUG 7
@@ -52,18 +52,20 @@ 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 set_cmd_name(const char *cmd_name);
int test_mode(void);
int partial_mode(void);
int debug_level(void);
int ignorelockingfailure(void);
/* Suppress messages to stdout/stderr */
void log_suppress(int suppress);
void print_log(int level, const char *file, int line, const char *format, ...)
__attribute__ (( format (printf, 4, 5) ));
__attribute__ ((format(printf, 4, 5)));
#define plog(l, x...) print_log(l, __FILE__, __LINE__ , ## x)
@@ -88,9 +90,3 @@ void print_log(int level, const char *file, int line, const char *format, ...)
log_info("%s: %s failed: %s", y, x, strerror(errno))
#endif
/*
* Local variables:
* c-file-style: "linux"
* End:
*/

View File

@@ -4,10 +4,9 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "metadata.h"
#include "pv_map.h"
#include "log.h"
#include "dbg_malloc.h"
#include "lvm-string.h"
#include "toolcontext.h"
@@ -17,7 +16,7 @@
* These functions adjust the pe counts in pv's
* after we've added or removed segments.
*/
static void _get_extents(struct stripe_segment *seg)
static void _get_extents(struct lv_segment *seg)
{
int s, count;
struct physical_volume *pv;
@@ -29,7 +28,7 @@ static void _get_extents(struct stripe_segment *seg)
}
}
static void _put_extents(struct stripe_segment *seg)
static void _put_extents(struct lv_segment *seg)
{
int s, count;
struct physical_volume *pv;
@@ -43,9 +42,9 @@ static void _put_extents(struct stripe_segment *seg)
}
}
static struct stripe_segment *_alloc_segment(struct pool *mem, int stripes)
static struct lv_segment *_alloc_segment(struct pool *mem, int stripes)
{
struct stripe_segment *seg;
struct lv_segment *seg;
uint32_t len = sizeof(*seg) + (stripes * sizeof(seg->area[0]));
if (!(seg = pool_zalloc(mem, len))) {
@@ -58,13 +57,13 @@ static struct stripe_segment *_alloc_segment(struct pool *mem, int stripes)
static int _alloc_stripe_area(struct logical_volume *lv, uint32_t stripes,
uint32_t stripe_size,
struct pv_area **areas, uint32_t * index)
struct pv_area **areas, uint32_t *index)
{
uint32_t count = lv->le_count - *index;
uint32_t per_area = count / stripes;
uint32_t smallest = areas[stripes - 1]->count;
uint32_t s;
struct stripe_segment *seg;
struct lv_segment *seg;
if (smallest < per_area)
per_area = smallest;
@@ -75,6 +74,7 @@ static int _alloc_stripe_area(struct logical_volume *lv, uint32_t stripes,
}
seg->lv = lv;
seg->type = SEG_STRIPED;
seg->le = *index;
seg->len = per_area * stripes;
seg->stripes = stripes;
@@ -169,11 +169,11 @@ static int _alloc_striped(struct logical_volume *lv,
* the complete area then the area is split, otherwise the area
* is unlinked from the pv_map.
*/
static int _alloc_linear_area(struct logical_volume *lv, uint32_t * index,
static int _alloc_linear_area(struct logical_volume *lv, uint32_t *index,
struct pv_map *map, struct pv_area *pva)
{
uint32_t count, remaining;
struct stripe_segment *seg;
struct lv_segment *seg;
count = pva->count;
remaining = lv->le_count - *index;
@@ -186,6 +186,7 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t * index,
}
seg->lv = lv;
seg->type = SEG_STRIPED;
seg->le = *index;
seg->len = count;
seg->stripe_size = 0;
@@ -248,8 +249,8 @@ static int _alloc_contiguous(struct logical_volume *lv,
* Areas just get allocated in order until the lv
* is full.
*/
static int _alloc_simple(struct logical_volume *lv,
struct list *pvms, uint32_t allocated)
static int _alloc_next_free(struct logical_volume *lv,
struct list *pvms, uint32_t allocated)
{
struct list *tmp1, *tmp2;
struct pv_map *pvm;
@@ -302,11 +303,11 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv,
if (stripes > 1)
r = _alloc_striped(lv, pvms, allocated, stripes, stripe_size);
else if (lv->status & ALLOC_CONTIGUOUS)
else if (lv->alloc == ALLOC_CONTIGUOUS)
r = _alloc_contiguous(lv, pvms, allocated);
else if (lv->status & ALLOC_SIMPLE)
r = _alloc_simple(lv, pvms, allocated);
else if (lv->alloc == ALLOC_NEXT_FREE || lv->alloc == ALLOC_DEFAULT)
r = _alloc_next_free(lv, pvms, allocated);
else {
log_error("Unknown allocation policy: "
@@ -322,7 +323,7 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv,
* counts in pv's.
*/
for (segh = lv->segments.p; segh != old_tail; segh = segh->p)
_get_extents(list_item(segh, struct stripe_segment));
_get_extents(list_item(segh, struct lv_segment));
} else {
/*
* Put the segment list back how we found it.
@@ -362,6 +363,7 @@ static char *_generate_lv_name(struct volume_group *vg,
struct logical_volume *lv_create(struct format_instance *fi,
const char *name,
uint32_t status,
alloc_policy_t alloc,
uint32_t stripes,
uint32_t stripe_size,
uint32_t extents,
@@ -422,6 +424,7 @@ struct logical_volume *lv_create(struct format_instance *fi,
}
lv->status = status;
lv->alloc = alloc;
lv->read_ahead = 0;
lv->minor = -1;
lv->size = (uint64_t) extents *vg->extent_size;
@@ -454,12 +457,12 @@ int lv_reduce(struct format_instance *fi,
struct logical_volume *lv, uint32_t extents)
{
struct list *segh;
struct stripe_segment *seg;
struct lv_segment *seg;
uint32_t count = extents;
for (segh = lv->segments.p;
(segh != &lv->segments) && count; segh = segh->p) {
seg = list_item(segh, struct stripe_segment);
seg = list_item(segh, struct lv_segment);
if (seg->len <= count) {
/* remove this segment completely */
@@ -532,7 +535,7 @@ int lv_remove(struct volume_group *vg, struct logical_volume *lv)
/* iterate through the lv's segments freeing off the pe's */
list_iterate(segh, &lv->segments)
_put_extents(list_item(segh, struct stripe_segment));
_put_extents(list_item(segh, struct lv_segment));
vg->lv_count--;
vg->free_count += lv->le_count;

View File

@@ -4,7 +4,7 @@
* This file is released under the LGPL.
*/
#include "log.h"
#include "lib.h"
#include "metadata.h"
/*
@@ -12,12 +12,14 @@
* successfully merged. If the do merge, 'first'
* will be adjusted to contain both areas.
*/
static int _merge(struct stripe_segment *first, struct stripe_segment *second)
static int _merge(struct lv_segment *first, struct lv_segment *second)
{
int s;
uint32_t width;
if (!first ||
(first->type != SEG_STRIPED) ||
(first->type != second->type) ||
(first->stripes != second->stripes) ||
(first->stripe_size != second->stripe_size))
return 0;
@@ -39,10 +41,10 @@ static int _merge(struct stripe_segment *first, struct stripe_segment *second)
int lv_merge_segments(struct logical_volume *lv)
{
struct list *segh;
struct stripe_segment *current, *prev = NULL;
struct lv_segment *current, *prev = NULL;
list_iterate(segh, &lv->segments) {
current = list_item(segh, struct stripe_segment);
current = list_item(segh, struct lv_segment);
if (_merge(prev, current))
list_del(&current->list);

View File

@@ -4,24 +4,21 @@
* This file is released under the LGPL.
*/
#include "log.h"
#include "lib.h"
#include "pool.h"
#include "device.h"
#include "dev-cache.h"
#include "metadata.h"
#include "toolcontext.h"
#include "lvm-string.h"
#include "uuid.h"
#include "vgcache.h"
#include "cache.h"
#include <string.h>
int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
const char *pv_name)
{
struct pv_list *pvl;
struct physical_volume *pv;
struct pool *mem = fi->fmt->cmd->mem;
struct pool *mem = fid->fmt->cmd->mem;
struct list mdas;
log_verbose("Adding physical volume '%s' to volume group '%s'",
pv_name, vg->name);
@@ -31,7 +28,8 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
return 0;
}
if (!(pv = pv_read(fi->fmt->cmd, pv_name))) {
list_init(&mdas);
if (!(pv = pv_read(fid->fmt->cmd, pv_name, &mdas, NULL))) {
log_error("Failed to read existing physical volume '%s'",
pv_name);
return 0;
@@ -43,6 +41,12 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
return 0;
}
if (pv->fmt != fid->fmt) {
log_error("Physical volume %s is of different format type (%s)",
pv_name, pv->fmt->name);
return 0;
}
if (!(pv->vg_name = pool_strdup(mem, vg->name))) {
log_error("vg->name allocation failed for '%s'", pv_name);
return 0;
@@ -58,13 +62,14 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
/*
* The next two fields should be corrected
* by fi->pv_setup.
* by fid->pv_setup.
*/
pv->pe_count = (pv->size - pv->pe_start) / pv->pe_size;
pv->pe_count = (pv->size - pv->pe_start) / vg->extent_size;
pv->pe_alloc_count = 0;
if (!fi->fmt->ops->pv_setup(fi, pv, vg)) {
if (!fid->fmt->ops->pv_setup(fid->fmt, 0, 0, vg->extent_size, 0, 0,
&fid->metadata_areas, pv, vg)) {
log_error("Format-specific setup of physical volume '%s' "
"failed.", pv_name);
return 0;
@@ -93,19 +98,21 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
return 1;
}
int vg_extend(struct format_instance *fi,
int vg_extend(struct format_instance *fid,
struct volume_group *vg, int pv_count, char **pv_names)
{
int i;
/* attach each pv */
for (i = 0; i < pv_count; i++)
if (!_add_pv_to_vg(fi, vg, pv_names[i])) {
if (!_add_pv_to_vg(fid, vg, pv_names[i])) {
log_error("Unable to add physical volume '%s' to "
"volume group '%s'.", pv_names[i], vg->name);
return 0;
}
/* FIXME Decide whether to initialise and add new mdahs to format instance */
return 1;
}
@@ -124,6 +131,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
{
struct volume_group *vg;
struct pool *mem = cmd->mem;
int consistent = 0;
if (!(vg = pool_zalloc(mem, sizeof(*vg)))) {
stack;
@@ -132,7 +140,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
/* is this vg name already in use ? */
init_partial(1);
if (vg_read(cmd, vg_name)) {
if (vg_read(cmd, vg_name, &consistent)) {
log_err("A volume group called '%s' already exists.", vg_name);
goto bad;
}
@@ -198,11 +206,17 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
return NULL;
}
struct physical_volume *pv_create(struct format_instance *fid,
const char *name,
struct id *id, uint64_t size)
/* Sizes in sectors */
struct physical_volume *pv_create(struct format_type *fmt,
struct device *dev,
struct id *id, uint64_t size,
uint64_t pe_start,
uint32_t existing_extent_count,
uint32_t existing_extent_size,
int pvmetadatacopies,
uint64_t pvmetadatasize, struct list *mdas)
{
struct pool *mem = fid->fmt->cmd->mem;
struct pool *mem = fmt->cmd->mem;
struct physical_volume *pv = pool_alloc(mem, sizeof(*pv));
if (!pv) {
@@ -215,10 +229,7 @@ struct physical_volume *pv_create(struct format_instance *fid,
else
memcpy(&pv->id, id, sizeof(*id));
if (!(pv->dev = dev_cache_get(name, fid->fmt->cmd->filter))) {
log_error("%s: Couldn't find device.", name);
goto bad;
}
pv->dev = dev;
if (!(pv->vg_name = pool_alloc(mem, NAME_LEN))) {
stack;
@@ -229,22 +240,22 @@ struct physical_volume *pv_create(struct format_instance *fid,
pv->status = ALLOCATABLE_PV;
if (!dev_get_size(pv->dev, &pv->size)) {
log_error("%s: Couldn't get size.", name);
log_error("%s: Couldn't get size.", dev_name(pv->dev));
goto bad;
}
if (size) {
if (size > pv->size)
log_print("WARNING: %s: Overriding real size. "
"You could lose data.", name);
"You could lose data.", dev_name(pv->dev));
log_verbose("%s: Pretending size is %" PRIu64 " sectors.",
name, size);
dev_name(pv->dev), size);
pv->size = size;
}
if (pv->size < PV_MIN_SIZE) {
log_error("%s: Size must exceed minimum of %lu sectors.",
name, PV_MIN_SIZE);
log_error("%s: Size must exceed minimum of %ld sectors.",
dev_name(pv->dev), PV_MIN_SIZE);
goto bad;
}
@@ -252,11 +263,14 @@ struct physical_volume *pv_create(struct format_instance *fid,
pv->pe_start = 0;
pv->pe_count = 0;
pv->pe_alloc_count = 0;
pv->fid = fid;
pv->fmt = fmt;
if (!fid->fmt->ops->pv_setup(fid, pv, NULL)) {
if (!fmt->ops->pv_setup(fmt, pe_start, existing_extent_count,
existing_extent_size,
pvmetadatacopies, pvmetadatasize, mdas,
pv, NULL)) {
log_error("%s: Format-specific setup of physical volume "
"failed.", name);
"failed.", dev_name(pv->dev));
goto bad;
}
return pv;
@@ -278,7 +292,21 @@ struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name)
}
return NULL;
}
struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg,
struct id *id)
{
struct list *pvh;
struct pv_list *pvl;
list_iterate(pvh, &vg->pvs) {
pvl = list_item(pvh, struct pv_list);
if (id_equal(&pvl->pv->id, id))
return pvl->pv;
}
return NULL;
}
struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name)
@@ -339,16 +367,14 @@ struct physical_volume *find_pv(struct volume_group *vg, struct device *dev)
int vg_remove(struct volume_group *vg)
{
struct list *mdah;
void *mdl;
if (!vg->fid->fmt->ops->vg_remove)
return 1;
struct metadata_area *mda;
/* FIXME Improve recovery situation? */
/* Remove each copy of the metadata */
list_iterate(mdah, &vg->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!vg->fid->fmt->ops->vg_remove(vg->fid, vg, mdl)) {
mda = list_item(mdah, struct metadata_area);
if (mda->ops->vg_remove &&
!mda->ops->vg_remove(vg->fid, vg, mda)) {
stack;
return 0;
}
@@ -360,7 +386,8 @@ int vg_remove(struct volume_group *vg)
int vg_write(struct volume_group *vg)
{
struct list *mdah;
void *mdl;
struct metadata_area *mda;
int cache_updated = 0;
if (vg->status & PARTIAL_VG) {
log_error("Cannot change metadata for partial volume group %s",
@@ -368,24 +395,31 @@ int vg_write(struct volume_group *vg)
return 0;
}
if (list_empty(&vg->fid->metadata_areas)) {
log_error("Aborting vg_write: No metadata areas to write to!");
return 0;
}
vg->seqno++;
/* Write to each copy of the metadata area */
list_iterate(mdah, &vg->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!vg->fid->fmt->ops->vg_write(vg->fid, vg, mdl)) {
mda = list_item(mdah, struct metadata_area);
if (!mda->ops->vg_write(vg->fid, vg, mda)) {
stack;
return 0;
}
}
if (!vg->fid->fmt->ops->vg_commit)
return 1;
/* Commit to each copy of the metadata area */
list_iterate(mdah, &vg->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!vg->fid->fmt->ops->vg_commit(vg->fid, vg, mdl)) {
mda = list_item(mdah, struct metadata_area);
if (!cache_updated) {
cache_update_vg(vg);
cache_updated = 1;
}
if (mda->ops->vg_commit &&
!mda->ops->vg_commit(vg->fid, vg, mda)) {
stack;
return 0;
}
@@ -394,46 +428,105 @@ int vg_write(struct volume_group *vg)
return 1;
}
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name)
/* Make orphan PVs look like a VG */
struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
{
struct cache_vginfo *vginfo;
struct list *ih;
struct device *dev;
struct pv_list *pvl;
struct volume_group *vg;
struct physical_volume *pv;
if (!(vginfo = vginfo_from_vgname(ORPHAN))) {
stack;
return NULL;
}
if (!(vg = pool_zalloc(cmd->mem, sizeof(*vg)))) {
log_error("vg allocation failed");
return NULL;
}
list_init(&vg->pvs);
list_init(&vg->lvs);
list_init(&vg->snapshots);
vg->cmd = cmd;
if (!(vg->name = pool_strdup(cmd->mem, ORPHAN))) {
log_error("vg name allocation failed");
return NULL;
}
list_iterate(ih, &vginfo->infos) {
dev = list_item(ih, struct cache_info)->dev;
if (!(pv = pv_read(cmd, dev_name(dev), NULL, NULL))) {
continue;
}
if (!(pvl = pool_zalloc(cmd->mem, sizeof(*pvl)))) {
log_error("pv_list allocation failed");
return NULL;
}
pvl->pv = pv;
list_add(&vg->pvs, &pvl->list);
vg->pv_count++;
}
return vg;
}
/* Caller sets consistent to 1 if it's safe for vg_read to correct
* inconsistent metadata on disk (i.e. the VG write lock is held).
* This guarantees only consistent metadata is returned unless PARTIAL_VG.
* If consistent is 0, caller must check whether consistent == 1 on return
* 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)
{
struct format_instance *fid;
struct format_type *fmt;
struct volume_group *vg, *correct_vg;
struct list *mdah, *names;
void *mdl;
struct list *mdah;
struct metadata_area *mda;
int inconsistent = 0, first_time = 1;
/* create format instance with appropriate metadata area */
if (!(fmt = vgcache_find_format(vg_name))) {
/* Do full scan */
if (!(names = get_vgs(cmd))) {
stack;
return NULL;
}
pool_free(cmd->mem, names);
if (!(fmt = vgcache_find_format(vg_name))) {
stack;
return NULL;
if (!*vgname) {
*consistent = 1;
return _vg_read_orphans(cmd);
}
/* Find the vgname in the cache */
/* If it's not there we must do full scan to be completely sure */
if (!(fmt = fmt_from_vgname(vgname))) {
cache_label_scan(cmd, 0);
if (!(fmt = fmt_from_vgname(vgname))) {
cache_label_scan(cmd, 1);
if (!(fmt = fmt_from_vgname(vgname))) {
stack;
return NULL;
}
}
}
if (!(fid = fmt->ops->create_instance(fmt, vg_name, 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 do recovery */
list_iterate(mdah, &fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!(vg = fid->fmt->ops->vg_read(fid, vg_name, mdl))) {
inconsistent = 1;
continue;
mda = list_item(mdah, struct metadata_area);
if (!(vg = mda->ops->vg_read(fid, vgname, mda))) {
inconsistent = 1;
continue;
}
if (first_time) {
correct_vg = vg;
first_time = 0;
continue;
}
/* FIXME Also ensure contents same - checksum compare? */
if (correct_vg->seqno != vg->seqno) {
inconsistent = 1;
if (vg->seqno > correct_vg->seqno)
@@ -447,7 +540,21 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name)
return NULL;
}
cache_update_vg(correct_vg);
if (inconsistent) {
if (!*consistent)
return correct_vg;
/* Don't touch partial volume group metadata */
/* Should be fixed manually with vgcfgbackup/restore etc. */
if ((correct_vg->status & PARTIAL_VG)) {
log_error("Inconsistent metadata copies found for "
"partial volume group %s", vgname);
*consistent = 0;
return correct_vg;
}
log_print("Inconsistent metadata copies found - updating "
"to use version %u", correct_vg->seqno);
if (!vg_write(correct_vg)) {
@@ -456,51 +563,121 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name)
}
}
vgcache_add(vg_name, correct_vg->id.uuid, NULL, fmt);
*consistent = 1;
return correct_vg;
}
/* 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.
*/
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid)
{
char *vgname;
struct list *vgs, *vgh;
struct list *vgnames, *slh;
struct volume_group *vg;
struct cache_vginfo *vginfo;
int consistent = 0;
if (!(vgs = get_vgs(cmd))) {
/* Is corresponding vgname already cached? */
if ((vginfo = vginfo_from_vgid(vgid)) &&
vginfo->vgname && *vginfo->vgname) {
if ((vg = vg_read(cmd, vginfo->vgname, &consistent)) &&
!strncmp(vg->id.uuid, vgid, ID_LEN)) {
if (!consistent) {
log_error("Volume group %s metadata is "
"inconsistent", vginfo->vgname);
return NULL;
}
return vg;
}
}
/* The slow way - full scan required to cope with vgrename */
if (!(vgnames = get_vgs(cmd, 1))) {
log_error("vg_read_by_vgid: get_vgs failed");
return NULL;
}
list_iterate(vgh, vgs) {
vgname = list_item(vgh, struct name_list)->name;
if ((vg = vg_read(cmd, vgname)) &&
!strncmp(vg->id.uuid, vgid, ID_LEN)) return vg;
list_iterate(slh, vgnames) {
vgname = list_item(slh, struct str_list)->str;
if (!vgname || !*vgname)
continue; /* FIXME Unnecessary? */
consistent = 0;
if ((vg = vg_read(cmd, vgname, &consistent)) &&
!strncmp(vg->id.uuid, vgid, ID_LEN)) {
if (!consistent) {
log_error("Volume group %s metadata is "
"inconsistent", vgname);
return NULL;
}
return vg;
}
}
pool_free(cmd->mem, vgs);
return NULL;
}
/* FIXME Use label functions instead of PV functions? */
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name)
/* Only called by activate.c */
struct logical_volume *lv_from_lvid(struct cmd_context *cmd, const char *lvid_s)
{
struct lv_list *lvl;
struct volume_group *vg;
union lvid *lvid;
lvid = (union lvid *) lvid_s;
log_very_verbose("Finding volume group for uuid %s", lvid_s);
if (!(vg = vg_read_by_vgid(cmd, lvid->id[0].uuid))) {
log_error("Volume group for uuid not found: %s", lvid_s);
return NULL;
}
log_verbose("Found volume group \"%s\"", vg->name);
if (vg->status & EXPORTED_VG) {
log_error("Volume group \"%s\" is exported", vg->name);
return NULL;
}
if (!(lvl = find_lv_in_vg_by_lvid(vg, lvid))) {
log_very_verbose("Can't find logical volume id %s", lvid_s);
return NULL;
}
return lvl->lv;
}
/* FIXME Use label functions instead of PV functions */
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
struct list *mdas, uint64_t *label_sector)
{
struct physical_volume *pv;
struct label *label;
struct cache_info *info;
struct device *dev;
if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
stack;
return 0;
}
if (!(label_read(dev, &label))) {
log_error("Failed to read label on physical volume %s",
pv_name);
return 0;
}
info = (struct cache_info *) label->info;
if (label_sector && *label_sector)
*label_sector = label->sector;
if (!(pv = pool_zalloc(cmd->mem, sizeof(*pv)))) {
log_error("pv_list allocation for '%s' failed", pv_name);
return 0;
}
/* Member of a format1 VG? */
if (!(cmd->fmt1->ops->pv_read(cmd->fmt1, pv_name, pv))) {
log_error("Failed to read existing physical volume '%s'",
pv_name);
return 0;
}
/* Member of a format_text VG? */
if (!(cmd->fmtt->ops->pv_read(cmd->fmtt, pv_name, pv))) {
/* 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;
@@ -512,30 +689,22 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name)
return pv;
}
struct list *get_vgs(struct cmd_context *cmd)
/* May return empty list */
struct list *get_vgs(struct cmd_context *cmd, int full_scan)
{
struct list *names;
if (!(names = pool_alloc(cmd->mem, sizeof(*names)))) {
log_error("VG name list allocation failed");
return NULL;
}
list_init(names);
if (!cmd->fmt1->ops->get_vgs(cmd->fmt1, names) ||
!cmd->fmtt->ops->get_vgs(cmd->fmtt, names) ||
list_empty(names)) {
pool_free(cmd->mem, names);
return NULL;
}
return names;
return cache_get_vgnames(cmd, full_scan);
}
struct list *get_pvs(struct cmd_context *cmd)
{
struct list *results;
char *vgname;
struct list *pvh, *tmp;
struct list *vgnames, *slh;
struct volume_group *vg;
int consistent = 0;
cache_label_scan(cmd, 0);
if (!(results = pool_alloc(cmd->mem, sizeof(*results)))) {
log_error("PV list allocation failed");
@@ -544,40 +713,50 @@ struct list *get_pvs(struct cmd_context *cmd)
list_init(results);
/* fmtt modifies fmt1 output */
if (!cmd->fmt1->ops->get_pvs(cmd->fmt1, results) ||
!cmd->fmtt->ops->get_pvs(cmd->fmtt, results)) {
pool_free(cmd->mem, results);
/* Get list of VGs */
if (!(vgnames = get_vgs(cmd, 0))) {
log_error("get_pvs: get_vgs failed");
return NULL;
}
/* Read every VG to ensure cache consistency */
/* Orphan VG is last on list */
init_partial(1);
list_iterate(slh, vgnames) {
vgname = list_item(slh, struct str_list)->str;
if (!vgname)
continue; /* FIXME Unnecessary? */
consistent = 0;
if (!(vg = vg_read(cmd, vgname, &consistent))) {
stack;
continue;
}
if (!consistent)
log_print("Warning: Volume Group %s is not consistent",
vgname);
/* Move PVs onto results list */
list_iterate_safe(pvh, tmp, &vg->pvs) {
list_add(results, pvh);
}
}
init_partial(0);
return results;
}
int pv_write(struct cmd_context *cmd, struct physical_volume *pv)
int pv_write(struct cmd_context *cmd, struct physical_volume *pv,
struct list *mdas, int64_t label_sector)
{
struct list *mdah;
void *mdl;
/* Write to each copy of the metadata area */
list_iterate(mdah, &pv->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!pv->fid->fmt->ops->pv_write(pv->fid, pv, mdl)) {
stack;
return 0;
}
if (*pv->vg_name || pv->pe_alloc_count) {
log_error("Assertion failed: can't _pv_write non-orphan PV "
"(in VG %s)", pv->vg_name);
return 0;
}
if (!pv->fid->fmt->ops->pv_commit)
return 1;
/* Commit to each copy of the metadata area */
list_iterate(mdah, &pv->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!pv->fid->fmt->ops->pv_commit(pv->fid, pv, mdl)) {
stack;
return 0;
}
if (!pv->fmt->ops->pv_write(pv->fmt, pv, mdas, label_sector)) {
stack;
return 0;
}
return 1;

View File

@@ -10,81 +10,126 @@
#ifndef _LVM_METADATA_H
#define _LVM_METADATA_H
#include <sys/types.h>
#include <asm/page.h>
#include "ctype.h"
#include "dev-cache.h"
#include "list.h"
#include "uuid.h"
#include <sys/types.h>
#include <asm/page.h>
#define NAME_LEN 128
#define MAX_STRIPES 128
#define SECTOR_SIZE 512
#define STRIPE_SIZE_DEFAULT 16 /* 16KB */
#define STRIPE_SIZE_MIN ( PAGE_SIZE/SECTOR_SIZE) /* PAGESIZE in sectors */
#define STRIPE_SIZE_MAX ( 512L * 1024 / SECTOR_SIZE) /* 512 KB in sectors */
#define PV_MIN_SIZE ( 512L * 1024 / SECTOR_SIZE) /* 512 KB in sectors */
#define PE_ALIGN (65536UL / SECTOR_SIZE) /* PE alignment */
#define SECTOR_SHIFT 9L
#define SECTOR_SIZE ( 1L << SECTOR_SHIFT )
#define STRIPE_SIZE_DEFAULT 16 /* 16KB */
#define STRIPE_SIZE_MIN ( PAGE_SIZE >> SECTOR_SHIFT) /* PAGESIZE in sectors */
#define STRIPE_SIZE_MAX ( 512L * 1024L >> SECTOR_SHIFT) /* 512 KB in sectors */
#define PV_MIN_SIZE ( 512L * 1024L >> SECTOR_SHIFT) /* 512 KB in sectors */
#define PE_ALIGN (65536UL >> SECTOR_SHIFT) /* PE alignment */
/* Various flags */
/* Note that the bits no longer necessarily correspond to LVM1 disk format */
#define EXPORTED_VG 0x00000002 /* VG PV */
#define RESIZEABLE_VG 0x00000004 /* VG */
#define PARTIAL_VG 0x00000040 /* VG */
#define PARTIAL_VG 0x00000001 /* VG */
#define EXPORTED_VG 0x00000002 /* VG PV */
#define RESIZEABLE_VG 0x00000004 /* VG */
/* May any free extents on this PV be used or must they be left free? */
#define ALLOCATABLE_PV 0x00000008 /* PV */
#define ALLOCATABLE_PV 0x00000008 /* PV */
#define SPINDOWN_LV 0x00000010 /* LV */
#define BADBLOCK_ON 0x00000020 /* LV */
#define FIXED_MINOR 0x00000080 /* LV */
#define SPINDOWN_LV 0x00000010 /* LV */
#define BADBLOCK_ON 0x00000020 /* LV */
#define VISIBLE_LV 0x00000040 /* LV */
#define FIXED_MINOR 0x00000080 /* LV */
/* FIXME Remove when metadata restructuring is completed */
#define SNAPSHOT 0x00001000 /* LV - temp internal use only */
/* FIXME: do we really set read/write for a whole vg ? */
#define LVM_READ 0x00000100 /* LV VG */
#define LVM_WRITE 0x00000200 /* LV VG */
#define CLUSTERED 0x00000400 /* VG */
#define SHARED 0x00000800 /* VG */
#define LVM_READ 0x00000100 /* LV VG */
#define LVM_WRITE 0x00000200 /* LV VG */
#define CLUSTERED 0x00000400 /* VG */
#define SHARED 0x00000800 /* VG */
/* FIXME: This should be an enum rather than a bitset,
remove from status - EJT */
#define ALLOC_SIMPLE 0x00001000 /* LV */
#define ALLOC_STRICT 0x00002000 /* LV */
#define ALLOC_CONTIGUOUS 0x00004000 /* LV */
/* Format features flags */
#define FMT_SEGMENTS 0x00000001 /* Arbitrary segment params? */
#define FMT_MDAS 0x00000002 /* Proper metadata areas? */
#define FMT_SEGMENTS 0x00000001 /* Arbitrary segment parameters? */
typedef enum {
ALLOC_DEFAULT,
ALLOC_NEXT_FREE,
ALLOC_CONTIGUOUS
} alloc_policy_t;
#define FMT_TEXT_NAME "text"
#define FMT_LVM1_NAME "lvm1"
struct physical_volume {
struct id id;
struct device *dev;
struct format_instance *fid;
char *vg_name;
uint32_t status;
uint64_t size;
/* physical extents */
uint64_t pe_size;
uint64_t pe_start;
uint32_t pe_count;
uint32_t pe_alloc_count;
};
typedef enum {
SEG_STRIPED,
SEG_SNAPSHOT,
SEG_MIRROR
} segment_type_t;
struct cmd_context;
struct format_handler;
struct labeller;
struct format_type {
struct list list;
struct cmd_context *cmd;
struct format_handler *ops;
struct labeller *labeller;
const char *name;
const char *alias;
uint32_t features;
void *library;
void *private;
};
struct physical_volume {
struct id id;
struct device *dev;
struct format_type *fmt;
char *vg_name;
uint32_t status;
uint64_t size;
/* physical extents */
uint64_t pe_size;
uint64_t pe_start;
uint32_t pe_count;
uint32_t pe_alloc_count;
};
struct metadata_area;
struct format_instance;
/* Per-format per-metadata area operations */
struct metadata_area_ops {
struct volume_group *(*vg_read) (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
* part of the VG.
*
* It is also the responsibility of the caller to ensure external
* consistency, eg by calling pv_write() if removing PVs from
* a VG or calling vg_write() a second time if splitting a VG
* into two.
*
* vg_write() should not read or write from any PVs not included
* in the volume_group structure it is handed.
* (format1 currently breaks this rule.)
*/
int (*vg_write) (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_remove) (struct format_instance * fi, struct volume_group * vg,
struct metadata_area * mda);
};
struct metadata_area {
struct list list;
struct metadata_area_ops *ops;
void *metadata_locn;
};
@@ -96,27 +141,27 @@ struct format_instance {
struct volume_group {
struct cmd_context *cmd;
struct format_instance *fid;
uint32_t seqno; /* Metadata sequence number */
uint32_t seqno; /* Metadata sequence number */
struct id id;
char *name;
char *system_id;
uint32_t status;
uint32_t status;
uint32_t extent_size;
uint32_t extent_count;
uint32_t free_count;
uint32_t extent_size;
uint32_t extent_count;
uint32_t free_count;
uint32_t max_lv;
uint32_t max_pv;
uint32_t max_lv;
uint32_t max_pv;
/* physical volumes */
uint32_t pv_count;
/* physical volumes */
uint32_t pv_count;
struct list pvs;
/* logical volumes */
uint32_t lv_count;
/* logical volumes */
uint32_t lv_count;
struct list lvs;
/* snapshots */
@@ -124,17 +169,23 @@ struct volume_group {
struct list snapshots;
};
struct stripe_segment {
struct lv_segment {
struct list list;
struct logical_volume *lv;
segment_type_t type;
uint32_t le;
uint32_t len;
/* FIXME Fields depend on segment type */
uint32_t stripe_size;
uint32_t stripes;
struct logical_volume *origin;
struct logical_volume *cow;
uint32_t chunk_size;
/* There will be one area for each stripe */
struct {
struct {
struct physical_volume *pv;
uint32_t pe;
} area[0];
@@ -142,21 +193,24 @@ struct stripe_segment {
struct logical_volume {
union lvid lvid;
char *name;
char *name;
struct volume_group *vg;
uint32_t status;
uint32_t status;
alloc_policy_t alloc;
uint32_t read_ahead;
int32_t minor;
uint64_t size;
uint32_t le_count;
uint64_t size;
uint32_t le_count;
struct list segments;
};
struct snapshot {
struct id id;
int persistent; /* boolean */
uint32_t chunk_size; /* in 512 byte sectors */
@@ -172,6 +226,7 @@ struct name_list {
struct pv_list {
struct list list;
struct physical_volume *pv;
struct list *mdas;
};
struct lv_list {
@@ -185,133 +240,111 @@ struct snapshot_list {
struct snapshot *snapshot;
};
struct mda_list {
struct list list;
struct device_area mda;
};
/*
* Ownership of objects passes to caller.
*/
struct format_handler {
/*
* Returns a name_list of vg's.
* Scan any metadata areas that aren't referenced in PV labels
*/
struct list *(*get_vgs)(struct format_type *fmt, struct list *names);
/*
* Returns pv_list of fully-populated pv structures.
*/
struct list *(*get_pvs)(struct format_type *fmt, struct list *results);
int (*scan) (struct format_type * fmt);
/*
* Return PV with given path.
*/
int (*pv_read)(struct format_type *fmt,
const char *pv_name,
struct physical_volume *pv);
int (*pv_read) (struct format_type * fmt, const char *pv_name,
struct physical_volume * pv, struct list * mdas);
/*
* Tweak an already filled out a pv ready for importing into a
* vg. eg. pe_count is format specific.
*/
int (*pv_setup)(struct format_instance *fi, struct physical_volume *pv,
struct volume_group *vg);
int (*pv_setup) (struct format_type * fmt,
uint64_t pe_start, uint32_t extent_count,
uint32_t extent_size,
int pvmetadatacopies,
uint64_t pvmetadatasize, struct list * mdas,
struct physical_volume * pv, struct volume_group * vg);
/*
* Write a PV structure to disk. Fails if the PV is in a VG ie
* pv->vg_name must be null.
*/
int (*pv_write)(struct format_instance *fi, struct physical_volume *pv,
void *mdl);
int (*pv_commit)(struct format_instance *fid,
struct physical_volume *pv, void *mdl);
int (*pv_write) (struct format_type * fmt, struct physical_volume * pv,
struct list * mdas, int64_t label_sector);
/*
* Tweak an already filled out a lv eg, check there
* aren't too many extents.
*/
int (*lv_setup)(struct format_instance *fi, struct logical_volume *lv);
int (*lv_setup) (struct format_instance * fi,
struct logical_volume * lv);
/*
* Tweak an already filled out vg. eg, max_pv is format
* specific.
*/
int (*vg_setup)(struct format_instance *fi, struct volume_group *vg);
int (*vg_remove)(struct format_instance *fi, struct volume_group *vg,
void *mdl);
int (*vg_setup) (struct format_instance * fi, struct volume_group * vg);
/*
* The name may be prefixed with the dev_dir from the
* job_context.
* mdl is the metadata location to use
*/
struct volume_group *(*vg_read)(struct format_instance *fi,
const char *vg_name, void *mdl);
/*
* Write out complete VG metadata. You must ensure internal
* consistency before calling. eg. PEs can't refer to PVs not
* part of the VG.
*
* It is also the responsibility of the caller to ensure external
* consistency, eg by calling pv_write() if removing PVs from
* a VG or calling vg_write() a second time if splitting a VG
* into two.
*
* vg_write() must not read or write from any PVs not included
* in the volume_group structure it is handed. Note: format1
* does read all pv's currently.
*/
int (*vg_write)(struct format_instance *fid, struct volume_group *vg,
void *mdl);
int (*vg_commit)(struct format_instance *fid, struct volume_group *vg,
void *mdl);
/*
* Create format instance with a particular metadata area
*/
struct format_instance *(*create_instance)(struct format_type *fmt,
const char *vgname,
void *context);
struct format_instance *(*create_instance) (struct format_type * fmt,
const char *vgname,
void *context);
/*
* Destructor for format instance
*/
void (*destroy_instance)(struct format_instance *fid);
void (*destroy_instance) (struct format_instance * fid);
/*
* Destructor for format type
*/
void (*destroy)(struct format_type *fmt);
void (*destroy) (struct format_type * fmt);
};
/*
* Utility functions
*/
int vg_write(struct volume_group *vg);
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name);
struct volume_group *vg_read(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 physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
struct list *mdas, uint64_t *label_sector);
struct list *get_pvs(struct cmd_context *cmd);
struct list *get_vgs(struct cmd_context *cmd);
int pv_write(struct cmd_context *cmd, struct physical_volume *pv);
/* Set full_scan to 1 to re-read every (filtered) device label */
struct list *get_vgs(struct cmd_context *cmd, int full_scan);
struct physical_volume *pv_create(struct format_instance *fi,
const char *name,
int pv_write(struct cmd_context *cmd, struct physical_volume *pv,
struct list *mdas, int64_t label_sector);
/* pe_start and pe_end relate to any existing data so that new metadata
* areas can avoid overlap */
struct physical_volume *pv_create(struct format_type *fmt,
struct device *dev,
struct id *id,
uint64_t size);
uint64_t size,
uint64_t pe_start,
uint32_t existing_extent_count,
uint32_t existing_extent_size,
int pvmetadatacopies,
uint64_t pvmetadatasize, struct list *mdas);
struct volume_group *vg_create(struct cmd_context *cmd, const char *name,
uint32_t extent_size, int max_pv, int max_lv,
int pv_count, char **pv_names);
int vg_remove(struct volume_group *vg);
/*
* This needs the format instance to check the
* pv's are orphaned.
*/
int vg_extend(struct format_instance *fi,
struct volume_group *vg, int pv_count, char **pv_names);
int vg_extend(struct format_instance *fi, struct volume_group *vg,
int pv_count, char **pv_names);
/*
* Create a new LV within a given volume group.
@@ -320,6 +353,7 @@ int vg_extend(struct format_instance *fi,
struct logical_volume *lv_create(struct format_instance *fi,
const char *name,
uint32_t status,
alloc_policy_t alloc,
uint32_t stripes,
uint32_t stripe_size,
uint32_t extents,
@@ -333,35 +367,33 @@ int lv_extend(struct format_instance *fi,
struct logical_volume *lv,
uint32_t stripes,
uint32_t stripe_size,
uint32_t extents,
struct list *allocatable_pvs);
uint32_t extents, struct list *allocatable_pvs);
/* lv must be part of vg->lvs */
int lv_remove(struct volume_group *vg, struct logical_volume *lv);
/* FIXME: Move to other files */
int id_eq(struct id *op1, struct id *op2);
/* Manipulate PV structures */
int pv_add(struct volume_group *vg, struct physical_volume *pv);
int pv_remove(struct volume_group *vg, struct physical_volume *pv);
struct physical_volume *pv_find(struct volume_group *vg,
const char *pv_name);
struct physical_volume *pv_find(struct volume_group *vg, const char *pv_name);
/* Find a PV within a given VG */
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);
/* Find an LV within a given VG */
struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name);
struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg,
struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg,
union lvid *lvid);
/* Return the VG that contains a given LV (based on path given in lv_name) */
/* or environment var */
struct volume_group *find_vg_with_lv(const char *lv_name);
/* Find LV with given lvid (used during activation) */
struct logical_volume *lv_from_lvid(struct cmd_context *cmd,
const char *lvid_s);
/* FIXME Merge these functions with ones above */
struct physical_volume *find_pv(struct volume_group *vg, struct device *dev);
@@ -377,7 +409,6 @@ const char *strip_dir(const char *vg_name, const char *dir);
*/
int lv_check_segments(struct logical_volume *lv);
/*
* Sometimes (eg, after an lvextend), it is possible to merge two
* adjacent segments into a single segment. This function trys
@@ -385,7 +416,6 @@ int lv_check_segments(struct logical_volume *lv);
*/
int lv_merge_segments(struct logical_volume *lv);
/*
* Useful functions for managing snapshots.
*/
@@ -398,10 +428,30 @@ struct list *find_snapshots(struct logical_volume *lv);
int vg_add_snapshot(struct logical_volume *origin,
struct logical_volume *cow,
int persistent,
uint32_t chunk_size);
int persistent, struct id *id, uint32_t chunk_size);
int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow);
static inline int validate_vgname(const char *n)
{
register char c;
register int len = 0;
if (!n || !*n)
return 0;
/* Hyphen used as VG-LV separator - ambiguity if LV starts with it */
if (*n == '-')
return 0;
while ((len++, c = *n++))
if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+')
return 0;
if (len > NAME_LEN)
return 0;
return 1;
}
#endif

View File

@@ -4,8 +4,8 @@
* This file is released under the LGPL.
*/
#include "lib.h"
#include "pv_map.h"
#include "log.h"
#include "hash.h"
#include <assert.h>
@@ -73,7 +73,7 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps)
struct pv_map *pvm;
uint32_t s, pe;
struct hash_table *hash;
struct stripe_segment *seg;
struct lv_segment *seg;
int r = 0;
if (!(hash = hash_create(128))) {
@@ -95,7 +95,7 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps)
lv = list_item(lvh, struct lv_list)->lv;
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment);
seg = list_item(segh, struct lv_segment);
for (s = 0; s < seg->stripes; s++) {
for (pe = 0; pe < (seg->len / seg->stripes);
@@ -142,7 +142,7 @@ static void _insert_area(struct list *head, struct pv_area *a)
}
static int _create_single_area(struct pool *mem, struct pv_map *pvm,
uint32_t * extent)
uint32_t *extent)
{
uint32_t e = *extent, b, count = pvm->pv->pe_count;
struct pv_area *pva;

View File

@@ -4,7 +4,7 @@
* This file is released under the LGPL.
*/
#include "log.h"
#include "lib.h"
#include "metadata.h"
#include "toolcontext.h"
@@ -97,7 +97,7 @@ struct list *find_snapshots(struct logical_volume *lv)
int vg_add_snapshot(struct logical_volume *origin,
struct logical_volume *cow,
int persistent, uint32_t chunk_size)
int persistent, struct id *id, uint32_t chunk_size)
{
struct snapshot *s;
struct snapshot_list *sl;
@@ -121,14 +121,23 @@ int vg_add_snapshot(struct logical_volume *origin,
s->origin = origin;
s->cow = cow;
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)))) {
stack;
pool_free(mem, s);
return 0;
}
cow->status &= ~VISIBLE_LV;
sl->snapshot = s;
list_add(&origin->vg->snapshots, &sl->list);
origin->vg->snapshot_count++;
return 1;
}
@@ -143,6 +152,7 @@ int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow)
if (sl->snapshot->cow == cow) {
list_del(slh);
vg->snapshot_count--;
return 1;
}
}

28
lib/misc/crc.c Normal file
View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#include "lib.h"
#include "lvm-types.h"
/* Calculate an endian-independent CRC of supplied buffer */
uint32_t calc_crc(uint32_t initial, void *buf, uint32_t size)
{
static const uint32_t crctab[] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};
uint32_t i, crc = initial;
uint8_t *data = (uint8_t *) buf;
for (i = 0; i < size; i++) {
crc ^= *data++;
crc = (crc >> 4) ^ crctab[crc & 0xf];
crc = (crc >> 4) ^ crctab[crc & 0xf];
}
return crc;
}

16
lib/misc/crc.h Normal file
View File

@@ -0,0 +1,16 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#ifndef _LVM_CRC_H
#define _LVM_CRC_H
#include "lvm-types.h"
#define INITIAL_CRC 0xf597a6cf
uint32_t calc_crc(uint32_t initial, void *buf, uint32_t size);
#endif

18
lib/misc/lib.h Normal file
View File

@@ -0,0 +1,18 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
/*
* This file must be included first by every source file.
*/
#ifndef _LVM_LIB_H
#define _LVM_LIB_H
#define _REENTRANT
#include "log.h"
#include "dbg_malloc.h"
#endif

View File

@@ -4,14 +4,11 @@
* This file is released under the LGPL.
*/
#include "log.h"
#include "lib.h"
#include "lvm-file.h"
#include "lvm-string.h"
#include "dbg_malloc.h"
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>
@@ -197,3 +194,35 @@ int is_empty_dir(const char *dir)
return dirent ? 0 : 1;
}
void sync_dir(const char *file)
{
int fd;
char *dir, *c;
if (!(dir = dbg_strdup(file))) {
log_error("sync_dir failed in strdup");
return;
}
if (!dir_exists(dir)) {
c = dir + strlen(dir);
while (*c != '/' && c > dir)
c--;
*c = '\0';
}
if ((fd = open(dir, O_RDONLY)) == -1) {
log_sys_error("open", dir);
goto out;
}
if (fsync(fd) == -1)
log_sys_error("fsync", dir);
close(fd);
out:
dbg_free(dir);
}

View File

@@ -32,3 +32,6 @@ int is_empty_dir(const char *dir);
* if directory was successfully created (or already exists), else 0.
*/
int create_dir(const char *dir);
/* Sync directory changes */
void sync_dir(const char *file);

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