mirror of
git://sourceware.org/git/lvm2.git
synced 2025-12-25 20:23:49 +03:00
Compare commits
162 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fff780035d | ||
|
|
46127e673d | ||
|
|
70df59b224 | ||
|
|
0fdbaa803f | ||
|
|
6af1830eff | ||
|
|
6f860e2bd5 | ||
|
|
20a492f7ee | ||
|
|
63875e7591 | ||
|
|
0ad98cabde | ||
|
|
668879d2e1 | ||
|
|
2e09783302 | ||
|
|
49734114b3 | ||
|
|
950d9d6ee7 | ||
|
|
f7974aee2e | ||
|
|
c870a82621 | ||
|
|
984929a001 | ||
|
|
7f9e2c1db8 | ||
|
|
324e8389dc | ||
|
|
6f448c5a38 | ||
|
|
ec43efbb20 | ||
|
|
3ed065de37 | ||
|
|
8152f0d72c | ||
|
|
f8047f4736 | ||
|
|
b93c66dc2d | ||
|
|
ac877b3065 | ||
|
|
dee8abfdde | ||
|
|
cef3841d73 | ||
|
|
3cd5e8a041 | ||
|
|
515b5f866e | ||
|
|
321f62bf92 | ||
|
|
f94fa47b52 | ||
|
|
c502f8a722 | ||
|
|
59b4868ac3 | ||
|
|
3634e12cce | ||
|
|
6d45445391 | ||
|
|
4f47e268cc | ||
|
|
0035b31cdb | ||
|
|
f2565aee03 | ||
|
|
5bd85668dd | ||
|
|
20f990b6ce | ||
|
|
6821379586 | ||
|
|
73b040eb49 | ||
|
|
49aa4b2e1e | ||
|
|
972241c74c | ||
|
|
680750e3c2 | ||
|
|
5e7d4d9d15 | ||
|
|
1e57e60613 | ||
|
|
3ac7ce605a | ||
|
|
b720dea9f0 | ||
|
|
c80722aefe | ||
|
|
a84fa69f28 | ||
|
|
e33781e59f | ||
|
|
8824bc7ece | ||
|
|
c2e3b0e448 | ||
|
|
f61a38e85a | ||
|
|
d23e948216 | ||
|
|
58bdaa31f0 | ||
|
|
b6491d88a6 | ||
|
|
f6061ba62e | ||
|
|
427899ddce | ||
|
|
c4ab7d2dbd | ||
|
|
0fd2ba033f | ||
|
|
ed38939a93 | ||
|
|
c7ee26ce5a | ||
|
|
909b8cb303 | ||
|
|
b0277370cf | ||
|
|
2ec8656bea | ||
|
|
b2ef256910 | ||
|
|
63d6ce95db | ||
|
|
a9532b189c | ||
|
|
844545411f | ||
|
|
4e23a2b9b8 | ||
|
|
5deba027eb | ||
|
|
fc8b7efc6f | ||
|
|
a1c2d9c0f3 | ||
|
|
4ca49a0501 | ||
|
|
493c53d090 | ||
|
|
b27e956d35 | ||
|
|
35ebed75c6 | ||
|
|
7bfdb5f77f | ||
|
|
8d8c02317f | ||
|
|
a34482feab | ||
|
|
cbdc8fd4a6 | ||
|
|
8d3afaa53c | ||
|
|
7ced9ef3df | ||
|
|
e8a9ae7e80 | ||
|
|
73a88ab3d3 | ||
|
|
aaed82738a | ||
|
|
de7f7b96db | ||
|
|
1a669b3e68 | ||
|
|
333af9b13a | ||
|
|
a5bca5e240 | ||
|
|
c885633e02 | ||
|
|
ca7e20b7ca | ||
|
|
545e11a3d7 | ||
|
|
44f5287664 | ||
|
|
cf510897f1 | ||
|
|
1d171345f8 | ||
|
|
4fa7e1cd49 | ||
|
|
acd008298e | ||
|
|
83a8021515 | ||
|
|
cf88dfb1db | ||
|
|
8937c4b481 | ||
|
|
cc6af10a4d | ||
|
|
6d94578955 | ||
|
|
08442ab71e | ||
|
|
10d91d213f | ||
|
|
b7a3b06994 | ||
|
|
5f12c37f23 | ||
|
|
585edebccd | ||
|
|
9921c62234 | ||
|
|
1ac76d2e16 | ||
|
|
6e983bf400 | ||
|
|
6a8fd4fa6e | ||
|
|
3698eaa2d2 | ||
|
|
8d97ca433c | ||
|
|
23cc65e537 | ||
|
|
2f5a3c2bbe | ||
|
|
f6485616cd | ||
|
|
6544fb43d9 | ||
|
|
a954b32dcc | ||
|
|
426dc7836c | ||
|
|
ff941ffc16 | ||
|
|
a063c201df | ||
|
|
e2be3fa0aa | ||
|
|
609da6fb50 | ||
|
|
fc9f3ccec3 | ||
|
|
f7baa67a0a | ||
|
|
e8d78c2cdb | ||
|
|
9d33366092 | ||
|
|
f5d61515c2 | ||
|
|
711a04a972 | ||
|
|
e5b470a3f1 | ||
|
|
31820e1e22 | ||
|
|
4849e8cd6d | ||
|
|
77e3b460aa | ||
|
|
b5321001f8 | ||
|
|
38eba9f5ea | ||
|
|
ea6f399454 | ||
|
|
f8bf2d7b7d | ||
|
|
c4856caebb | ||
|
|
fc1030bb22 | ||
|
|
9eb6cad8dc | ||
|
|
0fa2a78dce | ||
|
|
a56fa1558b | ||
|
|
261c73a997 | ||
|
|
929c1333ca | ||
|
|
286a79d94d | ||
|
|
8b951f99da | ||
|
|
abb449bca0 | ||
|
|
bd084028d1 | ||
|
|
138a27570b | ||
|
|
c2ed40a74f | ||
|
|
a7e7a00cab | ||
|
|
64a31ab3cd | ||
|
|
71958bc0f1 | ||
|
|
366ec35612 | ||
|
|
3738f6e8ae | ||
|
|
051a8e2af1 | ||
|
|
2f43f28d5e | ||
|
|
b64769754b | ||
|
|
a97daa18d1 |
7
TODO
7
TODO
@@ -4,24 +4,23 @@ 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
|
||||
partial activation (aka VG quorum)
|
||||
error message review
|
||||
locking during metadata changes
|
||||
format2 with atomic transactions
|
||||
bidirectional format1/format2 migration tool
|
||||
persistent minors
|
||||
stats
|
||||
pvmove
|
||||
statistics target and tool support
|
||||
review tool exit codes for LVM1 compatibility
|
||||
|
||||
before 2.1
|
||||
----------
|
||||
|
||||
e2fsadm
|
||||
lvmdiskscan
|
||||
lvmsadc
|
||||
lvmsar
|
||||
pvdata
|
||||
|
||||
29
debian/changelog
vendored
Normal file
29
debian/changelog
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
lvm2 (0.95.05-1) unstable; urgency=low
|
||||
|
||||
* New release (Beta2).
|
||||
|
||||
-- Andres Salomon <dilinger@mp3revolution.net> Thu, 25 Apr 2002 00:37:41 -0500
|
||||
|
||||
lvm2 (0.95.04cvs20020306-1) unstable; urgency=low
|
||||
|
||||
* CVS updated.
|
||||
* Convert from debian native package.
|
||||
|
||||
-- Andres Salomon <dilinger@mp3revolution.net> Wed, 6 Mar 2002 00:43:21 -0500
|
||||
|
||||
lvm2 (0.95.04cvs20020304) unstable; urgency=low
|
||||
|
||||
* CVS updated.
|
||||
* Enhance init script; create devmapper control device, etc.
|
||||
* Add dmsetup as a suggestion.
|
||||
* Add /etc/lvm/lvm.conf conffile.
|
||||
* Add undocumented(7) for the commands missing manpages.
|
||||
|
||||
-- Andres Salomon <dilinger@mp3revolution.net> Mon, 4 Mar 2002 04:51:26 -0500
|
||||
|
||||
lvm2 (0.95.02cvs20020220) unstable; urgency=low
|
||||
|
||||
* Initial Release.
|
||||
|
||||
-- Andres Salomon <dilinger@mp3revolution.net> Wed, 20 Feb 2002 03:17:25 -0500
|
||||
|
||||
2
debian/conffiles
vendored
Normal file
2
debian/conffiles
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/etc/lvm/lvm.conf
|
||||
/etc/init.d/lvm2
|
||||
19
debian/control
vendored
Normal file
19
debian/control
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Source: lvm2
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Maintainer: Andres Salomon <dilinger@mp3revolution.net>
|
||||
Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev, libreadline4-dev
|
||||
Standards-Version: 3.5.2
|
||||
|
||||
Package: lvm2
|
||||
Architecture: any
|
||||
Depends: libdevmapper0
|
||||
Replaces: lvm10, lvm-common
|
||||
Provides: lvm-binaries
|
||||
Suggests: dmsetup
|
||||
Description: The Linux Logical Volume Manager
|
||||
This is LVM2, the rewrite of The Linux Logical Volume Manager. LVM
|
||||
supports enterprise level volume management of disk and disk subsystems
|
||||
by grouping arbitrary disks into volume groups. The total capacity of
|
||||
volume groups can be allocated to logical volumes, which are accessed as
|
||||
regular block devices.
|
||||
25
debian/copyright
vendored
Normal file
25
debian/copyright
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
This package was debianized by Andres Salomon <dilinger@mp3revolution.net> on
|
||||
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
|
||||
|
||||
Copyright (c) 2001-2002 LVM Development Team
|
||||
|
||||
LVM2 is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
LVM2 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
|
||||
On Debian systems, the full text of the GPL can be found in
|
||||
/usr/share/common-licenses/GPL
|
||||
4
debian/dirs
vendored
Normal file
4
debian/dirs
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
etc/lvm
|
||||
usr/share/man/man5
|
||||
usr/share/man/man8
|
||||
sbin
|
||||
8
debian/docs
vendored
Normal file
8
debian/docs
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
BUGS
|
||||
INTRO
|
||||
README
|
||||
TODO
|
||||
VERSION
|
||||
doc/example.conf
|
||||
doc/pvmove_outline.txt
|
||||
doc/testing.txt
|
||||
65
debian/init.d
vendored
Normal file
65
debian/init.d
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# lvm2 This script handles LVM2 initialization/shutdown.
|
||||
#
|
||||
# Written by Andres Salomon <dilinger@mp3revolution.net>.
|
||||
#
|
||||
|
||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin
|
||||
NAME=lvm2
|
||||
DESC=LVM
|
||||
|
||||
test -x /sbin/vgchange || exit 0
|
||||
modprobe dm-mod >/dev/null 2>&1
|
||||
|
||||
# Create necessary files in /dev for device-mapper
|
||||
create_devfiles() {
|
||||
DIR="/dev/device-mapper"
|
||||
FILE="$DIR/control"
|
||||
major=$(awk '$2 ~ /^misc$/ {print $1}' /proc/devices)
|
||||
minor=$(awk "\$2 ~ /^$DM_NAME\$/ {print \$1}" /proc/misc)
|
||||
|
||||
if test ! -d $DIR; then
|
||||
mkdir --mode=755 $DIR >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
if test ! -c $FILE -a ! -z "$minor"; then
|
||||
mknod --mode=600 $FILE c $major $minor >/dev/null 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
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)
|
||||
echo -n "Shutting down $DESC: "
|
||||
# We don't really try all that hard to shut it down; far too many
|
||||
# things that can keep it from successfully shutting down.
|
||||
vgchange -a n
|
||||
echo "$NAME."
|
||||
;;
|
||||
restart|force-reload)
|
||||
echo -n "Restarting $DESC: "
|
||||
vgchange -a n
|
||||
sleep 1
|
||||
vgchange -a y
|
||||
echo "$NAME."
|
||||
;;
|
||||
*)
|
||||
N=/etc/init.d/$NAME
|
||||
echo "Usage: $N {start|stop|restart|force-reload}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
26
debian/manpages
vendored
Normal file
26
debian/manpages
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
debian/lvm2/usr/share/man/man5/lvm.conf.5
|
||||
debian/lvm2/usr/share/man/man8/lvchange.8
|
||||
debian/lvm2/usr/share/man/man8/lvcreate.8
|
||||
debian/lvm2/usr/share/man/man8/lvdisplay.8
|
||||
debian/lvm2/usr/share/man/man8/lvextend.8
|
||||
debian/lvm2/usr/share/man/man8/lvm.8
|
||||
debian/lvm2/usr/share/man/man8/lvmchange.8
|
||||
debian/lvm2/usr/share/man/man8/lvreduce.8
|
||||
debian/lvm2/usr/share/man/man8/lvremove.8
|
||||
debian/lvm2/usr/share/man/man8/lvrename.8
|
||||
debian/lvm2/usr/share/man/man8/lvscan.8
|
||||
debian/lvm2/usr/share/man/man8/pvchange.8
|
||||
debian/lvm2/usr/share/man/man8/pvcreate.8
|
||||
debian/lvm2/usr/share/man/man8/pvdisplay.8
|
||||
debian/lvm2/usr/share/man/man8/pvscan.8
|
||||
debian/lvm2/usr/share/man/man8/vgcfgbackup.8
|
||||
debian/lvm2/usr/share/man/man8/vgchange.8
|
||||
debian/lvm2/usr/share/man/man8/vgck.8
|
||||
debian/lvm2/usr/share/man/man8/vgcreate.8
|
||||
debian/lvm2/usr/share/man/man8/vgdisplay.8
|
||||
debian/lvm2/usr/share/man/man8/vgextend.8
|
||||
debian/lvm2/usr/share/man/man8/vgmerge.8
|
||||
debian/lvm2/usr/share/man/man8/vgreduce.8
|
||||
debian/lvm2/usr/share/man/man8/vgremove.8
|
||||
debian/lvm2/usr/share/man/man8/vgrename.8
|
||||
debian/lvm2/usr/share/man/man8/vgscan.8
|
||||
49
debian/postinst
vendored
Executable file
49
debian/postinst
vendored
Executable file
@@ -0,0 +1,49 @@
|
||||
#! /bin/sh
|
||||
# postinst script for lvm2
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
# summary of how this script can be called:
|
||||
# * <postinst> `configure' <most-recently-configured-version>
|
||||
# * <old-postinst> `abort-upgrade' <new version>
|
||||
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
|
||||
# <new-version>
|
||||
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
|
||||
# <failed-install-package> <version> `removing'
|
||||
# <conflicting-package> <version>
|
||||
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# the debian-policy package
|
||||
#
|
||||
# quoting from the policy:
|
||||
# Any necessary prompting should almost always be confined to the
|
||||
# post-installation script, and should be protected with a conditional
|
||||
# so that unnecessary prompting doesn't happen if a package's
|
||||
# installation fails and the `postinst' is called with `abort-upgrade',
|
||||
# `abort-remove' or `abort-deconfigure'.
|
||||
|
||||
case "$1" in
|
||||
configure)
|
||||
update-rc.d lvm2 start 25 S . start 50 0 6 . >/dev/null
|
||||
/etc/init.d/lvm2 start
|
||||
;;
|
||||
|
||||
abort-upgrade|abort-remove|abort-deconfigure)
|
||||
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postinst called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
|
||||
|
||||
39
debian/postrm
vendored
Executable file
39
debian/postrm
vendored
Executable file
@@ -0,0 +1,39 @@
|
||||
#! /bin/sh
|
||||
# postrm script for lvm2
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
# summary of how this script can be called:
|
||||
# * <postrm> `remove'
|
||||
# * <postrm> `purge'
|
||||
# * <old-postrm> `upgrade' <new-version>
|
||||
# * <new-postrm> `failed-upgrade' <old-version>
|
||||
# * <new-postrm> `abort-install'
|
||||
# * <new-postrm> `abort-install' <old-version>
|
||||
# * <new-postrm> `abort-upgrade' <old-version>
|
||||
# * <disappearer's-postrm> `disappear' <r>overwrit>r> <new-version>
|
||||
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# the debian-policy package
|
||||
|
||||
|
||||
case "$1" in
|
||||
purge)
|
||||
rm -f /etc/init.d/lvm2
|
||||
update-rc.d lvm2 remove >/dev/null
|
||||
;;
|
||||
remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postrm called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
esac
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
120
debian/rules
vendored
Executable file
120
debian/rules
vendored
Executable file
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/make -f
|
||||
# Sample debian/rules that uses debhelper.
|
||||
# GNU copyright 1997 by Joey Hess.
|
||||
#
|
||||
# This version is for a hypothetical package that builds an
|
||||
# architecture-dependant package, as well as an architecture-independent
|
||||
# package.
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
# This is the debhelper compatibility version to use.
|
||||
export DH_COMPAT=3
|
||||
|
||||
# These are used for cross-compiling and for saving the configure script
|
||||
# from having to guess our platform (since we know it already)
|
||||
DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
|
||||
DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
|
||||
|
||||
ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
|
||||
CFLAGS += -g
|
||||
endif
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
INSTALL_PROGRAM += -s
|
||||
endif
|
||||
|
||||
configure: configure-stamp
|
||||
configure-stamp:
|
||||
dh_testdir
|
||||
# Add here commands to configure the package.
|
||||
./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/ --mandir=\$${prefix}/usr/share/man --infodir=\$${prefix}/usr/share/info
|
||||
|
||||
touch configure-stamp
|
||||
|
||||
build-arch: configure-stamp build-arch-stamp
|
||||
build-arch-stamp:
|
||||
dh_testdir
|
||||
|
||||
# Add here command to compile/build the package.
|
||||
$(MAKE)
|
||||
|
||||
touch build-arch-stamp
|
||||
|
||||
build-indep: configure-stamp build-indep-stamp
|
||||
build-indep-stamp:
|
||||
dh_testdir
|
||||
|
||||
# Add here command to compile/build the arch indep package.
|
||||
# It's ok not to do anything here, if you don't need to build
|
||||
# anything for this package.
|
||||
#/usr/bin/docbook-to-man debian/lvm2.sgml > lvm2.1
|
||||
|
||||
touch build-indep-stamp
|
||||
|
||||
build: build-arch build-indep
|
||||
|
||||
clean:
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
rm -f build-stamp configure-stamp
|
||||
|
||||
# Add here commands to clean up after the build process.
|
||||
-$(MAKE) distclean
|
||||
-test -r /usr/share/misc/config.sub && \
|
||||
cp -f /usr/share/misc/config.sub config.sub
|
||||
-test -r /usr/share/misc/config.guess && \
|
||||
cp -f /usr/share/misc/config.guess config.guess
|
||||
|
||||
|
||||
dh_clean
|
||||
|
||||
install: DH_OPTIONS=
|
||||
install: build
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_clean -k
|
||||
dh_installdirs
|
||||
|
||||
# Add here commands to install the package into debian/lvm2.
|
||||
$(MAKE) install prefix=$(CURDIR)/debian/lvm2
|
||||
install -m 0644 doc/example.conf debian/lvm2/etc/lvm/lvm.conf
|
||||
|
||||
|
||||
# Build architecture-independent files here.
|
||||
# Pass -i to all debhelper commands in this target to reduce clutter.
|
||||
binary-indep: build install
|
||||
# nada.
|
||||
|
||||
# Build architecture-dependent files here.
|
||||
binary-arch: build install
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
|
||||
# dh_installdebconf
|
||||
dh_installdocs
|
||||
dh_installexamples
|
||||
# dh_installlogrotate -a
|
||||
# dh_installemacsen -a
|
||||
# dh_installpam -a
|
||||
# dh_installmime -a
|
||||
dh_installinit -n
|
||||
dh_installcron
|
||||
dh_installman
|
||||
dh_installinfo
|
||||
dh_undocumented
|
||||
dh_installchangelogs
|
||||
dh_strip
|
||||
dh_link
|
||||
dh_compress
|
||||
dh_fixperms
|
||||
dh_makeshlibs
|
||||
dh_installdeb
|
||||
# dh_perl -a
|
||||
dh_shlibdeps
|
||||
dh_gencontrol
|
||||
dh_md5sums
|
||||
dh_builddeb
|
||||
|
||||
binary: binary-indep binary-arch
|
||||
.PHONY: build clean binary-indep binary-arch binary install configure
|
||||
14
debian/undocumented
vendored
Normal file
14
debian/undocumented
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
e2fsadm.8
|
||||
lvmdiskscan.8
|
||||
lvmsadc.8
|
||||
lvmsar.8
|
||||
lvresize.8
|
||||
pvdata.8
|
||||
pvmove.8
|
||||
pvresize.8
|
||||
version.8
|
||||
vgcfgrestore.8
|
||||
vgexport.8
|
||||
vgimport.8
|
||||
vgmknodes.8
|
||||
vgsplit.8
|
||||
@@ -24,6 +24,8 @@ devices {
|
||||
# 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/.*/"
|
||||
|
||||
@@ -120,6 +122,12 @@ shell {
|
||||
history_size = 100
|
||||
}
|
||||
|
||||
# Metadata settings
|
||||
metadata {
|
||||
# List of directories holding copies of text format metadata
|
||||
dirs = [ "/etc/lvm/metadata" ]
|
||||
}
|
||||
|
||||
# Miscellaneous global settings
|
||||
global {
|
||||
|
||||
@@ -134,4 +142,11 @@ global {
|
||||
# will be made. Equivalent to having the -t option on every
|
||||
# command. Defaults to off.
|
||||
test = 0
|
||||
|
||||
# Default metadata format commands use - "lvm1" (default) or "text"
|
||||
format = "lvm1"
|
||||
|
||||
# Location of proc filesystem
|
||||
proc = "/proc"
|
||||
}
|
||||
|
||||
|
||||
46
doc/testing.txt
Normal file
46
doc/testing.txt
Normal file
@@ -0,0 +1,46 @@
|
||||
Here's how I test new LVM2 builds without interfering with the stable
|
||||
LVM2 that is running the LV's on my development box.
|
||||
|
||||
1) Create a set of loopback devices.
|
||||
|
||||
2) Create a new directory to contain the LVM2 configuration files for
|
||||
this setup. (I use /etc/lvm_loops)
|
||||
|
||||
3) Write a suitable lvm.conf file, this goes in the directory you just
|
||||
created. eg, my /etc/lvm_loops/lvm.conf looks like:
|
||||
|
||||
log {
|
||||
file="/tmp/lvm2_loop.log"
|
||||
level=9
|
||||
verbose=0
|
||||
overwrite=1
|
||||
}
|
||||
|
||||
devices {
|
||||
scan = "/dev"
|
||||
filter = ["a/loop/", "r/.*/"]
|
||||
}
|
||||
|
||||
|
||||
The important this to note is the devices section which makes sure that
|
||||
only the loopback devices are considered for LVM2 operations.
|
||||
|
||||
4) When you want to use this test setup just set the environment
|
||||
variable LVM_SYSTEM_DIR to point to your config directory
|
||||
(/etc/lvm_loops in my case).
|
||||
|
||||
5) It's a good idea to do a vgscan to initialise the filters:
|
||||
|
||||
export LVM_SYSTEM_DIR=/etc/lvm_loops
|
||||
./lvm vgscan
|
||||
|
||||
where ./lvm is the new build of LVM2 that I'm trying out.
|
||||
|
||||
7) Test away. Make sure that you are explicit about which lvm
|
||||
executable you want to execute (eg, ./lvm if you are in
|
||||
LVM2/tools).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
../lib/activate/activate.h
|
||||
../lib/commands/errors.h
|
||||
../lib/commands/toolcontext.h
|
||||
../lib/config/config.h
|
||||
../lib/config/defaults.h
|
||||
../lib/datastruct/bitset.h
|
||||
../lib/datastruct/btree.h
|
||||
../lib/datastruct/hash.h
|
||||
@@ -17,6 +20,7 @@
|
||||
../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
|
||||
|
||||
@@ -10,8 +10,8 @@ VPATH = @srcdir@
|
||||
|
||||
SOURCES=\
|
||||
activate/activate.c \
|
||||
activate/dev_manager.c \
|
||||
activate/fs.c \
|
||||
activate/names.c \
|
||||
config/config.c \
|
||||
datastruct/bitset.c \
|
||||
datastruct/btree.c \
|
||||
@@ -38,11 +38,16 @@ SOURCES=\
|
||||
format_text/import.c \
|
||||
label/label.c \
|
||||
label/uuid-map.c \
|
||||
locking/external_locking.c \
|
||||
locking/file_locking.c \
|
||||
locking/locking.c \
|
||||
locking/no_locking.c \
|
||||
log/log.c \
|
||||
metadata/lv_manip.c \
|
||||
metadata/merge.c \
|
||||
metadata/metadata.c \
|
||||
metadata/pv_map.c \
|
||||
metadata/snapshot_manip.c \
|
||||
misc/lvm-file.c \
|
||||
mm/dbg_malloc.c \
|
||||
mm/pool.c \
|
||||
|
||||
@@ -10,10 +10,18 @@
|
||||
#include "log.h"
|
||||
#include "fs.h"
|
||||
#include "lvm-string.h"
|
||||
#include "names.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)
|
||||
|
||||
int library_version(char *version, size_t size)
|
||||
{
|
||||
@@ -22,33 +30,6 @@ int library_version(char *version, size_t size)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct dm_task *_setup_task_with_name(struct logical_volume *lv,
|
||||
const char *lv_name,
|
||||
int task)
|
||||
{
|
||||
char name[128];
|
||||
struct dm_task *dmt;
|
||||
|
||||
if (!(dmt = dm_task_create(task))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!build_dm_name(name, sizeof(name), lv->vg->name, lv_name)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dm_task_set_name(dmt, name);
|
||||
|
||||
return dmt;
|
||||
}
|
||||
|
||||
static struct dm_task *_setup_task(struct logical_volume *lv, int task)
|
||||
{
|
||||
return _setup_task_with_name(lv, lv->name, task);
|
||||
}
|
||||
|
||||
int driver_version(char *version, size_t size)
|
||||
{
|
||||
int r = 0;
|
||||
@@ -74,355 +55,106 @@ int driver_version(char *version, size_t size)
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if info structure populated, else 0 on failure.
|
||||
*/
|
||||
int lv_info(struct logical_volume *lv, struct dm_info *info)
|
||||
{
|
||||
int r = 0;
|
||||
struct dm_task *dmt;
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
|
||||
log_very_verbose("Getting device info for %s", lv->name);
|
||||
if (!(dmt = _setup_task(lv, DM_DEVICE_INFO))) {
|
||||
if (!(dm = dev_manager_create(lv->vg->name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dm_task_run(dmt)) {
|
||||
if (!(r = dev_manager_info(dm, lv, info)))
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!dm_task_get_info(dmt, info)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
dev_manager_destroy(dm);
|
||||
return r;
|
||||
}
|
||||
|
||||
int lv_rename(const char *old_name, struct logical_volume *lv)
|
||||
static int _lv_active(struct logical_volume *lv)
|
||||
{
|
||||
int r = 0;
|
||||
char new_name[PATH_MAX];
|
||||
struct dm_task *dmt;
|
||||
|
||||
if (test_mode())
|
||||
return 0;
|
||||
|
||||
if (!(dmt = _setup_task_with_name(lv, old_name, DM_DEVICE_RENAME))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!build_dm_name(new_name, sizeof(new_name),
|
||||
lv->vg->name, lv->name)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dm_task_set_newname(dmt, new_name)) {
|
||||
stack;
|
||||
r = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!dm_task_run(dmt)) {
|
||||
stack;
|
||||
r = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
fs_rename_lv(old_name, lv);
|
||||
|
||||
end:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
|
||||
int lv_active(struct logical_volume *lv)
|
||||
{
|
||||
int r = -1;
|
||||
struct dm_info info;
|
||||
|
||||
if (!lv_info(lv, &info)) {
|
||||
stack;
|
||||
return r;
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_very_verbose("%s is%s active", lv->name, info.exists ? "":" not");
|
||||
return info.exists;
|
||||
}
|
||||
|
||||
int lv_suspended(struct logical_volume *lv)
|
||||
static int _lv_open_count(struct logical_volume *lv)
|
||||
{
|
||||
int r = -1;
|
||||
struct dm_info info;
|
||||
|
||||
if (!lv_info(lv, &info)) {
|
||||
stack;
|
||||
return r;
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_very_verbose("%s is%s suspended", lv->name,
|
||||
info.suspended ? "":" not");
|
||||
return info.suspended;
|
||||
}
|
||||
|
||||
int lv_open_count(struct logical_volume *lv)
|
||||
{
|
||||
int r = -1;
|
||||
struct dm_info info;
|
||||
|
||||
if (!lv_info(lv, &info)) {
|
||||
stack;
|
||||
return r;
|
||||
}
|
||||
|
||||
log_very_verbose("%s is open %d time(s)", lv->name, info.open_count);
|
||||
return info.open_count;
|
||||
}
|
||||
|
||||
/* FIXME Need to detect and handle an lv rename */
|
||||
static int _lv_activate(struct logical_volume *lv)
|
||||
{
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(r = dev_manager_activate(dm, lv)))
|
||||
stack;
|
||||
|
||||
dev_manager_destroy(dm);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _lv_deactivate(struct logical_volume *lv)
|
||||
{
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(r = dev_manager_deactivate(dm, lv)))
|
||||
stack;
|
||||
|
||||
dev_manager_destroy(dm);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _lv_suspend(struct logical_volume *lv)
|
||||
{
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(r = dev_manager_suspend(dm, lv)))
|
||||
stack;
|
||||
|
||||
dev_manager_destroy(dm);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit a target for a given segment.
|
||||
* These two functions return the number of LVs in the state,
|
||||
* or -1 on error.
|
||||
*/
|
||||
static int _emit_target(struct dm_task *dmt, struct stripe_segment *seg)
|
||||
{
|
||||
char params[1024];
|
||||
uint64_t esize = seg->lv->vg->extent_size;
|
||||
uint32_t s, stripes = seg->stripes;
|
||||
int w = 0, tw = 0, error = 0;
|
||||
const char *no_space =
|
||||
"Insufficient space to write target parameters.";
|
||||
char *filler = "/dev/ioerror";
|
||||
char *target;
|
||||
|
||||
if (stripes == 1) {
|
||||
if (!seg->area[0].pv) {
|
||||
target = "error";
|
||||
error = 1;
|
||||
}
|
||||
else
|
||||
target = "linear";
|
||||
}
|
||||
|
||||
if (stripes > 1) {
|
||||
target = "striped";
|
||||
tw = lvm_snprintf(params, sizeof(params), "%u %u ",
|
||||
stripes, seg->stripe_size);
|
||||
|
||||
if (tw < 0) {
|
||||
log_err(no_space);
|
||||
return 0;
|
||||
}
|
||||
|
||||
w = tw;
|
||||
}
|
||||
|
||||
if (!error) {
|
||||
for (s = 0; s < stripes; s++, w += tw) {
|
||||
if (!seg->area[s].pv)
|
||||
tw = lvm_snprintf(
|
||||
params + w, sizeof(params) - w,
|
||||
"%s 0%s", filler,
|
||||
s == (stripes - 1) ? "" : " ");
|
||||
else
|
||||
tw = lvm_snprintf(
|
||||
params + w, sizeof(params) - w,
|
||||
"%s %" PRIu64 "%s",
|
||||
dev_name(seg->area[s].pv->dev),
|
||||
(seg->area[s].pv->pe_start +
|
||||
(esize * seg->area[s].pe)),
|
||||
s == (stripes - 1) ? "" : " ");
|
||||
|
||||
if (tw < 0) {
|
||||
log_err(no_space);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log_very_verbose("Adding target: %" PRIu64 " %" PRIu64 " %s %s",
|
||||
esize * seg->le, esize * seg->len,
|
||||
target, params);
|
||||
|
||||
if (!dm_task_add_target(dmt, esize * seg->le, esize * seg->len,
|
||||
target, params)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _load(struct logical_volume *lv, int task)
|
||||
{
|
||||
int r = 0;
|
||||
struct dm_task *dmt;
|
||||
struct list *segh;
|
||||
struct stripe_segment *seg;
|
||||
|
||||
log_very_verbose("Generating devmapper parameters for %s", lv->name);
|
||||
if (!(dmt = _setup_task(lv, task))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct stripe_segment);
|
||||
if (!_emit_target(dmt, seg)) {
|
||||
log_error("Unable to activate logical volume '%s'",
|
||||
lv->name);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!((lv->status & LVM_WRITE) && (lv->vg->status & LVM_WRITE))) {
|
||||
if (!dm_task_set_ro(dmt))
|
||||
log_error("Failed to set %s read-only during "
|
||||
"activation.", lv->name);
|
||||
else
|
||||
log_very_verbose("Activating %s read-only", lv->name);
|
||||
}
|
||||
|
||||
|
||||
if (!(r = dm_task_run(dmt)))
|
||||
stack;
|
||||
|
||||
log_verbose("Logical volume %s%s activated", lv->name,
|
||||
r == 1 ? "" : " not");
|
||||
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* FIXME: Always display error msg */
|
||||
int lv_activate(struct logical_volume *lv)
|
||||
{
|
||||
if (test_mode())
|
||||
return 0;
|
||||
|
||||
log_very_verbose("Activating %s", lv->name);
|
||||
return _load(lv, DM_DEVICE_CREATE) && fs_add_lv(lv);
|
||||
}
|
||||
|
||||
int _suspend(struct logical_volume *lv, int sus)
|
||||
{
|
||||
int r;
|
||||
struct dm_task *dmt;
|
||||
int task = sus ? DM_DEVICE_SUSPEND : DM_DEVICE_RESUME;
|
||||
|
||||
log_very_verbose("%s %s", sus ? "Suspending" : "Resuming", lv->name);
|
||||
if (!(dmt = _setup_task(lv, task))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(r = dm_task_run(dmt)))
|
||||
log_err("Couldn't %s device '%s'", sus ? "suspend" : "resume",
|
||||
lv->name);
|
||||
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
|
||||
int lv_suspend(struct logical_volume *lv)
|
||||
{
|
||||
return _suspend(lv, 1);
|
||||
}
|
||||
|
||||
int lv_reactivate(struct logical_volume *lv)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (test_mode())
|
||||
return 0;
|
||||
|
||||
if (!lv_suspended(lv) && !_suspend(lv, 1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = _load(lv, DM_DEVICE_RELOAD);
|
||||
|
||||
if (!_suspend(lv, 0)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int lv_deactivate(struct logical_volume *lv)
|
||||
{
|
||||
int r;
|
||||
struct dm_task *dmt;
|
||||
|
||||
log_very_verbose("Deactivating %s", lv->name);
|
||||
if (test_mode())
|
||||
return 0;
|
||||
|
||||
if (!(dmt = _setup_task(lv, DM_DEVICE_REMOVE))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(r = dm_task_run(dmt)))
|
||||
stack;
|
||||
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
fs_del_lv(lv);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int activate_lvs_in_vg(struct volume_group *vg)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
int count = 0;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
count += (!lv_active(lv) && lv_activate(lv));
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int lv_update_write_access(struct logical_volume *lv)
|
||||
{
|
||||
struct dm_info info;
|
||||
|
||||
if (!lv_info(lv, &info)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!info.exists || info.suspended)
|
||||
/* Noop */
|
||||
return 1;
|
||||
|
||||
return lv_reactivate(lv);
|
||||
}
|
||||
|
||||
int deactivate_lvs_in_vg(struct volume_group *vg)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
int count = 0;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
count += ((lv_active(lv) == 1) && lv_deactivate(lv));
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int lvs_in_vg_activated(struct volume_group *vg)
|
||||
{
|
||||
struct list *lvh;
|
||||
@@ -431,7 +163,7 @@ int lvs_in_vg_activated(struct volume_group *vg)
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
count += (lv_active(lv) == 1);
|
||||
count += (_lv_active(lv) == 1);
|
||||
}
|
||||
|
||||
return count;
|
||||
@@ -445,8 +177,134 @@ int lvs_in_vg_opened(struct volume_group *vg)
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
count += (lv_open_count(lv) == 1);
|
||||
count += (_lv_open_count(lv) == 1);
|
||||
}
|
||||
|
||||
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)))
|
||||
return 0;
|
||||
|
||||
if (test_mode()) {
|
||||
_skip("Suspending '%s'.", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_info(lv, &info)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info.exists && !info.suspended)
|
||||
return _lv_suspend(lv);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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)))
|
||||
return 0;
|
||||
|
||||
if (test_mode()) {
|
||||
_skip("Resuming '%s'.", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_info(lv, &info)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info.exists && info.suspended)
|
||||
return _lv_activate(lv);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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)))
|
||||
return 0;
|
||||
|
||||
if (test_mode()) {
|
||||
_skip("Deactivating '%s'.", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_info(lv, &info)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info.exists)
|
||||
return _lv_deactivate(lv);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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)))
|
||||
return 0;
|
||||
|
||||
if (test_mode()) {
|
||||
_skip("Activating '%s'.", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_info(lv, &info)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!info.exists || info.suspended)
|
||||
return _lv_activate(lv);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#ifndef LVM_ACTIVATE_H
|
||||
@@ -9,44 +9,34 @@
|
||||
|
||||
#include <libdevmapper.h>
|
||||
|
||||
/* FIXME Snapshot handling? */
|
||||
|
||||
int driver_version(char *version, size_t size);
|
||||
int library_version(char *version, size_t size);
|
||||
|
||||
int lv_active(struct logical_volume *lv);
|
||||
int lv_suspended(struct logical_volume *lv);
|
||||
int lv_open_count(struct logical_volume *lv);
|
||||
/*
|
||||
* Returns 1 if info structure has been populated, else 0.
|
||||
*/
|
||||
int lv_info(struct logical_volume *lv, struct dm_info *info);
|
||||
int lv_rename(const char *old_name, struct logical_volume *lv);
|
||||
|
||||
int lv_activate(struct logical_volume *lv);
|
||||
int lv_reactivate(struct logical_volume *lv);
|
||||
int lv_deactivate(struct logical_volume *lv);
|
||||
int lv_suspend(struct logical_volume *lv);
|
||||
|
||||
/*
|
||||
* Return number of LVs in the VG that are
|
||||
* active.
|
||||
* These should eventually use config file
|
||||
* to determine whether or not to activate
|
||||
*/
|
||||
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s);
|
||||
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s);
|
||||
int lv_activate(struct cmd_context *cmd, const char *lvid_s);
|
||||
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s);
|
||||
|
||||
/*
|
||||
* FIXME:
|
||||
* I don't like the *lvs_in_vg* function names.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Return number of LVs in the VG that are active.
|
||||
*/
|
||||
int lvs_in_vg_activated(struct volume_group *vg);
|
||||
int lvs_in_vg_opened(struct volume_group *vg);
|
||||
|
||||
/*
|
||||
* Test for (lv->status & LVM_WRITE)
|
||||
*/
|
||||
int lv_update_write_access(struct logical_volume *lv);
|
||||
|
||||
/*
|
||||
* Activate all LVs in the VG. Ignore any that
|
||||
* are already active. Return number
|
||||
* activated.
|
||||
*/
|
||||
int activate_lvs_in_vg(struct volume_group *vg);
|
||||
|
||||
/*
|
||||
* Deactivate all LVs in the VG
|
||||
*/
|
||||
int deactivate_lvs_in_vg(struct volume_group *vg);
|
||||
int lv_setup_cow_store(struct logical_volume *lv);
|
||||
|
||||
#endif
|
||||
|
||||
1527
lib/activate/dev_manager.c
Normal file
1527
lib/activate/dev_manager.c
Normal file
File diff suppressed because it is too large
Load Diff
40
lib/activate/dev_manager.h
Normal file
40
lib/activate/dev_manager.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#ifndef _LVM_DEV_MANAGER_H
|
||||
#define _LVM_DEV_MANAGER_H
|
||||
|
||||
#include "metadata.h"
|
||||
|
||||
#include <libdevmapper.h>
|
||||
|
||||
struct dev_manager;
|
||||
|
||||
/*
|
||||
* Constructor and destructor.
|
||||
*/
|
||||
struct dev_manager *dev_manager_create(const char *vg_name);
|
||||
void dev_manager_destroy(struct dev_manager *dm);
|
||||
|
||||
/*
|
||||
* The device handler is responsible for creating all the layered
|
||||
* dm devices, and ensuring that all constraints are maintained
|
||||
* (eg, an origin is created before its snapshot, but is not
|
||||
* unsuspended until the snapshot is also created.)
|
||||
*/
|
||||
int dev_manager_info(struct dev_manager *dm, struct logical_volume *lv,
|
||||
struct dm_info *info);
|
||||
int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv);
|
||||
int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv);
|
||||
int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv);
|
||||
|
||||
|
||||
/*
|
||||
* Put the desired changes into effect.
|
||||
*/
|
||||
int dev_manager_execute(struct dev_manager *dm);
|
||||
|
||||
#endif
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
|
||||
#ifndef DMFS_INTERFACE_H
|
||||
#define DMFS_INTERFACE_H
|
||||
|
||||
struct dmfs;
|
||||
|
||||
struct dmfs *dmfs_create(void);
|
||||
void dmfs_destroy(struct dmfs *dm);
|
||||
|
||||
int dmfs_dev_is_present(struct dmfs *dm, const char *dev);
|
||||
int dmfs_dev_is_active(struct dmfs *dm, const char *dev);
|
||||
|
||||
int dmfs_table_is_present(struct dmfs *dm, const char *dev, const char *table);
|
||||
int dmfs_table_is_active(struct dmfs *dm, const char *dev, const char *table);
|
||||
|
||||
int dmfs_dev_create(struct dmfs *dm, const char *name);
|
||||
int dmfs_dev_load_table(struct dmfs *dm, const char *dev,
|
||||
const char *table, const char *file);
|
||||
int dmfs_dev_drop_table(struct dmfs *dm, const char *dev, const char *table);
|
||||
|
||||
int dmfs_dev_activate_table(struct dmfs *dm, const char *dev,
|
||||
const char *table);
|
||||
|
||||
int dmfs_dev_deactivate(struct dmfs *dm, const char *dev);
|
||||
|
||||
#endif
|
||||
@@ -4,6 +4,12 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#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>
|
||||
@@ -12,30 +18,27 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fs.h"
|
||||
#include "log.h"
|
||||
#include "names.h"
|
||||
|
||||
#include <libdevmapper.h>
|
||||
|
||||
|
||||
/*
|
||||
* Lazy programmer: I'm just going to always try
|
||||
* and create/remove the vg directory, and not say
|
||||
* anything if it fails.
|
||||
*/
|
||||
static int _mk_dir(struct volume_group *vg)
|
||||
{
|
||||
char vg_path[PATH_MAX];
|
||||
|
||||
if (!build_vg_path(vg_path, sizeof(vg_path),
|
||||
vg->cmd->dev_dir, vg->name)) {
|
||||
log_error("Couldn't construct name of volume group directory.");
|
||||
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
|
||||
vg->cmd->dev_dir, vg->name) == -1) {
|
||||
log_error("Couldn't construct name of volume "
|
||||
"group directory.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dir_exists(vg_path))
|
||||
return 1;
|
||||
|
||||
log_very_verbose("Creating directory %s", vg_path);
|
||||
mkdir(vg_path, 0555);
|
||||
if (mkdir(vg_path, 0555)) {
|
||||
log_sys_error("mkdir", vg_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -44,53 +47,56 @@ static int _rm_dir(struct volume_group *vg)
|
||||
{
|
||||
char vg_path[PATH_MAX];
|
||||
|
||||
if (!build_vg_path(vg_path, sizeof(vg_path),
|
||||
vg->cmd->dev_dir, vg->name)) {
|
||||
log_error("Couldn't construct name of volume group dir for %s",
|
||||
vg->name);
|
||||
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
|
||||
vg->cmd->dev_dir, vg->name) == -1) {
|
||||
log_error("Couldn't construct name of volume "
|
||||
"group directory.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_very_verbose("Removing directory %s", vg_path);
|
||||
rmdir(vg_path);
|
||||
|
||||
if (is_empty_dir(vg_path))
|
||||
rmdir(vg_path);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _mk_link(struct logical_volume *lv)
|
||||
static int _mk_link(struct logical_volume *lv, const char *dev)
|
||||
{
|
||||
char lv_path[PATH_MAX], link_path[PATH_MAX];
|
||||
struct stat buf;
|
||||
|
||||
if (!build_dm_path(lv_path, sizeof(lv_path), lv->vg->name, lv->name)) {
|
||||
log_error("Couldn't create destination pathname for "
|
||||
"logical volume link for %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!build_lv_link_path(link_path, sizeof(link_path),
|
||||
lv->vg->cmd->dev_dir,
|
||||
lv->vg->name, lv->name)) {
|
||||
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
|
||||
lv->vg->cmd->dev_dir, lv->vg->name, lv->name) == -1) {
|
||||
log_error("Couldn't create source pathname for "
|
||||
"logical volume link %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lstat(link_path, &buf)) {
|
||||
if (lvm_snprintf(link_path, sizeof(link_path), "%s/%s",
|
||||
dm_dir(), dev) == -1) {
|
||||
log_error("Couldn't create destination pathname for "
|
||||
"logical volume link for %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lstat(lv_path, &buf)) {
|
||||
if (!S_ISLNK(buf.st_mode)) {
|
||||
log_error("Symbolic link %s not created: file exists",
|
||||
link_path);
|
||||
return 0;
|
||||
}
|
||||
if (unlink(link_path) < 0) {
|
||||
log_sys_error("unlink", link_path);
|
||||
|
||||
if (unlink(lv_path) < 0) {
|
||||
log_sys_error("unlink", lv_path);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
log_very_verbose("Linking %s to %s", link_path, lv_path);
|
||||
if (symlink(lv_path, link_path) < 0) {
|
||||
log_sys_error("symlink", link_path);
|
||||
log_very_verbose("Linking %s -> %s", lv_path, link_path);
|
||||
if (symlink(link_path, lv_path) < 0) {
|
||||
log_sys_error("symlink", lv_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -100,36 +106,31 @@ static int _mk_link(struct logical_volume *lv)
|
||||
static int _rm_link(struct logical_volume *lv, const char *lv_name)
|
||||
{
|
||||
struct stat buf;
|
||||
char link_path[PATH_MAX];
|
||||
char lv_path[PATH_MAX];
|
||||
|
||||
if (!lv_name)
|
||||
lv_name = lv->name;
|
||||
|
||||
if (!build_lv_link_path(link_path, sizeof(link_path),
|
||||
lv->vg->cmd->dev_dir,
|
||||
lv->vg->name, lv->name)) {
|
||||
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
|
||||
lv->vg->cmd->dev_dir, lv->vg->name, lv_name) == -1) {
|
||||
log_error("Couldn't determine link pathname.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_very_verbose("Removing link %s", link_path);
|
||||
if (lstat(link_path, &buf) || !S_ISLNK(buf.st_mode)) {
|
||||
log_error("%s not symbolic link - not removing",
|
||||
link_path);
|
||||
return 0;
|
||||
log_very_verbose("Removing link %s", lv_path);
|
||||
if (lstat(lv_path, &buf) || !S_ISLNK(buf.st_mode)) {
|
||||
log_error("%s not symbolic link - not removing", lv_path);
|
||||
return 0;
|
||||
}
|
||||
if (unlink(link_path) < 0) {
|
||||
log_sys_error("unlink", link_path);
|
||||
|
||||
if (unlink(lv_path) < 0) {
|
||||
log_sys_error("unlink", lv_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fs_add_lv(struct logical_volume *lv)
|
||||
int fs_add_lv(struct logical_volume *lv, const char *dev)
|
||||
{
|
||||
if (!_mk_dir(lv->vg) ||
|
||||
!_mk_link(lv)) {
|
||||
if (!_mk_dir(lv->vg) || !_mk_link(lv, dev)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -139,8 +140,7 @@ int fs_add_lv(struct logical_volume *lv)
|
||||
|
||||
int fs_del_lv(struct logical_volume *lv)
|
||||
{
|
||||
if (!_rm_link(lv, NULL) ||
|
||||
!_rm_dir(lv->vg)) {
|
||||
if (!_rm_link(lv, lv->name) || !_rm_dir(lv->vg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -148,12 +148,14 @@ int fs_del_lv(struct logical_volume *lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fs_rename_lv(const char *old_name, struct logical_volume *lv)
|
||||
/* FIXME Use rename() */
|
||||
int fs_rename_lv(struct logical_volume *lv,
|
||||
const char *dev, const char *old_name)
|
||||
{
|
||||
if (!_rm_link(lv, old_name))
|
||||
if (old_name && !_rm_link(lv, old_name))
|
||||
stack;
|
||||
|
||||
if (!_mk_link(lv))
|
||||
if (!_mk_link(lv, dev))
|
||||
stack;
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
* up the volume group directory in /dev and the
|
||||
* symbolic links to the dm device.
|
||||
*/
|
||||
|
||||
int fs_add_lv(struct logical_volume *lv);
|
||||
int fs_add_lv(struct logical_volume *lv, const char *dev);
|
||||
int fs_del_lv(struct logical_volume *lv);
|
||||
int fs_rename_lv(const char *old_name, struct logical_volume *lv);
|
||||
int fs_rename_lv(struct logical_volume *lv,
|
||||
const char *dev, const char *old_name);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "names.h"
|
||||
#include "lvm-string.h"
|
||||
#include "log.h"
|
||||
#include "limits.h"
|
||||
|
||||
#include <libdevmapper.h>
|
||||
|
||||
/*
|
||||
* The volume group name and the logical volume name are
|
||||
* seperated by a single ':', any colons in the vg name are
|
||||
* doubled up to form a pair.
|
||||
*/
|
||||
int build_dm_name(char *buffer, size_t len,
|
||||
const char *vg_name, const char *lv_name)
|
||||
{
|
||||
char *out;
|
||||
const char *in;
|
||||
|
||||
for (out = buffer, in = vg_name; len && *in; len--) {
|
||||
if (*in == ':') {
|
||||
*out++ = ':';
|
||||
if (!--len)
|
||||
break;
|
||||
}
|
||||
|
||||
*out++ = *in++;
|
||||
len--;
|
||||
}
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
if (lvm_snprintf(out, len, ":%s", lv_name) == -1) {
|
||||
log_err("Couldn't build logical volume name.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int build_dm_path(char *buffer, size_t len,
|
||||
const char *vg_name, const char *lv_name)
|
||||
{
|
||||
char dev_name[PATH_MAX];
|
||||
|
||||
if (!build_dm_name(dev_name, sizeof(dev_name), vg_name, lv_name)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(buffer, len, "%s/%s", dm_dir(), dev_name) == -1) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int build_vg_path(char *buffer, size_t len,
|
||||
const char *dev_dir, const char *vg_name)
|
||||
{
|
||||
if (lvm_snprintf(buffer, len, "%s%s", dev_dir, vg_name) == -1) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int build_lv_link_path(char *buffer, size_t len, const char *dev_dir,
|
||||
const char *vg_name, const char *lv_name)
|
||||
{
|
||||
if (lvm_snprintf(buffer, len, "%s%s/%s",
|
||||
dev_dir, vg_name, lv_name) == -1) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#ifndef _LVM_NAMES_H
|
||||
#define _LVM_NAMES_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
* Functions that build up useful paths to devices, sym-links
|
||||
* etc. Names are passed in as strings, rather than via the
|
||||
* appropriate metadata structures, so we can use it for renaming
|
||||
* devices.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* The name of the device-mapper device for a particular LV.
|
||||
* eg, vg0:music
|
||||
*/
|
||||
int build_dm_name(char *buffer, size_t len,
|
||||
const char *vg_name, const char *lv_name);
|
||||
|
||||
/*
|
||||
* The path of the device-mapper device for a particular LV.
|
||||
* eg, /dev/device-mapper/vg0:music
|
||||
*/
|
||||
int build_dm_path(char *buffer, size_t len,
|
||||
const char *vg_name, const char *lv_name);
|
||||
|
||||
/*
|
||||
* Path to the volume group directory.
|
||||
* eg, /dev/vg0
|
||||
*/
|
||||
int build_vg_path(char *buffer, size_t len,
|
||||
const char *dev_dir, const char *vg_name);
|
||||
|
||||
/*
|
||||
* Path to the symbolic link that lives in the volume group
|
||||
* directory.
|
||||
* eg, /dev/vg0/music
|
||||
*/
|
||||
int build_lv_link_path(char *buffer, size_t len,
|
||||
const char *dev_dir,
|
||||
const char *vg_name, const char *lv_name);
|
||||
|
||||
#endif
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "table-build.c"
|
||||
|
||||
static void _print_run(FILE *fp, struct logical_volume *lv)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
int build_table(struct volume_group *vg, struct logical_volume *lv,
|
||||
const char *file)
|
||||
{
|
||||
int i;
|
||||
uint64_t sector = 0;
|
||||
uint64_t pe_size = vg->extent_size;
|
||||
uint64_t dest;
|
||||
struct pe_specifier *pes;
|
||||
FILE *fp = fopen(file, "w");
|
||||
|
||||
if (!fp) {
|
||||
log_err("couldn't open '%s' to write table", file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < lv->le_count; i++) {
|
||||
pes = lv->map + i;
|
||||
dest = pes->pv->pe_start + (pe_size * pes->pe);
|
||||
fprintf(fp, "%ull %ull linear %s %ull\n",
|
||||
sector, pe_size, pes->pv->dev->name, dest);
|
||||
sector += pe_size;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
|
||||
#ifndef TABLE_BUILD_H
|
||||
#define TABLE_BUILD_H
|
||||
|
||||
int build_table(struct volume_group *vg, struct logical_volume *lv,
|
||||
const char *file);
|
||||
|
||||
#endif
|
||||
16
lib/commands/errors.h
Normal file
16
lib/commands/errors.h
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#ifndef _LVM_ERRORS_H
|
||||
#define _LVM_ERRORS_H
|
||||
|
||||
#define EINVALID_CMD_LINE 1
|
||||
#define ENO_SUCH_CMD 3
|
||||
#define ECMD_PROCESSED 4
|
||||
#define ECMD_FAILED 5
|
||||
|
||||
#endif
|
||||
|
||||
37
lib/commands/toolcontext.h
Normal file
37
lib/commands/toolcontext.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LVM_TOOLCONTEXT_H
|
||||
#define _LVM_TOOLCONTEXT_H
|
||||
|
||||
#include "dev-cache.h"
|
||||
#include "config.h"
|
||||
#include "pool.h"
|
||||
#include "metadata.h"
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* FIXME Move into dynamic list */
|
||||
struct format_type *fmt1; /* Format1 */
|
||||
struct format_type *fmtt; /* Format_text */
|
||||
|
||||
char *cmd_line;
|
||||
char *dev_dir;
|
||||
struct dev_filter *filter;
|
||||
struct config_file *cf;
|
||||
|
||||
struct command *command;
|
||||
struct uuid_map *um;
|
||||
struct arg *args;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -18,34 +18,34 @@
|
||||
#include "log.h"
|
||||
|
||||
enum {
|
||||
TOK_INT,
|
||||
TOK_FLOAT,
|
||||
TOK_STRING,
|
||||
TOK_EQ,
|
||||
TOK_SECTION_B,
|
||||
TOK_SECTION_E,
|
||||
TOK_ARRAY_B,
|
||||
TOK_ARRAY_E,
|
||||
TOK_IDENTIFIER,
|
||||
TOK_INT,
|
||||
TOK_FLOAT,
|
||||
TOK_STRING,
|
||||
TOK_EQ,
|
||||
TOK_SECTION_B,
|
||||
TOK_SECTION_E,
|
||||
TOK_ARRAY_B,
|
||||
TOK_ARRAY_E,
|
||||
TOK_IDENTIFIER,
|
||||
TOK_COMMA,
|
||||
TOK_EOF
|
||||
};
|
||||
|
||||
struct parser {
|
||||
const char *fb, *fe; /* file limits */
|
||||
const char *fb, *fe; /* file limits */
|
||||
|
||||
int t; /* token limits and type */
|
||||
const char *tb, *te;
|
||||
int t; /* token limits and type */
|
||||
const char *tb, *te;
|
||||
|
||||
int fd; /* descriptor for file being parsed */
|
||||
int fd; /* descriptor for file being parsed */
|
||||
int line; /* line number we are on */
|
||||
|
||||
struct pool *mem;
|
||||
struct pool *mem;
|
||||
};
|
||||
|
||||
struct cs {
|
||||
struct config_file cf;
|
||||
struct pool *mem;
|
||||
struct config_file cf;
|
||||
struct pool *mem;
|
||||
};
|
||||
|
||||
static void _get_token(struct parser *p);
|
||||
@@ -68,7 +68,6 @@ static char *_dup_tok(struct parser *p);
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
|
||||
static int _tok_match(const char *str, const char *b, const char *e)
|
||||
{
|
||||
while (*str && (b != e)) {
|
||||
@@ -79,88 +78,92 @@ static int _tok_match(const char *str, const char *b, const char *e)
|
||||
return !(*str || (b != e));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* public interface
|
||||
*/
|
||||
struct config_file *create_config_file(void)
|
||||
{
|
||||
struct cs *c;
|
||||
struct pool *mem = pool_create(10 * 1024);
|
||||
struct cs *c;
|
||||
struct pool *mem = pool_create(10 * 1024);
|
||||
|
||||
if (!mem) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!mem) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(c = pool_alloc(mem, sizeof(*c)))) {
|
||||
stack;
|
||||
pool_destroy(mem);
|
||||
return 0;
|
||||
}
|
||||
if (!(c = pool_alloc(mem, sizeof(*c)))) {
|
||||
stack;
|
||||
pool_destroy(mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
c->mem = mem;
|
||||
c->cf.root = (struct config_node *)NULL;
|
||||
return &c->cf;
|
||||
c->mem = mem;
|
||||
c->cf.root = (struct config_node *) NULL;
|
||||
return &c->cf;
|
||||
}
|
||||
|
||||
void destroy_config_file(struct config_file *cf)
|
||||
{
|
||||
pool_destroy(((struct cs *) cf)->mem);
|
||||
pool_destroy(((struct cs *) cf)->mem);
|
||||
}
|
||||
|
||||
int read_config(struct config_file *cf, const char *file)
|
||||
{
|
||||
struct cs *c = (struct cs *) cf;
|
||||
struct parser *p;
|
||||
struct stat info;
|
||||
int r = 1, fd;
|
||||
struct parser *p;
|
||||
struct stat info;
|
||||
int r = 1, fd;
|
||||
|
||||
if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
p->mem = c->mem;
|
||||
|
||||
/* memory map the file */
|
||||
if (stat(file, &info) || S_ISDIR(info.st_mode)) {
|
||||
log_sys_error("stat", file);
|
||||
return 0;
|
||||
}
|
||||
/* memory map the file */
|
||||
if (stat(file, &info) || S_ISDIR(info.st_mode)) {
|
||||
log_sys_error("stat", file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((fd = open(file, O_RDONLY)) < 0) {
|
||||
log_sys_error("open", file);
|
||||
return 0;
|
||||
}
|
||||
if (info.st_size == 0) {
|
||||
log_verbose("%s is empty", file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
p->fb = mmap((caddr_t) 0, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (p->fb == MAP_FAILED) {
|
||||
log_sys_error("mmap", file);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
p->fe = p->fb + info.st_size;
|
||||
if ((fd = open(file, O_RDONLY)) < 0) {
|
||||
log_sys_error("open", file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* parse */
|
||||
p->tb = p->te = p->fb;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
/* unmap the file */
|
||||
if (munmap((char *) p->fb, info.st_size)) {
|
||||
log_sys_error("munmap", file);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return r;
|
||||
close(fd);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void _write_value(FILE *fp, struct config_value *v)
|
||||
static void _write_value(FILE * fp, struct config_value *v)
|
||||
{
|
||||
switch (v->type) {
|
||||
case CFG_STRING:
|
||||
@@ -177,21 +180,21 @@ static void _write_value(FILE *fp, struct config_value *v)
|
||||
}
|
||||
}
|
||||
|
||||
static int _write_config(struct config_node *n, FILE *fp, int level)
|
||||
static int _write_config(struct config_node *n, FILE * fp, int level)
|
||||
{
|
||||
char space[MAX_INDENT + 1];
|
||||
int l = (level < MAX_INDENT) ? level : MAX_INDENT;
|
||||
int i;
|
||||
char space[MAX_INDENT + 1];
|
||||
int l = (level < MAX_INDENT) ? level : MAX_INDENT;
|
||||
int i;
|
||||
|
||||
if (!n)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < l; i++)
|
||||
space[i] = ' ';
|
||||
space[i] = '\0';
|
||||
for (i = 0; i < l; i++)
|
||||
space[i] = ' ';
|
||||
space[i] = '\0';
|
||||
|
||||
while (n) {
|
||||
fprintf(fp, "%s%s", space, n->key);
|
||||
while (n) {
|
||||
fprintf(fp, "%s%s", space, n->key);
|
||||
if (!n->v) {
|
||||
/* it's a sub section */
|
||||
fprintf(fp, " {\n");
|
||||
@@ -214,8 +217,8 @@ static int _write_config(struct config_node *n, FILE *fp, int level)
|
||||
_write_value(fp, v);
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
n = n->sib;
|
||||
}
|
||||
n = n->sib;
|
||||
}
|
||||
/* FIXME: add error checking */
|
||||
return 1;
|
||||
}
|
||||
@@ -223,17 +226,17 @@ static int _write_config(struct config_node *n, FILE *fp, int level)
|
||||
int write_config(struct config_file *cf, const char *file)
|
||||
{
|
||||
int r = 1;
|
||||
FILE *fp = fopen(file, "w");
|
||||
if (!fp) {
|
||||
log_sys_error("open", file);
|
||||
return 0;
|
||||
}
|
||||
FILE *fp = fopen(file, "w");
|
||||
if (!fp) {
|
||||
log_sys_error("open", file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_write_config(cf->root, fp, 0)) {
|
||||
if (!_write_config(cf->root, fp, 0)) {
|
||||
stack;
|
||||
r = 0;
|
||||
}
|
||||
fclose(fp);
|
||||
fclose(fp);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -260,7 +263,7 @@ static struct config_node *_file(struct parser *p)
|
||||
|
||||
static struct config_node *_section(struct parser *p)
|
||||
{
|
||||
/* IDENTIFIER '{' VALUE* '}' */
|
||||
/* IDENTIFIER '{' VALUE* '}' */
|
||||
struct config_node *root, *n, *l = NULL;
|
||||
if (!(root = _create_node(p))) {
|
||||
stack;
|
||||
@@ -272,7 +275,7 @@ static struct config_node *_section(struct parser *p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
match (TOK_IDENTIFIER);
|
||||
match(TOK_IDENTIFIER);
|
||||
|
||||
if (p->t == TOK_SECTION_B) {
|
||||
match(TOK_SECTION_B);
|
||||
@@ -297,17 +300,17 @@ static struct config_node *_section(struct parser *p)
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
return root;
|
||||
}
|
||||
|
||||
static struct config_value *_value(struct parser *p)
|
||||
{
|
||||
/* '[' TYPE* ']' | TYPE */
|
||||
/* '[' TYPE* ']' | TYPE */
|
||||
struct config_value *h = 0, *l, *ll = 0;
|
||||
if (p->t == TOK_ARRAY_B) {
|
||||
match (TOK_ARRAY_B);
|
||||
while (p->t != TOK_ARRAY_E) {
|
||||
if (!(l = _type(p))) {
|
||||
if (p->t == TOK_ARRAY_B) {
|
||||
match(TOK_ARRAY_B);
|
||||
while (p->t != TOK_ARRAY_E) {
|
||||
if (!(l = _type(p))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -321,48 +324,48 @@ static struct config_value *_value(struct parser *p)
|
||||
if (p->t == TOK_COMMA)
|
||||
match(TOK_COMMA);
|
||||
}
|
||||
match(TOK_ARRAY_E);
|
||||
} else
|
||||
match(TOK_ARRAY_E);
|
||||
} else
|
||||
h = _type(p);
|
||||
|
||||
return h;
|
||||
return h;
|
||||
}
|
||||
|
||||
static struct config_value *_type(struct parser *p)
|
||||
{
|
||||
/* [0-9]+ | [0-9]*\.[0-9]* | ".*" */
|
||||
/* [0-9]+ | [0-9]*\.[0-9]* | ".*" */
|
||||
struct config_value *v = _create_value(p);
|
||||
|
||||
switch (p->t) {
|
||||
case TOK_INT:
|
||||
switch (p->t) {
|
||||
case TOK_INT:
|
||||
v->type = CFG_INT;
|
||||
v->v.i = strtol(p->tb, 0, 0); /* FIXME: check error */
|
||||
match(TOK_INT);
|
||||
break;
|
||||
v->v.i = strtol(p->tb, 0, 0); /* FIXME: check error */
|
||||
match(TOK_INT);
|
||||
break;
|
||||
|
||||
case TOK_FLOAT:
|
||||
case TOK_FLOAT:
|
||||
v->type = CFG_FLOAT;
|
||||
v->v.r = strtod(p->tb, 0); /* FIXME: check error */
|
||||
match(TOK_FLOAT);
|
||||
break;
|
||||
v->v.r = strtod(p->tb, 0); /* FIXME: check error */
|
||||
match(TOK_FLOAT);
|
||||
break;
|
||||
|
||||
case TOK_STRING:
|
||||
case TOK_STRING:
|
||||
v->type = CFG_STRING;
|
||||
|
||||
p->tb++, p->te--; /* strip "'s */
|
||||
p->tb++, p->te--; /* strip "'s */
|
||||
if (!(v->v.str = _dup_tok(p))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
p->te++;
|
||||
match(TOK_STRING);
|
||||
break;
|
||||
match(TOK_STRING);
|
||||
break;
|
||||
|
||||
default:
|
||||
default:
|
||||
log_error("Parse error at line %d: expected a value", p->line);
|
||||
return 0;
|
||||
}
|
||||
return v;
|
||||
return 0;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static int _match_aux(struct parser *p, int t)
|
||||
@@ -379,106 +382,114 @@ static int _match_aux(struct parser *p, int t)
|
||||
*/
|
||||
static void _get_token(struct parser *p)
|
||||
{
|
||||
p->tb = p->te;
|
||||
_eat_space(p);
|
||||
if (p->tb == p->fe) {
|
||||
p->tb = p->te;
|
||||
_eat_space(p);
|
||||
if (p->tb == p->fe) {
|
||||
p->t = TOK_EOF;
|
||||
return;
|
||||
}
|
||||
|
||||
p->t = TOK_INT; /* fudge so the fall through for
|
||||
floats works */
|
||||
switch (*p->te) {
|
||||
case '{':
|
||||
p->t = TOK_SECTION_B;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '}':
|
||||
p->t = TOK_SECTION_E;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
p->t = TOK_ARRAY_B;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case ']':
|
||||
p->t = TOK_ARRAY_E;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case ',':
|
||||
p->t = TOK_COMMA;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '=':
|
||||
p->t = TOK_EQ;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '"':
|
||||
p->t = TOK_STRING;
|
||||
p->t = TOK_INT; /* fudge so the fall through for
|
||||
floats works */
|
||||
switch (*p->te) {
|
||||
case '{':
|
||||
p->t = TOK_SECTION_B;
|
||||
p->te++;
|
||||
while ((p->te != p->fe) && (*p->te != '"')) {
|
||||
if ((*p->te == '\\') && (p->te + 1 != p->fe))
|
||||
p->te++;
|
||||
p->te++;
|
||||
}
|
||||
break;
|
||||
|
||||
if (p->te != p->fe)
|
||||
p->te++;
|
||||
break;
|
||||
case '}':
|
||||
p->t = TOK_SECTION_E;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '.':
|
||||
p->t = TOK_FLOAT;
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
p->te++;
|
||||
while (p->te != p->fe) {
|
||||
if (*p->te == '.') {
|
||||
if (p->t == TOK_FLOAT)
|
||||
break;
|
||||
p->t = TOK_FLOAT;
|
||||
} else if (!isdigit((int) *p->te))
|
||||
break;
|
||||
p->te++;
|
||||
}
|
||||
break;
|
||||
case '[':
|
||||
p->t = TOK_ARRAY_B;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
default:
|
||||
p->t = TOK_IDENTIFIER;
|
||||
while ((p->te != p->fe) && !isspace(*p->te) &&
|
||||
(*p->te != '#') && (*p->te != '='))
|
||||
p->te++;
|
||||
break;
|
||||
}
|
||||
case ']':
|
||||
p->t = TOK_ARRAY_E;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case ',':
|
||||
p->t = TOK_COMMA;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '=':
|
||||
p->t = TOK_EQ;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '"':
|
||||
p->t = TOK_STRING;
|
||||
p->te++;
|
||||
while ((p->te != p->fe) && (*p->te != '"')) {
|
||||
if ((*p->te == '\\') && (p->te + 1 != p->fe))
|
||||
p->te++;
|
||||
p->te++;
|
||||
}
|
||||
|
||||
if (p->te != p->fe)
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '.':
|
||||
p->t = TOK_FLOAT;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
p->te++;
|
||||
while (p->te != p->fe) {
|
||||
if (*p->te == '.') {
|
||||
if (p->t == TOK_FLOAT)
|
||||
break;
|
||||
p->t = TOK_FLOAT;
|
||||
} else if (!isdigit((int) *p->te))
|
||||
break;
|
||||
p->te++;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
p->t = TOK_IDENTIFIER;
|
||||
while ((p->te != p->fe) && !isspace(*p->te) &&
|
||||
(*p->te != '#') && (*p->te != '='))
|
||||
p->te++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void _eat_space(struct parser *p)
|
||||
{
|
||||
while (p->tb != p->fe) {
|
||||
if (*p->te == '#') {
|
||||
while ((p->te != p->fe) && (*p->te != '\n'))
|
||||
p->te++;
|
||||
while (p->tb != p->fe) {
|
||||
if (*p->te == '#') {
|
||||
while ((p->te != p->fe) && (*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) && isspace(*p->te)) {
|
||||
if (*p->te == '\n')
|
||||
p->line++;
|
||||
p->te++;
|
||||
p->te++;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
return;
|
||||
else
|
||||
return;
|
||||
|
||||
p->tb = p->te;
|
||||
}
|
||||
p->tb = p->te;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -525,8 +536,7 @@ struct config_node *find_config_node(struct config_node *cn,
|
||||
path++;
|
||||
|
||||
/* find the end of this segment */
|
||||
for (e = path; *e && (*e != sep); e++)
|
||||
;
|
||||
for (e = path; *e && (*e != sep); e++) ;
|
||||
|
||||
/* hunt for the node */
|
||||
while (cn) {
|
||||
@@ -547,20 +557,20 @@ struct config_node *find_config_node(struct config_node *cn,
|
||||
return cn;
|
||||
}
|
||||
|
||||
const char *
|
||||
find_config_str(struct config_node *cn,
|
||||
const char *path, char sep, const char *fail)
|
||||
const char *find_config_str(struct config_node *cn,
|
||||
const char *path, char sep, const char *fail)
|
||||
{
|
||||
struct config_node *n = find_config_node(cn, path, sep);
|
||||
|
||||
if (n && n->v->type == CFG_STRING) {
|
||||
log_very_verbose("Setting %s to %s", path, n->v->v.str);
|
||||
if (*n->v->v.str)
|
||||
log_very_verbose("Setting %s to %s", path, n->v->v.str);
|
||||
return n->v->v.str;
|
||||
}
|
||||
|
||||
if (fail)
|
||||
log_very_verbose("%s not found in config: defaulting to %s",
|
||||
path, fail);
|
||||
path, fail);
|
||||
return fail;
|
||||
}
|
||||
|
||||
@@ -574,7 +584,7 @@ int find_config_int(struct config_node *cn, const char *path,
|
||||
return n->v->v.i;
|
||||
}
|
||||
|
||||
log_very_verbose("%s not found in config: defaulting to %d",
|
||||
log_very_verbose("%s not found in config: defaulting to %d",
|
||||
path, fail);
|
||||
return fail;
|
||||
}
|
||||
@@ -590,7 +600,7 @@ float find_config_float(struct config_node *cn, const char *path,
|
||||
}
|
||||
|
||||
log_very_verbose("%s not found in config: defaulting to %f",
|
||||
path, fail);
|
||||
path, fail);
|
||||
|
||||
return fail;
|
||||
|
||||
@@ -609,8 +619,9 @@ static int _str_in_array(const char *str, const char *values[])
|
||||
|
||||
static int _str_to_bool(const char *str, int fail)
|
||||
{
|
||||
static const char *_true_values[] = {"y", "yes", "on", "true", NULL};
|
||||
static const char *_false_values[] = {"n", "no", "off", "false", NULL};
|
||||
static const char *_true_values[] = { "y", "yes", "on", "true", NULL };
|
||||
static const char *_false_values[] =
|
||||
{ "n", "no", "off", "false", NULL };
|
||||
|
||||
if (_str_in_array(str, _true_values))
|
||||
return 1;
|
||||
@@ -622,7 +633,7 @@ static int _str_to_bool(const char *str, int fail)
|
||||
}
|
||||
|
||||
int find_config_bool(struct config_node *cn, const char *path,
|
||||
char sep, int fail)
|
||||
char sep, int fail)
|
||||
{
|
||||
struct config_node *n = find_config_node(cn, path, sep);
|
||||
struct config_value *v;
|
||||
@@ -644,7 +655,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;
|
||||
|
||||
@@ -658,7 +669,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;
|
||||
|
||||
@@ -671,4 +682,3 @@ int get_config_uint64(struct config_node *cn, const char *path,
|
||||
*result = (uint64_t) n->v->v.i;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,12 @@
|
||||
#define DEFAULT_DEV_DIR "/dev"
|
||||
#define DEFAULT_PROC_DIR "/proc"
|
||||
|
||||
#define DEFAULT_LOCK_DIR "/var/lock/lvm"
|
||||
|
||||
#define DEFAULT_UMASK 0077
|
||||
|
||||
#define DEFAULT_FORMAT "lvm1"
|
||||
|
||||
#ifdef READLINE_SUPPORT
|
||||
#define DEFAULT_MAX_HISTORY 100
|
||||
#endif
|
||||
@@ -12,7 +12,7 @@
|
||||
/* 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;
|
||||
@@ -33,7 +33,7 @@ void bitset_destroy(bitset_t bs)
|
||||
void bit_union(bitset_t out, bitset_t in1, bitset_t in2)
|
||||
{
|
||||
int i;
|
||||
for(i = (in1[0] / BITS_PER_INT) + 1; i; i--)
|
||||
for (i = (in1[0] / BITS_PER_INT) + 1; i; i--)
|
||||
out[i] = in1[i] | in2[i];
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ int bit_get_next(bitset_t bs, int last_bit)
|
||||
|
||||
last_bit++; /* otherwise we'll return the same bit again */
|
||||
|
||||
while(last_bit < bs[0]) {
|
||||
while (last_bit < bs[0]) {
|
||||
word = last_bit >> INT_SHIFT;
|
||||
test = bs[word + 1];
|
||||
bit = last_bit & (BITS_PER_INT - 1);
|
||||
@@ -66,8 +66,8 @@ int bit_get_next(bitset_t bs, int last_bit)
|
||||
if ((bit = _test_word(test, bit)) >= 0)
|
||||
return (word * BITS_PER_INT) + bit;
|
||||
|
||||
last_bit = last_bit - (last_bit & (BITS_PER_INT - 1)) +
|
||||
BITS_PER_INT;
|
||||
last_bit = last_bit - (last_bit & (BITS_PER_INT - 1)) +
|
||||
BITS_PER_INT;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
@@ -40,8 +40,7 @@ static uint32_t _shuffle(uint32_t k)
|
||||
#if 1
|
||||
return ((k & 0xff) << 24 |
|
||||
(k & 0xff00) << 8 |
|
||||
(k & 0xff0000) >> 8 |
|
||||
(k & 0xff000000) >> 24);
|
||||
(k & 0xff0000) >> 8 | (k & 0xff000000) >> 24);
|
||||
#else
|
||||
return k;
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
|
||||
#include "dbg_malloc.h"
|
||||
#include "hash.h"
|
||||
#include "log.h"
|
||||
@@ -23,22 +22,30 @@ struct hash_table {
|
||||
|
||||
/* Permutation of the Integers 0 through 255 */
|
||||
static unsigned char _nums[] = {
|
||||
1, 14,110, 25, 97,174,132,119,138,170,125,118, 27,233,140, 51,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
193,239,101,242, 5,171,126, 11, 74, 59,137,228,108,191,232,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,
|
||||
249,236, 45,244,111,182,153,136,129, 90,217,202, 19,165,231, 71,
|
||||
230,142, 96,227, 62,179,246,114,162, 53,160,215,205,180, 47,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
|
||||
1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232,
|
||||
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,
|
||||
249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231,
|
||||
71,
|
||||
230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47,
|
||||
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
|
||||
};
|
||||
|
||||
static struct hash_node *_create_node(const char *str)
|
||||
@@ -83,7 +90,7 @@ struct hash_table *hash_create(unsigned size_hint)
|
||||
|
||||
/* round size hint up to a power of two */
|
||||
while (new_size < size_hint)
|
||||
new_size = new_size << 1;
|
||||
new_size = new_size << 1;
|
||||
|
||||
hc->num_slots = new_size;
|
||||
len = sizeof(*(hc->slots)) * new_size;
|
||||
@@ -94,7 +101,7 @@ struct hash_table *hash_create(unsigned size_hint)
|
||||
memset(hc->slots, 0, len);
|
||||
return hc;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
dbg_free(hc->slots);
|
||||
dbg_free(hc);
|
||||
return 0;
|
||||
@@ -124,8 +131,8 @@ static inline struct hash_node **_find(struct hash_table *t, const char *key)
|
||||
unsigned h = _hash(key) & (t->num_slots - 1);
|
||||
struct hash_node **c;
|
||||
|
||||
for(c = &t->slots[h]; *c; c = &((*c)->next))
|
||||
if(!strcmp(key, (*c)->key))
|
||||
for (c = &t->slots[h]; *c; c = &((*c)->next))
|
||||
if (!strcmp(key, (*c)->key))
|
||||
break;
|
||||
|
||||
return c;
|
||||
@@ -141,7 +148,7 @@ int hash_insert(struct hash_table *t, const char *key, void *data)
|
||||
{
|
||||
struct hash_node **c = _find(t, key);
|
||||
|
||||
if(*c)
|
||||
if (*c)
|
||||
(*c)->data = data;
|
||||
else {
|
||||
struct hash_node *n = _create_node(key);
|
||||
@@ -175,7 +182,7 @@ unsigned hash_get_num_entries(struct hash_table *t)
|
||||
return t->num_nodes;
|
||||
}
|
||||
|
||||
void hash_iterate(struct hash_table *t, iterate_fn f)
|
||||
void hash_iter(struct hash_table *t, iterate_fn f)
|
||||
{
|
||||
struct hash_node *c;
|
||||
int i;
|
||||
@@ -223,4 +230,3 @@ struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n)
|
||||
unsigned int h = _hash(n->key) & (t->num_slots - 1);
|
||||
return n->next ? n->next : _next_slot(t, h + 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,12 +21,16 @@ int hash_insert(struct hash_table *t, const char *key, void *data);
|
||||
void hash_remove(struct hash_table *t, const char *key);
|
||||
|
||||
unsigned hash_get_num_entries(struct hash_table *t);
|
||||
void hash_iterate(struct hash_table *t, iterate_fn f);
|
||||
void hash_iter(struct hash_table *t, iterate_fn f);
|
||||
|
||||
char *hash_get_key(struct hash_table *t, struct hash_node *n);
|
||||
void *hash_get_data(struct hash_table *t, struct hash_node *n);
|
||||
struct hash_node *hash_get_first(struct hash_table *t);
|
||||
struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n);
|
||||
|
||||
#define hash_iterate(v, h) \
|
||||
for (v = hash_get_first(h); v; \
|
||||
v = hash_get_next(h, v))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -46,7 +46,6 @@ static struct {
|
||||
|
||||
} _cache;
|
||||
|
||||
|
||||
#define _alloc(x) pool_alloc(_cache.mem, (x))
|
||||
#define _free(x) pool_free(_cache.mem, (x))
|
||||
|
||||
@@ -194,7 +193,7 @@ static int _insert(const char *path, int rec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (S_ISDIR(info.st_mode)) { /* add a directory */
|
||||
if (S_ISDIR(info.st_mode)) { /* add a directory */
|
||||
if (rec)
|
||||
r = _insert_dir(path);
|
||||
|
||||
@@ -255,7 +254,7 @@ int dev_cache_init(void)
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
dev_cache_exit();
|
||||
return 0;
|
||||
}
|
||||
@@ -268,7 +267,7 @@ void _check_closed(struct device *dev)
|
||||
|
||||
static inline void _check_for_open_devices(void)
|
||||
{
|
||||
hash_iterate(_cache.names, (iterate_fn)_check_closed);
|
||||
hash_iter(_cache.names, (iterate_fn) _check_closed);
|
||||
}
|
||||
|
||||
void dev_cache_exit(void)
|
||||
@@ -313,8 +312,8 @@ const char *dev_name_confirmed(struct device *dev)
|
||||
char *name;
|
||||
int r;
|
||||
|
||||
while ((r = stat(name = list_item(dev->aliases.n,
|
||||
struct str_list)->str, &buf)) ||
|
||||
while ((r = stat(name = list_item(dev->aliases.n,
|
||||
struct str_list)->str, &buf)) ||
|
||||
(buf.st_rdev != dev->dev)) {
|
||||
if (r < 0)
|
||||
log_sys_error("stat", name);
|
||||
@@ -342,7 +341,6 @@ const char *dev_name_confirmed(struct device *dev)
|
||||
return dev_name(dev);
|
||||
}
|
||||
|
||||
|
||||
struct device *dev_cache_get(const char *name, struct dev_filter *f)
|
||||
{
|
||||
struct stat buf;
|
||||
@@ -399,4 +397,3 @@ struct device *dev_iter_get(struct dev_iter *iter)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/fs.h> // UGH!!! for BLKSSZGET
|
||||
#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;
|
||||
@@ -93,9 +93,16 @@ int dev_open(struct device *dev, int flags)
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev->flags = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _flush(int fd)
|
||||
{
|
||||
ioctl(fd, BLKFLSBUF, 0);
|
||||
}
|
||||
|
||||
int dev_close(struct device *dev)
|
||||
{
|
||||
if (dev->fd < 0) {
|
||||
@@ -104,6 +111,9 @@ int dev_close(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dev->flags & DEV_ACCESSED_W)
|
||||
_flush(dev->fd);
|
||||
|
||||
if (close(dev->fd))
|
||||
log_sys_error("close", dev_name(dev));
|
||||
|
||||
@@ -135,7 +145,7 @@ int _read(int fd, void *buf, size_t count)
|
||||
return tot;
|
||||
}
|
||||
|
||||
int64_t dev_read(struct device *dev, uint64_t offset,
|
||||
int64_t dev_read(struct device * dev, uint64_t offset,
|
||||
int64_t len, void *buffer)
|
||||
{
|
||||
const char *name = dev_name(dev);
|
||||
@@ -178,7 +188,7 @@ int _write(int fd, const void *buf, size_t count)
|
||||
return tot;
|
||||
}
|
||||
|
||||
int64_t dev_write(struct device *dev, uint64_t offset,
|
||||
int64_t dev_write(struct device * dev, uint64_t offset,
|
||||
int64_t len, void *buffer)
|
||||
{
|
||||
const char *name = dev_name(dev);
|
||||
@@ -194,6 +204,8 @@ int64_t dev_write(struct device *dev, uint64_t offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev->flags |= DEV_ACCESSED_W;
|
||||
|
||||
return _write(fd, buffer, len);
|
||||
}
|
||||
|
||||
@@ -230,6 +242,8 @@ int dev_zero(struct device *dev, uint64_t offset, int64_t len)
|
||||
}
|
||||
}
|
||||
|
||||
dev->flags |= DEV_ACCESSED_W;
|
||||
|
||||
/* FIXME: Always display error */
|
||||
return (len == 0);
|
||||
}
|
||||
|
||||
@@ -38,8 +38,6 @@
|
||||
#include <linux/major.h>
|
||||
#include <linux/genhd.h>
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
int _get_partition_type(struct dev_filter *filter, struct device *d);
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "lvm-types.h"
|
||||
#include "list.h"
|
||||
|
||||
#define DEV_ACCESSED_W 0x00000001 /* Device written to? */
|
||||
|
||||
/*
|
||||
* All devices in LVM will be represented by one of these.
|
||||
* pointer comparisons are valid.
|
||||
@@ -20,6 +22,7 @@ struct device {
|
||||
|
||||
/* private */
|
||||
int fd;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct device_list {
|
||||
@@ -44,7 +47,8 @@ int dev_zero(struct device *dev, uint64_t offset, int64_t len);
|
||||
|
||||
|
||||
static inline const char *dev_name(struct device *dev) {
|
||||
return list_item(dev->aliases.n, struct str_list)->str;
|
||||
return (dev) ? list_item(dev->aliases.n, struct str_list)->str :
|
||||
"unknown device";
|
||||
}
|
||||
|
||||
/* Return a valid device name from the alias list; NULL otherwise */
|
||||
|
||||
@@ -24,13 +24,14 @@
|
||||
#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(unsigned long long size, size_len_t sl)
|
||||
char *display_size(uint64_t size, size_len_t sl)
|
||||
{
|
||||
int s;
|
||||
ulong byte = 1024 * 1024 * 1024;
|
||||
@@ -78,12 +79,12 @@ void pvdisplay_colons(struct physical_volume *pv)
|
||||
dev_name(pv->dev), pv->vg_name, pv->size,
|
||||
/* FIXME pv->pv_number, Derive or remove? */
|
||||
pv->status, /* FIXME Support old or new format here? */
|
||||
pv->status & ALLOCATABLE_PV, /* FIXME remove? */
|
||||
pv->status & ALLOCATABLE_PV, /* FIXME remove? */
|
||||
/* FIXME pv->lv_cur, Remove? */
|
||||
pv->pe_size / 2,
|
||||
pv->pe_count,
|
||||
pv->pe_count - pv->pe_allocated,
|
||||
pv->pe_allocated, *uuid ? uuid : "none");
|
||||
pv->pe_count - pv->pe_alloc_count,
|
||||
pv->pe_alloc_count, *uuid ? uuid : "none");
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -103,22 +104,36 @@ 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(pv->size / 2, SIZE_SHORT);
|
||||
size = display_size((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
|
||||
/******** FIXME display LVM on-disk data size - static for now...
|
||||
size2 = display_size(pv->size / 2, SIZE_SHORT);
|
||||
********/
|
||||
|
||||
log_print("PV Size %s" " / not usable %s", /* [LVM: %s]", */
|
||||
size, size1); /* , size2); */
|
||||
log_print("PV Size %s [%llu secs]" " / not "
|
||||
"usable %s [LVM: %s]",
|
||||
size, (uint64_t) pv->size, size1, "151 KB");
|
||||
/* , size2); */
|
||||
|
||||
dbg_free(size1);
|
||||
/* dbg_free(size2); */
|
||||
@@ -126,24 +141,27 @@ void pvdisplay_full(struct physical_volume *pv)
|
||||
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);
|
||||
**********/
|
||||
|
||||
pe_free = pv->pe_count - pv->pe_allocated;
|
||||
pe_free = pv->pe_count - pv->pe_alloc_count;
|
||||
if (pv->pe_count && (pv->status & ALLOCATABLE_PV))
|
||||
log_print("Allocatable yes %s",
|
||||
(!pe_free && pv->pe_count) ? "(but full)" : "");
|
||||
else
|
||||
log_print("Allocatable NO");
|
||||
|
||||
/*********FIXME
|
||||
log_print("Cur LV %u", pv->lv_cur);
|
||||
*********/
|
||||
/*********FIXME Erm...where is this stored?
|
||||
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_allocated);
|
||||
log_print("Allocated PE %u", pv->pe_alloc_count);
|
||||
|
||||
#ifdef LVM_FUTURE
|
||||
printf("Stale PE %u", pv->pe_stale);
|
||||
@@ -155,7 +173,8 @@ void pvdisplay_full(struct physical_volume *pv)
|
||||
return;
|
||||
}
|
||||
|
||||
int pvdisplay_short(struct volume_group *vg, struct physical_volume *pv)
|
||||
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct physical_volume *pv)
|
||||
{
|
||||
if (!pv)
|
||||
return 0;
|
||||
@@ -165,12 +184,14 @@ int pvdisplay_short(struct volume_group *vg, struct physical_volume *pv)
|
||||
log_print("PV Status %sallocatable",
|
||||
(pv->status & ALLOCATABLE_PV) ? "" : "NOT ");
|
||||
log_print("Total PE / Free PE %u / %u",
|
||||
pv->pe_count, pv->pe_count - pv->pe_allocated);
|
||||
pv->pe_count, pv->pe_count - pv->pe_alloc_count);
|
||||
|
||||
log_print(" ");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void lvdisplay_colons(struct logical_volume *lv)
|
||||
{
|
||||
int inkernel;
|
||||
@@ -182,37 +203,67 @@ void lvdisplay_colons(struct logical_volume *lv)
|
||||
lv->vg->name,
|
||||
lv->name,
|
||||
lv->vg->name,
|
||||
(lv->status & (LVM_READ | LVM_WRITE)) >> 8,
|
||||
inkernel ? 1 : 0,
|
||||
(lv->status & (LVM_READ | LVM_WRITE)) >> 8, inkernel ? 1 : 0,
|
||||
/* 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,
|
||||
inkernel ? info.major : -1,
|
||||
inkernel ? info.minor : -1
|
||||
);
|
||||
inkernel ? info.major : -1, inkernel ? info.minor : -1);
|
||||
return;
|
||||
}
|
||||
|
||||
int lvdisplay_full(struct logical_volume *lv)
|
||||
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
char *size;
|
||||
uint32_t alloc;
|
||||
struct dm_info info;
|
||||
int inkernel;
|
||||
char uuid[64];
|
||||
struct snapshot *snap;
|
||||
struct stripe_segment *seg;
|
||||
struct list *lvseg;
|
||||
struct logical_volume *origin;
|
||||
|
||||
if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 origina for a snapshot */
|
||||
if ((snap = find_origin(lv))) {
|
||||
log_print("LV snapshot status source of");
|
||||
log_print(" %s%s/%s [%s]",
|
||||
lv->vg->cmd->dev_dir, lv->vg->name, snap->cow->name,
|
||||
"active");
|
||||
/* reset so we don't try to use this to display other snapshot
|
||||
* related information. */
|
||||
snap = NULL;
|
||||
}
|
||||
/* Check to see if this LV is a COW target for a snapshot */
|
||||
else if ((snap = find_cow(lv)))
|
||||
log_print("LV snapshot status %s destination for %s%s/%s",
|
||||
"active", lv->vg->cmd->dev_dir, lv->vg->name,
|
||||
snap->origin->name);
|
||||
|
||||
|
||||
/******* FIXME Snapshot
|
||||
if (lv->status & (LVM_SNAPSHOT_ORG | LVM_SNAPSHOT)) {
|
||||
if (lvm_tab_vg_read_with_pv_and_lv(vg_name, &vg) < 0) {
|
||||
@@ -262,15 +313,19 @@ int lvdisplay_full(struct logical_volume *lv)
|
||||
log_print("LV Status suspended");
|
||||
else
|
||||
log_print("LV Status %savailable",
|
||||
inkernel ? "" : "NOT ");
|
||||
inkernel ? "" : "NOT ");
|
||||
|
||||
/********* FIXME lv_number
|
||||
/********* FIXME lv_number - not sure that we're going to bother with this
|
||||
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);
|
||||
@@ -283,15 +338,46 @@ int lvdisplay_full(struct logical_volume *lv)
|
||||
#endif
|
||||
********/
|
||||
|
||||
size = display_size(lv->size / 2, SIZE_SHORT);
|
||||
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("Current LE %u", lv->le_count);
|
||||
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);
|
||||
/**********/
|
||||
|
||||
|
||||
/********** FIXME allocation
|
||||
log_print("Allocated LE %u", lv->allocated_le);
|
||||
**********/
|
||||
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;
|
||||
}
|
||||
|
||||
if(snap) {
|
||||
/*char *s1, *s2;*/
|
||||
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);
|
||||
/* s1 = display_size();*/
|
||||
log_print("Allocated to snapshot %s [%s/%s]", "NA", "NA", size);
|
||||
dbg_free(size);
|
||||
/* size = display_size(snap->cow->size / 2, SIZE_SHORT); */
|
||||
log_print("Allocated to COW-table %s", "NA");
|
||||
/* dbg_free(size); */
|
||||
}
|
||||
|
||||
/********** FIXME Snapshot
|
||||
if (lv->lv_access & LV_SNAPSHOT) {
|
||||
@@ -325,7 +411,9 @@ int lvdisplay_full(struct logical_volume *lv)
|
||||
}
|
||||
******************/
|
||||
|
||||
/** 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);
|
||||
@@ -353,6 +441,9 @@ int lvdisplay_full(struct logical_volume *lv)
|
||||
|
||||
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) ");
|
||||
@@ -364,7 +455,7 @@ int lvdisplay_full(struct logical_volume *lv)
|
||||
*************/
|
||||
|
||||
if (inkernel)
|
||||
log_print("Block device %d:%d", info.major,
|
||||
log_print("Block device %d:%d", info.major,
|
||||
info.minor);
|
||||
|
||||
log_print(" ");
|
||||
@@ -381,7 +472,7 @@ void _display_stripe(struct stripe_segment *seg, int s, const char *pre)
|
||||
|
||||
if (seg->area[s].pv)
|
||||
log_print("%sphysical extents\t%d to %d", pre,
|
||||
seg->area[s].pe, seg->area[s].pe + len - 1);
|
||||
seg->area[s].pe, seg->area[s].pe + len - 1);
|
||||
}
|
||||
|
||||
int lvdisplay_segments(struct logical_volume *lv)
|
||||
@@ -392,7 +483,7 @@ int lvdisplay_segments(struct logical_volume *lv)
|
||||
|
||||
log_print("--- Segments ---");
|
||||
|
||||
list_iterate (segh, &lv->segments) {
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct stripe_segment);
|
||||
|
||||
log_print("logical extent %d to %d:",
|
||||
@@ -417,8 +508,6 @@ int lvdisplay_segments(struct logical_volume *lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vgdisplay_extents(struct volume_group *vg)
|
||||
{
|
||||
return;
|
||||
@@ -429,10 +518,27 @@ void vgdisplay_full(struct volume_group *vg)
|
||||
uint32_t access;
|
||||
char *s1;
|
||||
char uuid[64];
|
||||
uint32_t active_pvs;
|
||||
struct list *pvlist;
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
else
|
||||
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);
|
||||
*******/
|
||||
access = vg->status & (LVM_READ | LVM_WRITE);
|
||||
log_print("VG Access %s%s%s%s",
|
||||
access == (LVM_READ | LVM_WRITE) ? "read/write" : "",
|
||||
@@ -440,33 +546,28 @@ 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/" : "",
|
||||
vg->status & EXPORTED_VG ? "exported/" : "available/",
|
||||
vg->status & RESIZEABLE_VG ? "" : "NOT ");
|
||||
/******* FIXME vg number
|
||||
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);
|
||||
/****** FIXME Open LVs
|
||||
log_print ( "Open LV %u", vg->lv_open);
|
||||
*******/
|
||||
/****** 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("Open LV %u", lvs_in_vg_opened(vg));
|
||||
log_print("MAX LV Size 256 TB");
|
||||
log_print("Max PV %u", vg->max_pv);
|
||||
log_print("Cur PV %u", vg->pv_count);
|
||||
/******* FIXME act PVs
|
||||
log_print ( "Act PV %u", vg->pv_act);
|
||||
*********/
|
||||
log_print("Act PV %u", active_pvs);
|
||||
|
||||
s1 = display_size(vg->extent_count * vg->extent_size / 2, SIZE_SHORT);
|
||||
s1 =
|
||||
display_size((uint64_t) vg->extent_count * (vg->extent_size / 2),
|
||||
SIZE_SHORT);
|
||||
log_print("VG Size %s", s1);
|
||||
dbg_free(s1);
|
||||
|
||||
@@ -476,14 +577,16 @@ void vgdisplay_full(struct volume_group *vg)
|
||||
|
||||
log_print("Total PE %u", vg->extent_count);
|
||||
|
||||
s1 =
|
||||
display_size((vg->extent_count - vg->free_count) *
|
||||
vg->extent_size / 2, SIZE_SHORT);
|
||||
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);
|
||||
|
||||
s1 = display_size(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);
|
||||
|
||||
|
||||
@@ -28,16 +28,16 @@
|
||||
typedef enum {SIZE_LONG=0, SIZE_SHORT=1} size_len_t;
|
||||
|
||||
/* Specify size in KB */
|
||||
char *display_size(unsigned long long size, size_len_t sl);
|
||||
char *display_size(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 volume_group *vg, struct physical_volume *pv);
|
||||
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv);
|
||||
|
||||
void lvdisplay_colons(struct logical_volume *lv);
|
||||
int lvdisplay_segments(struct logical_volume *lv);
|
||||
int lvdisplay_full(struct logical_volume *lv);
|
||||
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv);
|
||||
|
||||
void vgdisplay_extents(struct volume_group *vg);
|
||||
void vgdisplay_full(struct volume_group *vg);
|
||||
|
||||
@@ -36,7 +36,6 @@ static void _destroy(struct dev_filter *f)
|
||||
dbg_free(f);
|
||||
}
|
||||
|
||||
|
||||
struct dev_filter *composite_filter_create(int n, ...)
|
||||
{
|
||||
struct dev_filter **filters = dbg_malloc(sizeof(*filters) * (n + 1));
|
||||
|
||||
@@ -54,7 +54,7 @@ static int _read_array(struct pfilter *pf, struct config_file *cf,
|
||||
|
||||
if (!(cn = find_config_node(cf->root, path, '/'))) {
|
||||
log_very_verbose("Couldn't find %s array in '%s'",
|
||||
path, pf->file);
|
||||
path, pf->file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -65,13 +65,13 @@ static int _read_array(struct pfilter *pf, struct config_file *cf,
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != CFG_STRING) {
|
||||
log_verbose("Devices array contains a value "
|
||||
"which is not a string ... ignoring");
|
||||
"which is not a string ... ignoring");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hash_insert(pf->devices, cv->v.str, data))
|
||||
log_verbose("Couldn't add '%s' to filter ... ignoring",
|
||||
cv->v.str);
|
||||
cv->v.str);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -101,12 +101,12 @@ int persistent_filter_load(struct dev_filter *f)
|
||||
if (hash_get_num_entries(pf->devices))
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
out:
|
||||
destroy_config_file(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;
|
||||
@@ -175,7 +175,7 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
|
||||
|
||||
if (!l) {
|
||||
l = pf->real->passes_filter(pf->real, dev) ?
|
||||
PF_GOOD_DEVICE : PF_BAD_DEVICE;
|
||||
PF_GOOD_DEVICE : PF_BAD_DEVICE;
|
||||
|
||||
list_iterate(ah, &dev->aliases) {
|
||||
sl = list_item(ah, struct str_list);
|
||||
@@ -232,7 +232,7 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
|
||||
|
||||
return f;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
dbg_free(pf->file);
|
||||
if (pf->devices)
|
||||
hash_destroy(pf->devices);
|
||||
|
||||
@@ -128,8 +128,7 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
||||
* the matcher gives.
|
||||
*/
|
||||
for (v = val, i = count - 1; v; v = v->next, i--)
|
||||
if (!_extract_pattern(scratch, v->v.str,
|
||||
regex, rf->accept, i)) {
|
||||
if (!_extract_pattern(scratch, v->v.str, regex, rf->accept, i)) {
|
||||
log_info("invalid filter pattern");
|
||||
goto out;
|
||||
}
|
||||
@@ -137,12 +136,12 @@ 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)))
|
||||
if (!(rf->engine = matcher_create(rf->mem, (const char **) regex,
|
||||
count)))
|
||||
stack;
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
out:
|
||||
pool_destroy(scratch);
|
||||
return r;
|
||||
}
|
||||
@@ -221,8 +220,7 @@ struct dev_filter *regex_filter_create(struct config_value *patterns)
|
||||
f->private = rf;
|
||||
return f;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
pool_destroy(mem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,12 +71,12 @@ static int passes_lvm_type_device_filter(struct dev_filter *f,
|
||||
return 0;
|
||||
|
||||
/* Check it's accessible */
|
||||
if ((fd = open(name, O_RDONLY)) < 0) {
|
||||
log_debug("Unable to open %s: %s", name, strerror(errno));
|
||||
if ((fd = open(name, O_RDONLY)) < 0) {
|
||||
log_debug("Unable to open %s: %s", name, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
close(fd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -85,7 +85,7 @@ struct dev_filter *lvm_type_filter_create(const char *proc)
|
||||
{
|
||||
struct dev_filter *f;
|
||||
|
||||
if (!(f = dbg_malloc(sizeof (struct dev_filter)))) {
|
||||
if (!(f = dbg_malloc(sizeof(struct dev_filter)))) {
|
||||
log_error("LVM type filter allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
@@ -124,12 +124,13 @@ static int *scan_proc_dev(const char *proc)
|
||||
|
||||
int *max_partitions_by_major;
|
||||
|
||||
if (!(max_partitions_by_major = dbg_malloc(sizeof (int) * NUMBER_OF_MAJORS))) {
|
||||
if (!(max_partitions_by_major =
|
||||
dbg_malloc(sizeof(int) * NUMBER_OF_MAJORS))) {
|
||||
log_error("Filter failed to allocate max_partitions_by_major");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(proc_devices, sizeof(proc_devices),
|
||||
if (lvm_snprintf(proc_devices, sizeof(proc_devices),
|
||||
"%s/devices", proc) < 0) {
|
||||
log_error("Failed to create /proc/devices string");
|
||||
return NULL;
|
||||
@@ -140,7 +141,7 @@ static int *scan_proc_dev(const char *proc)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(max_partitions_by_major, 0, sizeof (int) * NUMBER_OF_MAJORS);
|
||||
memset(max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS);
|
||||
while (fgets(line, 80, pd) != NULL) {
|
||||
i = 0;
|
||||
while (line[i] == ' ' && line[i] != '\0')
|
||||
@@ -168,7 +169,7 @@ static int *scan_proc_dev(const char *proc)
|
||||
_md_major = line_maj;
|
||||
|
||||
/* Go through the valid device names and if there is a
|
||||
match store max number of partitions */
|
||||
match store max number of partitions */
|
||||
for (j = 0; device_info[j].name != NULL; j++) {
|
||||
|
||||
dev_len = strlen(device_info[j].name);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#ifndef _LVM_FILTER_H
|
||||
#define _LVM_FILTER_H
|
||||
|
||||
struct dev_filter *lvm_type_filter_create();
|
||||
struct dev_filter *lvm_type_filter_create(const char *proc);
|
||||
|
||||
void lvm_type_filter_destroy(struct dev_filter *f);
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ static int _munge_formats(struct pv_disk *pvd)
|
||||
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",
|
||||
log_very_verbose("Failed to read PV data from %s",
|
||||
dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
@@ -265,35 +265,35 @@ static void _munge_exported_vg(struct disk_list *data)
|
||||
int l, s;
|
||||
|
||||
/* Return if PV not in a VG or VG not exported */
|
||||
if ((!*data->pvd.vg_name) ||
|
||||
!(data->vgd.vg_status & VG_EXPORTED))
|
||||
if ((!*data->pvd.vg_name) || !(data->vgd.vg_status & VG_EXPORTED))
|
||||
return;
|
||||
|
||||
l = strlen(data->pvd.vg_name);
|
||||
s = sizeof(EXPORTED_TAG);
|
||||
if (!strncmp(data->pvd.vg_name + l - s + 1, EXPORTED_TAG, s))
|
||||
data->pvd.vg_name[l - s + 1] = '\0';
|
||||
data->pvd.vg_name[l - s + 1] = '\0';
|
||||
|
||||
data->pvd.pv_status |= VG_EXPORTED;
|
||||
}
|
||||
|
||||
static struct disk_list *__read_disk(struct device *dev, struct pool *mem,
|
||||
static struct disk_list *__read_disk(struct format_type *fmt,
|
||||
struct device *dev, struct pool *mem,
|
||||
const char *vg_name)
|
||||
{
|
||||
struct disk_list *data = pool_alloc(mem, sizeof(*data));
|
||||
struct disk_list *dl = pool_alloc(mem, sizeof(*dl));
|
||||
const char *name = dev_name(dev);
|
||||
|
||||
if (!data) {
|
||||
if (!dl) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data->dev = dev;
|
||||
data->mem = mem;
|
||||
list_init(&data->uuids);
|
||||
list_init(&data->lvds);
|
||||
dl->dev = dev;
|
||||
dl->mem = mem;
|
||||
list_init(&dl->uuids);
|
||||
list_init(&dl->lvds);
|
||||
|
||||
if (!read_pvd(dev, &data->pvd)) {
|
||||
if (!read_pvd(dev, &dl->pvd)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
@@ -301,60 +301,60 @@ static struct disk_list *__read_disk(struct device *dev, struct pool *mem,
|
||||
/*
|
||||
* is it an orphan ?
|
||||
*/
|
||||
if (!*data->pvd.vg_name) {
|
||||
log_very_verbose("%s is not a member of any VG", name);
|
||||
if (!*dl->pvd.vg_name) {
|
||||
log_very_verbose("%s is not a member of any format1 VG", name);
|
||||
|
||||
/* Update VG cache */
|
||||
vgcache_add(data->pvd.vg_name, dev);
|
||||
vgcache_add(dl->pvd.vg_name, NULL, dev, fmt);
|
||||
|
||||
return (vg_name) ? NULL : data;
|
||||
return (vg_name) ? NULL : dl;
|
||||
}
|
||||
|
||||
if (!_read_vgd(data)) {
|
||||
if (!_read_vgd(dl)) {
|
||||
log_error("Failed to read VG data from PV (%s)", name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* If VG is exported, set VG name back to the real name */
|
||||
_munge_exported_vg(data);
|
||||
_munge_exported_vg(dl);
|
||||
|
||||
/* Update VG cache with what we found */
|
||||
vgcache_add(data->pvd.vg_name, dev);
|
||||
vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt);
|
||||
|
||||
if (vg_name && strcmp(vg_name, data->pvd.vg_name)) {
|
||||
if (vg_name && strcmp(vg_name, dl->pvd.vg_name)) {
|
||||
log_very_verbose("%s is not a member of the VG %s",
|
||||
name, vg_name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_read_uuids(data)) {
|
||||
if (!_read_uuids(dl)) {
|
||||
log_error("Failed to read PV uuid list from %s", name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_read_lvs(data)) {
|
||||
if (!_read_lvs(dl)) {
|
||||
log_error("Failed to read LV's from %s", name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_read_extents(data)) {
|
||||
if (!_read_extents(dl)) {
|
||||
log_error("Failed to read extents from %s", name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
log_very_verbose("Found %s in %sVG %s", name,
|
||||
(data->vgd.vg_status & VG_EXPORTED) ? "exported " : "",
|
||||
data->pvd.vg_name);
|
||||
log_very_verbose("Found %s in %sVG %s", name,
|
||||
(dl->vgd.vg_status & VG_EXPORTED) ? "exported " : "",
|
||||
dl->pvd.vg_name);
|
||||
|
||||
return data;
|
||||
return dl;
|
||||
|
||||
bad:
|
||||
pool_free(data->mem, data);
|
||||
pool_free(dl->mem, dl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct disk_list *read_disk(struct device *dev, struct pool *mem,
|
||||
const char *vg_name)
|
||||
struct disk_list *read_disk(struct format_type *fmt, struct device *dev,
|
||||
struct pool *mem, const char *vg_name)
|
||||
{
|
||||
struct disk_list *r;
|
||||
|
||||
@@ -363,7 +363,7 @@ struct disk_list *read_disk(struct device *dev, struct pool *mem,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = __read_disk(dev, mem, vg_name);
|
||||
r = __read_disk(fmt, dev, mem, vg_name);
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
@@ -378,16 +378,16 @@ static void _add_pv_to_list(struct list *head, struct disk_list *data)
|
||||
|
||||
list_iterate(pvdh, head) {
|
||||
pvd = &list_item(pvdh, struct disk_list)->pvd;
|
||||
if (!strncmp(data->pvd.pv_uuid, pvd->pv_uuid,
|
||||
if (!strncmp(data->pvd.pv_uuid, pvd->pv_uuid,
|
||||
sizeof(pvd->pv_uuid))) {
|
||||
if (MAJOR(data->dev->dev) != md_major()) {
|
||||
log_very_verbose("Ignoring duplicate PV %s on "
|
||||
"%s", pvd->pv_uuid,
|
||||
"%s", pvd->pv_uuid,
|
||||
dev_name(data->dev));
|
||||
return;
|
||||
}
|
||||
log_very_verbose("Duplicate PV %s - using md %s",
|
||||
pvd->pv_uuid, dev_name(data->dev));
|
||||
log_very_verbose("Duplicate PV %s - using md %s",
|
||||
pvd->pv_uuid, dev_name(data->dev));
|
||||
list_del(pvdh);
|
||||
break;
|
||||
}
|
||||
@@ -400,8 +400,9 @@ static void _add_pv_to_list(struct list *head, struct disk_list *data)
|
||||
* We keep track of the first object allocated form the pool
|
||||
* so we can free off all the memory if something goes wrong.
|
||||
*/
|
||||
int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
|
||||
struct pool *mem, struct list *head)
|
||||
int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
|
||||
struct dev_filter *filter, struct pool *mem,
|
||||
struct list *head)
|
||||
{
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
@@ -413,7 +414,7 @@ int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
|
||||
if ((pvdh = vgcache_find(vg_name))) {
|
||||
list_iterate(pvdh2, pvdh) {
|
||||
dev = list_item(pvdh2, struct pvdev_list)->dev;
|
||||
if (!(data = read_disk(dev, mem, vg_name)))
|
||||
if (!(data = read_disk(fmt, dev, mem, vg_name)))
|
||||
break;
|
||||
_add_pv_to_list(head, data);
|
||||
}
|
||||
@@ -421,8 +422,7 @@ int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
|
||||
/* 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. */
|
||||
list_init(head);
|
||||
@@ -436,7 +436,7 @@ int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
|
||||
|
||||
/* Otherwise do a complete scan */
|
||||
for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
|
||||
if ((data = read_disk(dev, mem, vg_name))) {
|
||||
if ((data = read_disk(fmt, dev, mem, vg_name))) {
|
||||
_add_pv_to_list(head, data);
|
||||
}
|
||||
}
|
||||
@@ -543,16 +543,16 @@ static int _write_pvd(struct disk_list *data)
|
||||
ulong pos = data->pvd.pv_on_disk.base;
|
||||
ulong size = data->pvd.pv_on_disk.size;
|
||||
|
||||
if(size < sizeof(struct pv_disk)) {
|
||||
if (size < sizeof(struct pv_disk)) {
|
||||
log_error("Invalid PV structure size.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure that the gap between the PV structure and
|
||||
/* Make sure that the gap between the PV structure and
|
||||
the next one is zeroed in order to make non LVM tools
|
||||
happy (idea from AED) */
|
||||
buf = dbg_malloc(size);
|
||||
if(!buf) {
|
||||
if (!buf) {
|
||||
log_err("Couldn't allocate temporary PV buffer.");
|
||||
return 0;
|
||||
}
|
||||
@@ -560,7 +560,7 @@ static int _write_pvd(struct disk_list *data)
|
||||
memset(buf, 0, size);
|
||||
memcpy(buf, &data->pvd, sizeof(struct pv_disk));
|
||||
|
||||
_xlate_pvd((struct pv_disk *)buf);
|
||||
_xlate_pvd((struct pv_disk *) buf);
|
||||
if (dev_write(data->dev, pos, size, buf) != size) {
|
||||
dbg_free(buf);
|
||||
fail;
|
||||
@@ -573,7 +573,7 @@ static int _write_pvd(struct disk_list *data)
|
||||
/*
|
||||
* assumes the device has been opened.
|
||||
*/
|
||||
static int __write_all_pvd(struct disk_list *data)
|
||||
static int __write_all_pvd(struct format_type *fmt, struct disk_list *data)
|
||||
{
|
||||
const char *pv_name = dev_name(data->dev);
|
||||
|
||||
@@ -582,13 +582,19 @@ static int __write_all_pvd(struct disk_list *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!test_mode())
|
||||
vgcache_add(data->pvd.vg_name, data->dev);
|
||||
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 (data->pvd.vg_name[0] == '\0') {
|
||||
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 (!_write_vgd(data)) {
|
||||
log_error("Failed to write VG data to %s", pv_name);
|
||||
@@ -616,7 +622,7 @@ static int __write_all_pvd(struct disk_list *data)
|
||||
/*
|
||||
* opens the device and hands to the above fn.
|
||||
*/
|
||||
static int _write_all_pvd(struct disk_list *data)
|
||||
static int _write_all_pvd(struct format_type *fmt, struct disk_list *data)
|
||||
{
|
||||
int r;
|
||||
|
||||
@@ -625,7 +631,7 @@ static int _write_all_pvd(struct disk_list *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = __write_all_pvd(data);
|
||||
r = __write_all_pvd(fmt, data);
|
||||
|
||||
if (!dev_close(data->dev))
|
||||
stack;
|
||||
@@ -638,17 +644,17 @@ static int _write_all_pvd(struct disk_list *data)
|
||||
* little sanity checking, so make sure correct
|
||||
* data is passed to here.
|
||||
*/
|
||||
int write_disks(struct list *pvs)
|
||||
int write_disks(struct format_type *fmt, struct list *pvs)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct disk_list *dl;
|
||||
|
||||
list_iterate(pvh, pvs) {
|
||||
dl = list_item(pvh, struct disk_list);
|
||||
if (!(_write_all_pvd(dl)))
|
||||
if (!(_write_all_pvd(fmt, dl)))
|
||||
fail;
|
||||
|
||||
log_very_verbose("Successfully wrote data to %s",
|
||||
log_very_verbose("Successfully wrote data to %s",
|
||||
dev_name(dl->dev));
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#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 */
|
||||
@@ -40,6 +41,7 @@
|
||||
/* logical volume */
|
||||
#define LV_ACTIVE 0x01 /* lv_status */
|
||||
#define LV_SPINDOWN 0x02 /* " */
|
||||
#define LV_PERSISTENT_MINOR 0x04 /* " */
|
||||
|
||||
#define LV_READ 0x01 /* lv_access */
|
||||
#define LV_WRITE 0x02 /* " */
|
||||
@@ -166,7 +168,6 @@ struct disk_list {
|
||||
* Layout constants.
|
||||
*/
|
||||
#define METADATA_ALIGN 4096UL
|
||||
#define PE_ALIGN (65536UL / SECTOR_SIZE)
|
||||
|
||||
#define METADATA_BASE 0UL
|
||||
#define PV_SIZE 1024UL
|
||||
@@ -186,13 +187,14 @@ int calculate_extent_count(struct physical_volume *pv);
|
||||
*/
|
||||
int read_pvd(struct device *dev, struct pv_disk *pvd);
|
||||
|
||||
struct disk_list *read_disk(struct device *dev, struct pool *mem,
|
||||
const char *vg_name);
|
||||
struct disk_list *read_disk(struct format_type *fmt, struct device *dev,
|
||||
struct pool *mem, const char *vg_name);
|
||||
|
||||
int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
|
||||
int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
|
||||
struct dev_filter *filter,
|
||||
struct pool *mem, struct list *results);
|
||||
|
||||
int write_disks(struct list *pvds);
|
||||
int write_disks(struct format_type *fmt, struct list *pvds);
|
||||
|
||||
|
||||
/*
|
||||
@@ -215,13 +217,14 @@ int import_lv(struct pool *mem, struct logical_volume *lv,
|
||||
void export_lv(struct lv_disk *lvd, struct volume_group *vg,
|
||||
struct logical_volume *lv, const char *dev_dir);
|
||||
|
||||
int import_extents(struct pool *mem, struct volume_group *vg,
|
||||
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);
|
||||
|
||||
int import_pvs(struct pool *mem, struct volume_group *vg,
|
||||
int import_pvs(struct format_instance *fid, 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,
|
||||
@@ -229,6 +232,9 @@ int import_lvs(struct pool *mem, struct volume_group *vg,
|
||||
int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||
struct physical_volume *pv, const char *dev_dir);
|
||||
|
||||
int import_snapshots(struct pool *mem, struct volume_group *vg,
|
||||
struct list *pvds);
|
||||
|
||||
int export_uuids(struct disk_list *dl, struct volume_group *vg);
|
||||
|
||||
void export_numbers(struct list *pvds, struct volume_group *vg);
|
||||
@@ -236,10 +242,10 @@ void export_numbers(struct list *pvds, struct volume_group *vg);
|
||||
void export_pv_act(struct list *pvds);
|
||||
|
||||
/* blech */
|
||||
int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
|
||||
int *result);
|
||||
int export_vg_number(struct list *pvds, const char *vg_name,
|
||||
struct dev_filter *filter);
|
||||
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
|
||||
const char *candidate_vg, int *result);
|
||||
int export_vg_number(struct format_instance *fid, struct list *pvds,
|
||||
const char *vg_name, struct dev_filter *filter);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
#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"
|
||||
|
||||
/* VG consistency checks */
|
||||
static int _check_vgs(struct list *pvs, int *partial)
|
||||
@@ -28,7 +30,7 @@ static int _check_vgs(struct list *pvs, int *partial)
|
||||
* If there are exported and unexported PVs, ignore exported ones.
|
||||
* This means an active VG won't be affected if disks are inserted
|
||||
* bearing an exported VG with the same name.
|
||||
*/
|
||||
*/
|
||||
list_iterate(pvh, pvs) {
|
||||
dl = list_item(pvh, struct disk_list);
|
||||
|
||||
@@ -48,7 +50,6 @@ static int _check_vgs(struct list *pvs, int *partial)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Remove any PVs with VG structs that differ from the first */
|
||||
list_iterate_safe(pvh, t, pvs) {
|
||||
dl = list_item(pvh, struct disk_list);
|
||||
@@ -81,8 +82,10 @@ static int _check_vgs(struct list *pvs, int *partial)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct volume_group *_build_vg(struct pool *mem, struct list *pvs)
|
||||
static struct volume_group *_build_vg(struct format_instance *fid,
|
||||
struct list *pvs)
|
||||
{
|
||||
struct pool *mem = fid->fmt->cmd->mem;
|
||||
struct volume_group *vg = pool_alloc(mem, sizeof(*vg));
|
||||
struct disk_list *dl;
|
||||
int partial;
|
||||
@@ -95,8 +98,12 @@ static struct volume_group *_build_vg(struct pool *mem, struct list *pvs)
|
||||
|
||||
memset(vg, 0, sizeof(*vg));
|
||||
|
||||
vg->cmd = fid->fmt->cmd;
|
||||
vg->fid = fid;
|
||||
vg->seqno = 0;
|
||||
list_init(&vg->pvs);
|
||||
list_init(&vg->lvs);
|
||||
list_init(&vg->snapshots);
|
||||
|
||||
if (!_check_vgs(pvs, &partial))
|
||||
goto bad;
|
||||
@@ -106,7 +113,7 @@ static struct volume_group *_build_vg(struct pool *mem, struct list *pvs)
|
||||
if (!import_vg(mem, vg, dl, partial))
|
||||
goto bad;
|
||||
|
||||
if (!import_pvs(mem, vg, pvs, &vg->pvs, &vg->pv_count))
|
||||
if (!import_pvs(fid, mem, vg, pvs, &vg->pvs, &vg->pv_count))
|
||||
goto bad;
|
||||
|
||||
if (!import_lvs(mem, vg, pvs))
|
||||
@@ -115,16 +122,19 @@ static struct volume_group *_build_vg(struct pool *mem, struct list *pvs)
|
||||
if (!import_extents(mem, vg, pvs))
|
||||
goto bad;
|
||||
|
||||
if (!import_snapshots(mem, vg, pvs))
|
||||
goto bad;
|
||||
|
||||
return vg;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
stack;
|
||||
pool_free(mem, vg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct volume_group *_vg_read(struct format_instance *fi,
|
||||
const char *vg_name)
|
||||
static struct volume_group *_vg_read(struct format_instance *fid,
|
||||
const char *vg_name, void *mda)
|
||||
{
|
||||
struct pool *mem = pool_create(1024 * 10);
|
||||
struct list pvs;
|
||||
@@ -136,22 +146,21 @@ static struct volume_group *_vg_read(struct format_instance *fi,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Strip dev_dir if present */
|
||||
vg_name = strip_dir(vg_name, fi->cmd->dev_dir);
|
||||
/* Strip dev_dir if present */
|
||||
vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir);
|
||||
|
||||
if (!read_pvs_in_vg(vg_name, fi->cmd->filter, mem, &pvs)) {
|
||||
if (!read_pvs_in_vg
|
||||
(fid->fmt, vg_name, fid->fmt->cmd->filter, mem, &pvs)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(vg = _build_vg(fi->cmd->mem, &pvs))) {
|
||||
if (!(vg = _build_vg(fid, &pvs))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
vg->cmd = fi->cmd;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
pool_destroy(mem);
|
||||
return vg;
|
||||
}
|
||||
@@ -186,7 +195,8 @@ static struct disk_list *_flatten_pv(struct pool *mem, struct volume_group *vg,
|
||||
return dl;
|
||||
}
|
||||
|
||||
static int _flatten_vg(struct pool *mem, struct volume_group *vg,
|
||||
static int _flatten_vg(struct format_instance *fid, struct pool *mem,
|
||||
struct volume_group *vg,
|
||||
struct list *pvds, const char *dev_dir,
|
||||
struct dev_filter *filter)
|
||||
{
|
||||
@@ -208,7 +218,7 @@ static int _flatten_vg(struct pool *mem, struct volume_group *vg,
|
||||
export_numbers(pvds, vg);
|
||||
export_pv_act(pvds);
|
||||
|
||||
if (!export_vg_number(pvds, vg->name, filter)) {
|
||||
if (!export_vg_number(fid, pvds, vg->name, filter)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -216,7 +226,8 @@ static int _flatten_vg(struct pool *mem, struct volume_group *vg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _vg_write(struct format_instance *fi, struct volume_group *vg)
|
||||
static int _vg_write(struct format_instance *fid, struct volume_group *vg,
|
||||
void *mdl)
|
||||
{
|
||||
struct pool *mem = pool_create(1024 * 10);
|
||||
struct list pvds;
|
||||
@@ -227,65 +238,58 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vg->status & PARTIAL_VG) {
|
||||
log_error("Cannot change metadata for partial volume group %s",
|
||||
vg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_init(&pvds);
|
||||
|
||||
r = (_flatten_vg(mem, vg, &pvds, fi->cmd->dev_dir, fi->cmd->filter) &&
|
||||
write_disks(&pvds));
|
||||
r = (_flatten_vg(fid, mem, vg, &pvds, fid->fmt->cmd->dev_dir,
|
||||
fid->fmt->cmd->filter) &&
|
||||
write_disks(fid->fmt, &pvds));
|
||||
pool_destroy(mem);
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct physical_volume *_pv_read(struct format_instance *fi,
|
||||
const char *name)
|
||||
int _pv_read(struct format_type *fmt, const char *name,
|
||||
struct physical_volume *pv)
|
||||
{
|
||||
struct pool *mem = pool_create(1024);
|
||||
struct physical_volume *pv = NULL;
|
||||
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", name);
|
||||
|
||||
if (!mem) {
|
||||
stack;
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(dev = dev_cache_get(name, fi->cmd->filter))) {
|
||||
if (!(dev = dev_cache_get(name, fmt->cmd->filter))) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(dl = read_disk(dev, mem, NULL))) {
|
||||
if (!(dl = read_disk(fmt, dev, mem, NULL))) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(pv = pool_alloc(fi->cmd->mem, sizeof(*pv)))) {
|
||||
if (!import_pv(fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!import_pv(fi->cmd->mem, dl->dev, NULL, pv, &dl->pvd)) {
|
||||
stack;
|
||||
pool_free(fi->cmd->mem, pv);
|
||||
pv = NULL;
|
||||
}
|
||||
pv->fid = fmt->ops->create_instance(fmt, NULL, NULL);
|
||||
|
||||
out:
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
pool_destroy(mem);
|
||||
return pv;
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct list *_get_pvs(struct format_instance *fi)
|
||||
static struct list *_get_pvs(struct format_type *fmt, struct list *results)
|
||||
{
|
||||
struct pool *mem = pool_create(1024 * 10);
|
||||
struct list pvs, *results;
|
||||
struct list pvs;
|
||||
uint32_t count;
|
||||
|
||||
if (!mem) {
|
||||
@@ -293,21 +297,14 @@ static struct list *_get_pvs(struct format_instance *fi)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(results = pool_alloc(fi->cmd->mem, sizeof(*results)))) {
|
||||
stack;
|
||||
pool_destroy(mem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_init(&pvs);
|
||||
list_init(results);
|
||||
|
||||
if (!read_pvs_in_vg(NULL, fi->cmd->filter, mem, &pvs)) {
|
||||
if (!read_pvs_in_vg(fmt, NULL, fmt->cmd->filter, mem, &pvs)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!import_pvs(fi->cmd->mem, NULL, &pvs, results, &count)) {
|
||||
if (!import_pvs(NULL, fmt->cmd->mem, NULL, &pvs, results, &count)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
@@ -315,8 +312,7 @@ static struct list *_get_pvs(struct format_instance *fi)
|
||||
pool_destroy(mem);
|
||||
return results;
|
||||
|
||||
bad:
|
||||
pool_free(fi->cmd->mem, results);
|
||||
bad:
|
||||
pool_destroy(mem);
|
||||
return NULL;
|
||||
}
|
||||
@@ -335,58 +331,70 @@ static int _find_vg_name(struct list *names, const char *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct list *_get_vgs(struct format_instance *fi)
|
||||
static struct list *_get_vgs(struct format_type *fmt, struct list *names)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct list *pvs, *names = pool_alloc(fi->cmd->mem, sizeof(*names));
|
||||
struct list *pvs;
|
||||
struct name_list *nl;
|
||||
|
||||
if (!names) {
|
||||
stack;
|
||||
return NULL;
|
||||
if (!(pvs = pool_alloc(fmt->cmd->mem, sizeof(*pvs)))) {
|
||||
log_error("PV list allocation failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
list_init(names);
|
||||
list_init(pvs);
|
||||
|
||||
if (!(pvs = _get_pvs(fi))) {
|
||||
if (!_get_pvs(fmt, pvs)) {
|
||||
stack;
|
||||
goto bad;
|
||||
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))
|
||||
_find_vg_name(names, pvl->pv->vg_name))
|
||||
continue;
|
||||
|
||||
if (!(nl = pool_alloc(fi->cmd->mem, sizeof(*nl)))) {
|
||||
if (!(nl = pool_alloc(fmt->cmd->mem, sizeof(*nl)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!(nl->name = pool_strdup(fi->cmd->mem,
|
||||
pvl->pv->vg_name))) {
|
||||
if (!(nl->name = pool_strdup(fmt->cmd->mem, pvl->pv->vg_name))) {
|
||||
stack;
|
||||
goto bad;
|
||||
goto err;
|
||||
}
|
||||
|
||||
list_add(names, &nl->list);
|
||||
}
|
||||
|
||||
if (list_empty(names))
|
||||
goto bad;
|
||||
pool_free(fmt->cmd->mem, pvs);
|
||||
|
||||
return names;
|
||||
|
||||
bad:
|
||||
pool_free(fi->cmd->mem, names);
|
||||
err:
|
||||
pool_free(fmt->cmd->mem, pvs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _pv_setup(struct format_instance *fi, struct physical_volume *pv,
|
||||
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");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Nothing more to do if pe_size isn't known */
|
||||
if (!vg)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* This works out pe_start and pe_count.
|
||||
*/
|
||||
@@ -398,18 +406,50 @@ static int _pv_setup(struct format_instance *fi, struct physical_volume *pv,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lv_setup(struct format_instance *fi, struct logical_volume *lv)
|
||||
static int _find_free_lvnum(struct logical_volume *lv)
|
||||
{
|
||||
int lvnum_used[MAX_LV];
|
||||
int i = 0;
|
||||
struct list *lvh;
|
||||
struct lv_list *lvl;
|
||||
|
||||
memset(&lvnum_used, 0, sizeof(lvnum_used));
|
||||
|
||||
list_iterate(lvh, &lv->vg->lvs) {
|
||||
lvl = list_item(lvh, struct lv_list);
|
||||
lvnum_used[lvnum_from_lvid(&lvl->lv->lvid)] = 1;
|
||||
}
|
||||
|
||||
while (lvnum_used[i])
|
||||
i++;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
|
||||
{
|
||||
uint64_t max_size = UINT_MAX;
|
||||
|
||||
if (!*lv->lvid.s)
|
||||
lvid_from_lvnum(&lv->lvid, &lv->vg->id, _find_free_lvnum(lv));
|
||||
|
||||
if (lv->le_count > MAX_LE_TOTAL) {
|
||||
log_error("logical volumes cannot contain more than "
|
||||
"%d extents.", MAX_LE_TOTAL);
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
|
||||
static int _pv_write(struct format_instance *fid, struct physical_volume *pv,
|
||||
void *mdl)
|
||||
{
|
||||
struct pool *mem;
|
||||
struct disk_list *dl;
|
||||
@@ -417,14 +457,15 @@ static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
|
||||
|
||||
list_init(&pvs);
|
||||
|
||||
if (*pv->vg_name || pv->pe_allocated ) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* Ensure any residual PE structure is gone */
|
||||
pv->pe_size = pv->pe_count = pv->pe_start = 0;
|
||||
pv->pe_size = pv->pe_count = 0;
|
||||
pv->pe_start = PE_ALIGN;
|
||||
|
||||
if (!(mem = pool_create(1024))) {
|
||||
stack;
|
||||
@@ -447,9 +488,10 @@ static int _pv_write(struct format_instance *fi, 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;
|
||||
|
||||
list_add(&pvs, &dl->list);
|
||||
if (!write_disks(&pvs)) {
|
||||
if (!write_disks(fid->fmt, &pvs)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
@@ -457,26 +499,26 @@ static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
|
||||
pool_destroy(mem);
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
pool_destroy(mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _vg_setup(struct format_instance *fi, struct volume_group *vg)
|
||||
int _vg_setup(struct format_instance *fid, struct volume_group *vg)
|
||||
{
|
||||
/* just check max_pv and max_lv */
|
||||
if (vg->max_lv >= MAX_LV)
|
||||
vg->max_lv = MAX_LV - 1;
|
||||
|
||||
if (vg->max_pv >= MAX_PV)
|
||||
if (vg->max_pv >= MAX_PV)
|
||||
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)));
|
||||
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)),
|
||||
(dummy2 = display_size(MAX_PE_SIZE / 2, SIZE_SHORT)));
|
||||
|
||||
dbg_free(dummy);
|
||||
dbg_free(dummy2);
|
||||
@@ -486,7 +528,7 @@ int _vg_setup(struct format_instance *fi, struct volume_group *vg)
|
||||
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)));
|
||||
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)));
|
||||
dbg_free(dummy);
|
||||
return 0;
|
||||
}
|
||||
@@ -500,37 +542,72 @@ int _vg_setup(struct format_instance *fi, struct volume_group *vg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void _destroy(struct format_instance *fi)
|
||||
struct format_instance *_create_instance(struct format_type *fmt,
|
||||
const char *vgname, void *private)
|
||||
{
|
||||
dbg_free(fi);
|
||||
}
|
||||
struct format_instance *fid;
|
||||
struct metadata_area *mda;
|
||||
|
||||
|
||||
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,
|
||||
destroy: _destroy,
|
||||
};
|
||||
|
||||
struct format_instance *create_lvm1_format(struct cmd_context *cmd)
|
||||
{
|
||||
struct format_instance *fi = dbg_malloc(sizeof(*fi));
|
||||
|
||||
if (!fi) {
|
||||
if (!(fid = pool_alloc(fmt->cmd->mem, sizeof(*fid)))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fi->cmd = cmd;
|
||||
fi->ops = &_format1_ops;
|
||||
fi->private = NULL;
|
||||
fid->fmt = fmt;
|
||||
list_init(&fid->metadata_areas);
|
||||
|
||||
return fi;
|
||||
/* Define a NULL metadata area */
|
||||
if (!(mda = pool_alloc(fmt->cmd->mem, sizeof(*mda)))) {
|
||||
stack;
|
||||
pool_free(fmt->cmd->mem, fid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mda->metadata_locn = NULL;
|
||||
list_add(&fid->metadata_areas, &mda->list);
|
||||
|
||||
return fid;
|
||||
}
|
||||
|
||||
void _destroy_instance(struct format_instance *fid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void _destroy(struct format_type *fmt)
|
||||
{
|
||||
dbg_free(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,
|
||||
create_instance:_create_instance,
|
||||
destroy_instance:_destroy_instance,
|
||||
destroy: _destroy,
|
||||
};
|
||||
|
||||
struct format_type *create_lvm1_format(struct cmd_context *cmd)
|
||||
{
|
||||
struct format_type *fmt = dbg_malloc(sizeof(*fmt));
|
||||
|
||||
if (!fmt) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fmt->cmd = cmd;
|
||||
fmt->ops = &_format1_ops;
|
||||
fmt->name = FMT_LVM1_NAME;
|
||||
fmt->features = 0;
|
||||
fmt->private = NULL;
|
||||
|
||||
return fmt;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
|
||||
#include "metadata.h"
|
||||
|
||||
struct format_instance *create_lvm1_format(struct cmd_context *cmd);
|
||||
struct format_type *create_lvm1_format(struct cmd_context *cmd);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <linux/kdev_t.h>
|
||||
|
||||
static int _check_vg_name(const char *name)
|
||||
{
|
||||
@@ -52,15 +53,15 @@ int import_pv(struct pool *mem, struct device *dev,
|
||||
|
||||
/* Store system_id from first PV if PV belongs to a VG */
|
||||
if (vg && !*vg->system_id)
|
||||
strncpy(vg->system_id, pvd->system_id, NAME_LEN);
|
||||
strncpy(vg->system_id, pvd->system_id, NAME_LEN);
|
||||
|
||||
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
|
||||
* we don't always have a struct volume_group when we need this.
|
||||
*/
|
||||
@@ -74,7 +75,7 @@ int import_pv(struct pool *mem, struct device *dev,
|
||||
pv->pe_size = pvd->pe_size;
|
||||
pv->pe_start = pvd->pe_start;
|
||||
pv->pe_count = pvd->pe_total;
|
||||
pv->pe_allocated = pvd->pe_allocated;
|
||||
pv->pe_alloc_count = pvd->pe_allocated;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -88,7 +89,7 @@ int _system_id(char *s, const char *prefix)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(s, NAME_LEN, "%s%s%lu",
|
||||
if (lvm_snprintf(s, NAME_LEN, "%s%s%lu",
|
||||
prefix, uts.nodename, time(NULL)) < 0) {
|
||||
log_error("Generated system_id too long");
|
||||
return 0;
|
||||
@@ -119,14 +120,14 @@ int export_pv(struct pool *mem, struct volume_group *vg,
|
||||
strncpy(pvd->vg_name, pv->vg_name, sizeof(pvd->vg_name));
|
||||
|
||||
/* Preserve existing system_id if it exists */
|
||||
if (vg && *vg->system_id)
|
||||
if (vg && *vg->system_id)
|
||||
strncpy(pvd->system_id, vg->system_id, sizeof(pvd->system_id));
|
||||
|
||||
/* Is VG already exported or being exported? */
|
||||
if (vg && (vg->status & EXPORTED_VG)) {
|
||||
/* Does system_id need setting? */
|
||||
if (!*vg->system_id ||
|
||||
strncmp(vg->system_id, EXPORTED_TAG,
|
||||
if (!*vg->system_id ||
|
||||
strncmp(vg->system_id, EXPORTED_TAG,
|
||||
sizeof(EXPORTED_TAG) - 1)) {
|
||||
if (!_system_id(pvd->system_id, EXPORTED_TAG)) {
|
||||
stack;
|
||||
@@ -159,10 +160,10 @@ int export_pv(struct pool *mem, struct volume_group *vg,
|
||||
}
|
||||
|
||||
/* Update internal system_id if we changed it */
|
||||
if (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);
|
||||
|
||||
@@ -173,15 +174,14 @@ int export_pv(struct pool *mem, struct volume_group *vg,
|
||||
pvd->lv_cur = 0; /* this is set when exporting the lv list */
|
||||
pvd->pe_size = pv->pe_size;
|
||||
pvd->pe_total = pv->pe_count;
|
||||
pvd->pe_allocated = pv->pe_allocated;
|
||||
pvd->pe_allocated = pv->pe_alloc_count;
|
||||
pvd->pe_start = pv->pe_start;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct vg_disk *vgd = &dl->vgd;
|
||||
memcpy(vg->id.uuid, vgd->vg_uuid, ID_LEN);
|
||||
@@ -271,8 +271,9 @@ 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)
|
||||
{
|
||||
memset(&lv->id, 0, sizeof(lv->id));
|
||||
if (!(lv->name = _create_lv_name(mem, lvd->lv_name))) {
|
||||
lvid_from_lvnum(&lv->lvid, &lv->vg->id, lvd->lv_number);
|
||||
|
||||
if (!(lv->name = _create_lv_name(mem, lvd->lv_name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -280,18 +281,18 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
|
||||
if (lvd->lv_status & LV_SPINDOWN)
|
||||
lv->status |= SPINDOWN_LV;
|
||||
|
||||
if (lvd->lv_status & LV_PERSISTENT_MINOR) {
|
||||
lv->status |= FIXED_MINOR;
|
||||
lv->minor = MINOR(lvd->lv_dev);
|
||||
} else
|
||||
lv->minor = -1;
|
||||
|
||||
if (lvd->lv_access & LV_READ)
|
||||
lv->status |= LVM_READ;
|
||||
|
||||
if (lvd->lv_access & LV_WRITE)
|
||||
lv->status |= LVM_WRITE;
|
||||
|
||||
if (lvd->lv_access & LV_SNAPSHOT)
|
||||
lv->status |= SNAPSHOT;
|
||||
|
||||
if (lvd->lv_access & LV_SNAPSHOT_ORG)
|
||||
lv->status |= SNAPSHOT_ORG;
|
||||
|
||||
if (lvd->lv_badblock)
|
||||
lv->status |= BADBLOCK_ON;
|
||||
|
||||
@@ -304,8 +305,8 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
|
||||
lv->status |= ALLOC_SIMPLE;
|
||||
|
||||
lv->read_ahead = lvd->lv_read_ahead;
|
||||
lv->size = lvd->lv_size;
|
||||
lv->le_count = lvd->lv_allocated_le;
|
||||
lv->size = lvd->lv_size;
|
||||
lv->le_count = lvd->lv_allocated_le;
|
||||
|
||||
list_init(&lv->segments);
|
||||
|
||||
@@ -329,23 +330,22 @@ void export_lv(struct lv_disk *lvd, struct volume_group *vg,
|
||||
if (lv->status & LVM_WRITE)
|
||||
lvd->lv_access |= LV_WRITE;
|
||||
|
||||
if (lv->status & SNAPSHOT)
|
||||
lvd->lv_access |= LV_SNAPSHOT;
|
||||
|
||||
if (lv->status & SNAPSHOT_ORG)
|
||||
lvd->lv_access |= LV_SNAPSHOT_ORG;
|
||||
|
||||
if (lv->status & SPINDOWN_LV)
|
||||
lvd->lv_status |= LV_SPINDOWN;
|
||||
|
||||
if (lv->status & FIXED_MINOR) {
|
||||
lvd->lv_status |= LV_PERSISTENT_MINOR;
|
||||
lvd->lv_dev = MKDEV(0, lv->minor);
|
||||
}
|
||||
|
||||
lvd->lv_read_ahead = lv->read_ahead;
|
||||
lvd->lv_stripes = list_item(lv->segments.n,
|
||||
struct stripe_segment)->stripes;
|
||||
lvd->lv_stripesize = list_item(lv->segments.n,
|
||||
struct stripe_segment)->stripe_size;
|
||||
struct stripe_segment)->stripe_size;
|
||||
|
||||
lvd->lv_size = lv->size;
|
||||
lvd->lv_allocated_le = lv->le_count;
|
||||
lvd->lv_size = lv->size;
|
||||
lvd->lv_allocated_le = lv->le_count;
|
||||
|
||||
if (lv->status & BADBLOCK_ON)
|
||||
lvd->lv_badblock = LV_BADBLOCK_ON;
|
||||
@@ -358,26 +358,25 @@ void export_lv(struct lv_disk *lvd, struct volume_group *vg,
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct list *segh;
|
||||
struct pe_disk *ped;
|
||||
struct stripe_segment *seg;
|
||||
uint32_t pe, s;
|
||||
|
||||
list_iterate (segh, &lv->segments) {
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct stripe_segment);
|
||||
|
||||
for (s = 0; s < seg->stripes; s++) {
|
||||
if (seg->area[s].pv != pv)
|
||||
continue; /* not our pv */
|
||||
continue; /* not our pv */
|
||||
|
||||
for (pe = 0; pe < (seg->len / seg->stripes); pe++) {
|
||||
ped = &dl->extents[pe + seg->area[s].pe];
|
||||
ped->lv_num = lv_num;
|
||||
ped->le_num = (seg->le / seg->stripes) + pe +
|
||||
s * (lv->le_count / seg->stripes);
|
||||
s * (lv->le_count / seg->stripes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -385,7 +384,8 @@ int export_extents(struct disk_list *dl, int lv_num,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int import_pvs(struct pool *mem, struct volume_group *vg,
|
||||
int import_pvs(struct format_instance *fid, struct pool *mem,
|
||||
struct volume_group *vg,
|
||||
struct list *pvds, struct list *results, int *count)
|
||||
{
|
||||
struct list *pvdh;
|
||||
@@ -408,6 +408,7 @@ int import_pvs(struct pool *mem, struct volume_group *vg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
pvl->pv->fid = fid;
|
||||
list_add(results, &pvl->list);
|
||||
(*count)++;
|
||||
}
|
||||
@@ -428,6 +429,7 @@ static struct logical_volume *_add_lv(struct pool *mem,
|
||||
return NULL;
|
||||
}
|
||||
lv = ll->lv;
|
||||
lv->vg = vg;
|
||||
|
||||
if (!import_lv(mem, lv, lvd)) {
|
||||
stack;
|
||||
@@ -435,14 +437,12 @@ static struct logical_volume *_add_lv(struct pool *mem,
|
||||
}
|
||||
|
||||
list_add(&vg->lvs, &ll->list);
|
||||
lv->vg = vg;
|
||||
vg->lv_count++;
|
||||
|
||||
return lv;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct disk_list *dl;
|
||||
struct lvd_list *ll;
|
||||
@@ -466,13 +466,21 @@ int import_lvs(struct pool *mem, struct volume_group *vg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME: tidy */
|
||||
int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||
struct physical_volume *pv, const char *dev_dir)
|
||||
{
|
||||
struct list *lvh;
|
||||
int r = 0;
|
||||
struct list *lvh, *sh;
|
||||
struct lv_list *ll;
|
||||
struct lvd_list *lvdl;
|
||||
int lv_num = 0, len;
|
||||
int lv_num, len;
|
||||
struct hash_table *lvd_hash;
|
||||
|
||||
if (!(lvd_hash = hash_create(32))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* setup the pv's extents array
|
||||
@@ -480,29 +488,141 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||
len = sizeof(struct pe_disk) * dl->pvd.pe_total;
|
||||
if (!(dl->extents = pool_alloc(dl->mem, len))) {
|
||||
stack;
|
||||
return 0;
|
||||
goto out;
|
||||
}
|
||||
memset(dl->extents, 0, len);
|
||||
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
ll = list_item(lvh, struct lv_list);
|
||||
if (!(lvdl = pool_alloc(dl->mem, sizeof(*lvdl)))) {
|
||||
stack;
|
||||
return 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
|
||||
|
||||
lv_num = lvnum_from_lvid(&ll->lv->lvid);
|
||||
|
||||
lvdl->lvd.lv_number = lv_num;
|
||||
|
||||
if (!hash_insert(lvd_hash, ll->lv->name, &lvdl->lvd)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!export_extents(dl, lv_num + 1, ll->lv, pv)) {
|
||||
stack;
|
||||
return 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
list_add(&dl->lvds, &lvdl->list);
|
||||
dl->pvd.lv_cur++;
|
||||
lv_num++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we need to run through the snapshots, exporting
|
||||
* the SNAPSHOT_ORG flags etc.
|
||||
*/
|
||||
list_iterate(sh, &vg->snapshots) {
|
||||
struct lv_disk *org, *cow;
|
||||
struct snapshot *s = list_item(sh,
|
||||
struct snapshot_list)->snapshot;
|
||||
|
||||
if (!(org = hash_lookup(lvd_hash, s->origin->name))) {
|
||||
log_err("Couldn't find snapshot origin '%s'.",
|
||||
s->origin->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(cow = hash_lookup(lvd_hash, s->cow->name))) {
|
||||
log_err("Couldn't find snapshot cow store '%s'.",
|
||||
s->cow->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
org->lv_access |= LV_SNAPSHOT_ORG;
|
||||
cow->lv_access |= LV_SNAPSHOT;
|
||||
cow->lv_snapshot_minor = org->lv_number;
|
||||
cow->lv_chunk_size = s->chunk_size;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
hash_destroy(lvd_hash);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: More inefficient code.
|
||||
*/
|
||||
int import_snapshots(struct pool *mem, struct volume_group *vg,
|
||||
struct list *pvds)
|
||||
{
|
||||
struct logical_volume *lvs[MAX_LV];
|
||||
struct list *pvdh, *lvdh;
|
||||
struct disk_list *dl;
|
||||
struct lv_disk *lvd;
|
||||
int lvnum;
|
||||
struct logical_volume *org, *cow;
|
||||
|
||||
/* build an index of lv numbers */
|
||||
memset(lvs, 0, sizeof(lvs));
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
|
||||
list_iterate(lvdh, &dl->lvds) {
|
||||
lvd = &(list_item(lvdh, struct lvd_list)->lvd);
|
||||
|
||||
lvnum = lvd->lv_number;
|
||||
|
||||
if (lvnum > MAX_LV) {
|
||||
log_err("Logical volume number "
|
||||
"out of bounds.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lvs[lvnum] &&
|
||||
!(lvs[lvnum] = find_lv(vg, lvd->lv_name))) {
|
||||
log_err("Couldn't find logical volume '%s'.",
|
||||
lvd->lv_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now iterate through yet again adding the snapshots.
|
||||
*/
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
|
||||
list_iterate(lvdh, &dl->lvds) {
|
||||
lvd = &(list_item(lvdh, struct lvd_list)->lvd);
|
||||
|
||||
if (!(lvd->lv_access & LV_SNAPSHOT))
|
||||
continue;
|
||||
|
||||
lvnum = lvd->lv_number;
|
||||
cow = lvs[lvnum];
|
||||
if (!(org = lvs[lvd->lv_snapshot_minor])) {
|
||||
log_err("Couldn't find origin logical volume "
|
||||
"for snapshot '%s'.", lvd->lv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we may have already added this snapshot */
|
||||
if (lv_is_cow(cow))
|
||||
continue;
|
||||
|
||||
/* insert the snapshot */
|
||||
if (!vg_add_snapshot(org, cow, 1, lvd->lv_chunk_size)) {
|
||||
log_err("Couldn't add snapshot.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -528,9 +648,8 @@ int export_uuids(struct disk_list *dl, struct volume_group *vg)
|
||||
}
|
||||
|
||||
/*
|
||||
* This calculates the nasty pv_number and
|
||||
* lv_number fields used by LVM1. Very
|
||||
* inefficient code.
|
||||
* This calculates the nasty pv_number field
|
||||
* used by LVM1.
|
||||
*/
|
||||
void export_numbers(struct list *pvds, struct volume_group *vg)
|
||||
{
|
||||
@@ -565,14 +684,14 @@ void export_pv_act(struct list *pvds)
|
||||
}
|
||||
}
|
||||
|
||||
int export_vg_number(struct list *pvds, const char *vg_name,
|
||||
struct dev_filter *filter)
|
||||
int export_vg_number(struct format_instance *fid, struct list *pvds,
|
||||
const char *vg_name, struct dev_filter *filter)
|
||||
{
|
||||
struct list *pvdh;
|
||||
struct disk_list *dl;
|
||||
int vg_num;
|
||||
|
||||
if (!get_free_vg_number(filter, vg_name, &vg_num)) {
|
||||
if (!get_free_vg_number(fid, filter, vg_name, &vg_num)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -584,4 +703,3 @@ int export_vg_number(struct list *pvds, const char *vg_name,
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@ 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))
|
||||
(lvm->map[le + st * len].pe != seg->area[st].pe + seg->len))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@@ -266,8 +266,7 @@ static int _read_stripes(struct pool *mem, struct lv_map *lvm)
|
||||
if (lvm->lv->le_count % lvm->stripes) {
|
||||
log_error("Number of stripes (%u) incompatible "
|
||||
"with logical extent count (%u) for %s",
|
||||
lvm->stripes, lvm->lv->le_count,
|
||||
lvm->lv->name);
|
||||
lvm->stripes, lvm->lv->le_count, lvm->lv->name);
|
||||
}
|
||||
len = lvm->lv->le_count / lvm->stripes;
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "log.h"
|
||||
#include "dbg_malloc.h"
|
||||
|
||||
|
||||
/*
|
||||
* Only works with powers of 2.
|
||||
*/
|
||||
@@ -51,17 +50,17 @@ static void _calc_simple_layout(struct pv_disk *pvd)
|
||||
pvd->pv_on_disk.base = METADATA_BASE;
|
||||
pvd->pv_on_disk.size = PV_SIZE;
|
||||
|
||||
pvd->vg_on_disk.base = _next_base(&pvd->pv_on_disk);
|
||||
pvd->vg_on_disk.size = VG_SIZE;
|
||||
pvd->vg_on_disk.base = _next_base(&pvd->pv_on_disk);
|
||||
pvd->vg_on_disk.size = VG_SIZE;
|
||||
|
||||
pvd->pv_uuidlist_on_disk.base = _next_base(&pvd->vg_on_disk);
|
||||
pvd->pv_uuidlist_on_disk.size = MAX_PV * NAME_LEN;
|
||||
pvd->pv_uuidlist_on_disk.base = _next_base(&pvd->vg_on_disk);
|
||||
pvd->pv_uuidlist_on_disk.size = MAX_PV * NAME_LEN;
|
||||
|
||||
pvd->lv_on_disk.base = _next_base(&pvd->pv_uuidlist_on_disk);
|
||||
pvd->lv_on_disk.size = MAX_LV * sizeof(struct lv_disk);
|
||||
pvd->lv_on_disk.base = _next_base(&pvd->pv_uuidlist_on_disk);
|
||||
pvd->lv_on_disk.size = MAX_LV * sizeof(struct lv_disk);
|
||||
|
||||
pvd->pe_on_disk.base = _next_base(&pvd->lv_on_disk);
|
||||
pvd->pe_on_disk.size = pvd->pe_total * sizeof(struct pe_disk);
|
||||
pvd->pe_on_disk.base = _next_base(&pvd->lv_on_disk);
|
||||
pvd->pe_on_disk.size = pvd->pe_total * sizeof(struct pe_disk);
|
||||
}
|
||||
|
||||
int _check_vg_limits(struct disk_list *dl)
|
||||
@@ -103,11 +102,9 @@ int calculate_layout(struct disk_list *dl)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
int calculate_extent_count(struct physical_volume *pv)
|
||||
@@ -117,15 +114,13 @@ int calculate_extent_count(struct physical_volume *pv)
|
||||
|
||||
if (!pvd) {
|
||||
stack;
|
||||
dbg_free(pvd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Guess how many extents will fit,
|
||||
* bearing in mind that one is going to be
|
||||
* knocked off at the start of the next
|
||||
* loop.
|
||||
* Guess how many extents will fit, bearing in mind that
|
||||
* one is going to be knocked off at the start of the
|
||||
* next loop.
|
||||
*/
|
||||
pvd->pe_total = (pv->size / pv->pe_size);
|
||||
|
||||
@@ -136,16 +131,15 @@ int calculate_extent_count(struct physical_volume *pv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
pvd->pe_total--;
|
||||
_calc_simple_layout(pvd);
|
||||
end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size + \
|
||||
SECTOR_SIZE - 1) / SECTOR_SIZE);
|
||||
end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size +
|
||||
SECTOR_SIZE - 1) / SECTOR_SIZE);
|
||||
|
||||
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 * pv->pe_size)) > pv->size);
|
||||
|
||||
if (pvd->pe_total > MAX_PE_TOTAL) {
|
||||
log_error("Metadata extent limit (%u) exceeded for %s - "
|
||||
|
||||
@@ -25,21 +25,20 @@ 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;
|
||||
}
|
||||
if (!dev_open(dev, O_RDONLY)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = read_pvd(dev, &pvd);
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _write(struct labeller *l,
|
||||
struct device *dev, struct label *label)
|
||||
static int _write(struct labeller *l, struct device *dev, struct label *label)
|
||||
{
|
||||
_not_supported("write");
|
||||
return 0;
|
||||
@@ -81,15 +80,15 @@ 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;
|
||||
}
|
||||
if (!dev_open(dev, O_RDONLY)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = read_pvd(dev, &pvd);
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
if (!r) {
|
||||
stack;
|
||||
@@ -118,15 +117,14 @@ 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
|
||||
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)
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* Put in separate file so it wouldn't contaminate
|
||||
* other code.
|
||||
*/
|
||||
int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
|
||||
int *result)
|
||||
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
|
||||
const char *candidate_vg, int *result)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct list all_pvs;
|
||||
@@ -31,7 +31,7 @@ int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!read_pvs_in_vg(NULL, filter, mem, &all_pvs)) {
|
||||
if (!read_pvs_in_vg(fid->fmt, NULL, filter, mem, &all_pvs)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
@@ -40,8 +40,7 @@ int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
|
||||
|
||||
list_iterate(pvh, &all_pvs) {
|
||||
dl = list_item(pvh, struct disk_list);
|
||||
if (!*dl->pvd.vg_name ||
|
||||
!strcmp(dl->pvd.vg_name, candidate_vg))
|
||||
if (!*dl->pvd.vg_name || !strcmp(dl->pvd.vg_name, candidate_vg))
|
||||
continue;
|
||||
|
||||
numbers[dl->vgd.vg_number] = 1;
|
||||
@@ -55,7 +54,7 @@ int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
out:
|
||||
pool_destroy(mem);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "import-export.h"
|
||||
#include "lvm-string.h"
|
||||
#include "lvm-file.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
@@ -20,7 +21,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/*
|
||||
* The format instance is given a directory path upon creation.
|
||||
@@ -34,103 +35,22 @@
|
||||
* Backup files that have expired will be removed.
|
||||
*/
|
||||
|
||||
struct archive_c {
|
||||
uint32_t retain_days;
|
||||
uint32_t min_retains;
|
||||
|
||||
char *dir;
|
||||
|
||||
/*
|
||||
* An ordered list of previous archives. Each list
|
||||
* entered against the vg name. Most recent first.
|
||||
*/
|
||||
struct hash_table *vg_archives;
|
||||
|
||||
/*
|
||||
* Scratch pool. Contents of vg_archives come from here.
|
||||
*/
|
||||
struct pool *mem;
|
||||
};
|
||||
|
||||
/*
|
||||
* A list of these is built up for each volume group. Ordered
|
||||
* A list of these is built up for our volume group. Ordered
|
||||
* with the least recent at the head.
|
||||
*/
|
||||
struct archive_file {
|
||||
struct list list;
|
||||
|
||||
char *path;
|
||||
char *vg;
|
||||
int index;
|
||||
};
|
||||
|
||||
/*
|
||||
* This format is write only.
|
||||
*/
|
||||
static void _unsupported(const char *cmd)
|
||||
{
|
||||
log_err("The archive format doesn't support '%s'", cmd);
|
||||
}
|
||||
|
||||
static struct list *_get_vgs(struct format_instance *fi)
|
||||
{
|
||||
_unsupported("get_vgs");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct list *_get_pvs(struct format_instance *fi)
|
||||
{
|
||||
_unsupported("get_pvs");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct physical_volume *_pv_read(struct format_instance *fi,
|
||||
const char *pv_name)
|
||||
{
|
||||
_unsupported("pv_read");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _pv_setup(struct format_instance *fi, struct physical_volume *pv,
|
||||
struct volume_group *vg)
|
||||
{
|
||||
_unsupported("pv_setup");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
|
||||
{
|
||||
_unsupported("pv_write");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _vg_setup(struct format_instance *fi, struct volume_group *vg)
|
||||
{
|
||||
_unsupported("vg_setup");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct volume_group *_vg_read(struct format_instance *fi,
|
||||
const char *vg_name)
|
||||
{
|
||||
_unsupported("vg_read");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _destroy(struct format_instance *fi)
|
||||
{
|
||||
struct archive_c *bc = (struct archive_c *) fi->private;
|
||||
if (bc->vg_archives)
|
||||
hash_destroy(bc->vg_archives);
|
||||
pool_destroy(bc->mem);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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;
|
||||
@@ -170,7 +90,7 @@ static void _insert_file(struct list *head, struct archive_file *b)
|
||||
}
|
||||
|
||||
/* index increases through list */
|
||||
list_iterate (bh, head) {
|
||||
list_iterate(bh, head) {
|
||||
bf = list_item(bh, struct archive_file);
|
||||
|
||||
if (bf->index > b->index) {
|
||||
@@ -182,50 +102,6 @@ static void _insert_file(struct list *head, struct archive_file *b)
|
||||
list_add_h(&bf->list, &b->list);
|
||||
}
|
||||
|
||||
static int _scan_vg(struct archive_c *bc, const char *file,
|
||||
const char *vg_name, int index)
|
||||
{
|
||||
struct archive_file *b;
|
||||
struct list *files;
|
||||
|
||||
/*
|
||||
* Do we need to create a new list of archive files for
|
||||
* this vg ?
|
||||
*/
|
||||
if (!(files = hash_lookup(bc->vg_archives, vg_name))) {
|
||||
if (!(files = pool_alloc(bc->mem, sizeof(*files)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_init(files);
|
||||
if (!hash_insert(bc->vg_archives, vg_name, files)) {
|
||||
log_err("Couldn't insert archive file "
|
||||
"into hash table.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new archive file.
|
||||
*/
|
||||
if (!(b = pool_alloc(bc->mem, sizeof(*b)))) {
|
||||
log_err("Couldn't create new archive file.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
b->index = index;
|
||||
b->path = (char *)file;
|
||||
b->vg = (char *)vg_name;
|
||||
|
||||
/*
|
||||
* Insert it to the correct part of the list.
|
||||
*/
|
||||
_insert_file(files, b);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char *_join(struct pool *mem, const char *dir, const char *name)
|
||||
{
|
||||
if (!pool_begin_object(mem, 32) ||
|
||||
@@ -240,70 +116,90 @@ static char *_join(struct pool *mem, const char *dir, const char *name)
|
||||
return pool_end_object(mem);
|
||||
}
|
||||
|
||||
static int _scan_dir(struct archive_c *bc)
|
||||
/*
|
||||
* Returns a list of archive_files.
|
||||
*/
|
||||
static struct list *_scan_archive(struct pool *mem,
|
||||
const char *vg, const char *dir)
|
||||
{
|
||||
int r = 0, i, count, index;
|
||||
int i, count, index;
|
||||
char vg_name[64], *path;
|
||||
struct dirent **dirent;
|
||||
struct archive_file *af;
|
||||
struct list *results;
|
||||
|
||||
if ((count = scandir(bc->dir, &dirent, NULL, alphasort)) < 0) {
|
||||
if (!(results = pool_alloc(mem, sizeof(*results)))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_init(results);
|
||||
|
||||
if ((count = scandir(dir, &dirent, NULL, alphasort)) < 0) {
|
||||
log_err("Couldn't scan archive directory.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if ((dirent[i]->d_name[0] == '.') ||
|
||||
!_split_vg(dirent[i]->d_name, vg_name,
|
||||
/* ignore dot files */
|
||||
if (dirent[i]->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
/* check the name is the correct format */
|
||||
if (!_split_vg(dirent[i]->d_name, vg_name,
|
||||
sizeof(vg_name), &index))
|
||||
continue;
|
||||
|
||||
if (!(path = _join(bc->mem, bc->dir, dirent[i]->d_name))) {
|
||||
/* is it the vg we're interested in ? */
|
||||
if (strcmp(vg, vg_name))
|
||||
continue;
|
||||
|
||||
if (!(path = _join(mem, dir, dirent[i]->d_name))) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
_scan_vg(bc, path, vg_name, index);
|
||||
}
|
||||
r = 1;
|
||||
/*
|
||||
* Create a new archive_file.
|
||||
*/
|
||||
if (!(af = pool_alloc(mem, sizeof(*af)))) {
|
||||
log_err("Couldn't create new archive file.");
|
||||
results = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
af->index = index;
|
||||
af->path = path;
|
||||
|
||||
/*
|
||||
* Insert it to the correct part of the list.
|
||||
*/
|
||||
_insert_file(results, af);
|
||||
}
|
||||
|
||||
out:
|
||||
for (i = 0; i < count; i++)
|
||||
free(dirent[i]);
|
||||
free(dirent);
|
||||
|
||||
return r;
|
||||
return results;
|
||||
}
|
||||
|
||||
static int _scan_archives(struct archive_c *bc)
|
||||
int archive_vg(struct volume_group *vg,
|
||||
const char *dir, const char *desc,
|
||||
uint32_t retain_days, uint32_t min_archive)
|
||||
{
|
||||
pool_empty(bc->mem);
|
||||
|
||||
if (bc->vg_archives)
|
||||
hash_destroy(bc->vg_archives);
|
||||
|
||||
if (!(bc->vg_archives = hash_create(128))) {
|
||||
log_err("Couldn't create hash table for scanning archives.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_scan_dir(bc)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _vg_write(struct format_instance *fi, struct volume_group *vg)
|
||||
{
|
||||
int r = 0, i, fd;
|
||||
int i, fd;
|
||||
unsigned int index = 0;
|
||||
struct archive_c *bc = (struct archive_c *) fi->private;
|
||||
struct archive_file *last;
|
||||
FILE *fp = NULL;
|
||||
char temp_file[PATH_MAX], archive_name[PATH_MAX];
|
||||
struct list *archives;
|
||||
|
||||
if (!create_temp_name(bc->dir, temp_file, sizeof(temp_file), &fd)) {
|
||||
/*
|
||||
* Write the vg out to a temporary file.
|
||||
*/
|
||||
if (!create_temp_name(dir, temp_file, sizeof(temp_file), &fd)) {
|
||||
log_err("Couldn't create temporary archive name.");
|
||||
return 0;
|
||||
}
|
||||
@@ -314,7 +210,7 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!text_vg_export(fp, vg)) {
|
||||
if (!text_vg_export(fp, vg, desc)) {
|
||||
stack;
|
||||
fclose(fp);
|
||||
return 0;
|
||||
@@ -325,97 +221,92 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg)
|
||||
/*
|
||||
* Now we want to rename this file to <vg>_index.vg.
|
||||
*/
|
||||
if (!_scan_archives(bc)) {
|
||||
log_err("Couldn't scan the archive directory (%s).", bc->dir);
|
||||
goto out;
|
||||
if (!(archives = _scan_archive(vg->cmd->mem, vg->name, dir))) {
|
||||
log_err("Couldn't scan the archive directory (%s).", dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((last = (struct archive_file *) hash_lookup(bc->vg_archives,
|
||||
vg->name))) {
|
||||
/* move to the last in the list */
|
||||
last = list_item(last->list.p, struct archive_file);
|
||||
if (list_empty(archives))
|
||||
index = 0;
|
||||
|
||||
else {
|
||||
last = list_item(archives->p, struct archive_file);
|
||||
index = last->index + 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (lvm_snprintf(archive_name, sizeof(archive_name),
|
||||
"%s/%s_%05d.vg",
|
||||
bc->dir, vg->name, index) < 0) {
|
||||
"%s/%s_%05d.vg", dir, vg->name, index) < 0) {
|
||||
log_err("archive file name too long.");
|
||||
goto out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_rename(temp_file, archive_name)) {
|
||||
r = 1;
|
||||
if (lvm_rename(temp_file, archive_name))
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
out:
|
||||
return r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void archive_expire(struct format_instance *fi)
|
||||
static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
|
||||
struct archive_file *af)
|
||||
{
|
||||
/* FIXME: finish */
|
||||
struct volume_group *vg = NULL;
|
||||
struct format_instance *tf;
|
||||
time_t when;
|
||||
char *desc;
|
||||
void *context;
|
||||
|
||||
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))) {
|
||||
log_error("Couldn't create text instance object.");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the archive file to ensure that it is valid, and
|
||||
* retrieve the archive time and description.
|
||||
*/
|
||||
/* FIXME Use variation on _vg_read */
|
||||
if (!(vg = text_vg_import(tf, af->path, um, &when, &desc))) {
|
||||
log_print("Unable to read archive file.");
|
||||
tf->fmt->ops->destroy_instance(tf);
|
||||
return;
|
||||
}
|
||||
|
||||
log_print("description:\t%s", desc ? desc : "<No description>");
|
||||
log_print("time:\t\t%s", ctime(&when));
|
||||
|
||||
pool_free(cmd->mem, vg);
|
||||
tf->fmt->ops->destroy_instance(tf);
|
||||
}
|
||||
|
||||
static struct format_handler _archive_handler = {
|
||||
get_vgs: _get_vgs,
|
||||
get_pvs: _get_pvs,
|
||||
pv_read: _pv_read,
|
||||
pv_setup: _pv_setup,
|
||||
pv_write: _pv_write,
|
||||
vg_setup: _vg_setup,
|
||||
vg_read: _vg_read,
|
||||
vg_write: _vg_write,
|
||||
destroy: _destroy
|
||||
};
|
||||
|
||||
struct format_instance *archive_format_create(struct cmd_context *cmd,
|
||||
const char *dir,
|
||||
uint32_t retain_days,
|
||||
uint32_t min_retains)
|
||||
int archive_list(struct cmd_context *cmd, struct uuid_map *um,
|
||||
const char *dir, const char *vg)
|
||||
{
|
||||
struct format_instance *fi;
|
||||
struct archive_c *bc = NULL;
|
||||
struct pool *mem = cmd->mem;
|
||||
struct list *archives, *ah;
|
||||
struct archive_file *af;
|
||||
|
||||
if (!(bc = pool_zalloc(mem, sizeof(*bc)))) {
|
||||
stack;
|
||||
return NULL;
|
||||
if (!(archives = _scan_archive(cmd->mem, vg, dir))) {
|
||||
log_err("Couldn't scan the archive directory (%s).", dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(bc->mem = pool_create(1024))) {
|
||||
stack;
|
||||
goto bad;
|
||||
if (list_empty(archives))
|
||||
log_print("No archives found.");
|
||||
|
||||
list_iterate(ah, archives) {
|
||||
af = list_item(ah, struct archive_file);
|
||||
|
||||
_display_archive(cmd, um, af);
|
||||
log_print(" ");
|
||||
}
|
||||
|
||||
if (!(bc->dir = pool_strdup(mem, dir))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
pool_free(cmd->mem, archives);
|
||||
|
||||
bc->retain_days = retain_days;
|
||||
bc->min_retains = min_retains;
|
||||
|
||||
if (!(fi = pool_alloc(mem, sizeof(*fi)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
fi->cmd = cmd;
|
||||
fi->ops = &_archive_handler;
|
||||
fi->private = bc;
|
||||
|
||||
return fi;
|
||||
|
||||
bad:
|
||||
if (bc->mem)
|
||||
pool_destroy(bc->mem);
|
||||
|
||||
pool_free(mem, bc);
|
||||
return NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -16,14 +16,13 @@
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
/*
|
||||
* The first half of this file deals with
|
||||
* exporting the vg, ie. writing it to a file.
|
||||
*/
|
||||
struct formatter {
|
||||
struct pool *mem; /* pv names allocated from here */
|
||||
struct hash_table *pv_names; /* dev_name -> pv_name (eg, pv1) */
|
||||
struct hash_table *pv_names; /* dev_name -> pv_name (eg, pv1) */
|
||||
|
||||
FILE *fp; /* where we're writing to */
|
||||
int indent; /* current level of indentation */
|
||||
@@ -34,16 +33,14 @@ struct formatter {
|
||||
/*
|
||||
* Formatting functions.
|
||||
*/
|
||||
static void _out_size(struct formatter *f, uint64_t size,
|
||||
const char *fmt, ...)
|
||||
__attribute__ (( format (printf, 3, 4) ));
|
||||
static void _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, ...)
|
||||
__attribute__ (( format (printf, 2, 3) ));
|
||||
__attribute__ ((format(printf, 2, 3)));
|
||||
|
||||
static void _out(struct formatter *f, const char *fmt, ...)
|
||||
__attribute__ (( format (printf, 2, 3) ));
|
||||
|
||||
__attribute__ ((format(printf, 2, 3)));
|
||||
|
||||
#define MAX_INDENT 5
|
||||
static void _inc_indent(struct formatter *f)
|
||||
@@ -116,7 +113,7 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
|
||||
"Gigabytes",
|
||||
"Terrabytes",
|
||||
NULL
|
||||
};
|
||||
};
|
||||
|
||||
int i;
|
||||
double d = (double) sectors;
|
||||
@@ -124,7 +121,7 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
|
||||
/* to convert to K */
|
||||
d /= 2.0;
|
||||
|
||||
for (i = 0; (d > 1024.0) && _units[i]; i++)
|
||||
for (i = 0; (d > 1024.0) && _units[i]; i++)
|
||||
d /= 1024.0;
|
||||
|
||||
return lvm_snprintf(buffer, s, "# %g %s", d, _units[i]) > 0;
|
||||
@@ -134,8 +131,7 @@ 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 void _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
|
||||
{
|
||||
char buffer[64];
|
||||
va_list ap;
|
||||
@@ -172,7 +168,8 @@ static void _out(struct formatter *f, const char *fmt, ...)
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static int _print_header(struct formatter *f, struct volume_group *vg)
|
||||
static int _print_header(struct formatter *f,
|
||||
struct volume_group *vg, const char *desc)
|
||||
{
|
||||
time_t t;
|
||||
|
||||
@@ -181,6 +178,10 @@ static int _print_header(struct formatter *f, struct volume_group *vg)
|
||||
_out(f,
|
||||
"# This file was originally generated by the LVM2 library\n"
|
||||
"# Generated: %s\n", ctime(&t));
|
||||
|
||||
_out(f, "description = \"%s\"", desc);
|
||||
_out(f, "creation_time = %lu\n", t);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -195,6 +196,7 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
|
||||
|
||||
_out(f, "id = \"%s\"", buffer);
|
||||
|
||||
_out(f, "seqno = %u", vg->seqno);
|
||||
if (!print_flags(vg->status, VG_FLAGS, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
@@ -214,12 +216,11 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
|
||||
* Get the pv%d name from the formatters hash
|
||||
* table.
|
||||
*/
|
||||
static inline const char *
|
||||
_get_pv_name(struct formatter *f, struct physical_volume *pv)
|
||||
static inline const char *_get_pv_name(struct formatter *f,
|
||||
struct physical_volume *pv)
|
||||
{
|
||||
return (pv) ? (const char *)
|
||||
hash_lookup(f->pv_names, dev_name(pv->dev)) :
|
||||
"Missing";
|
||||
return (pv) ? (const char *)
|
||||
hash_lookup(f->pv_names, dev_name(pv->dev)) : "Missing";
|
||||
}
|
||||
|
||||
static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
||||
@@ -232,7 +233,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
||||
_out(f, "physical_volumes {");
|
||||
_inc_indent(f);
|
||||
|
||||
list_iterate (pvh, &vg->pvs) {
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
|
||||
@@ -254,8 +255,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
||||
_out_hint(f, "device = \"%s\"", dev_name(pv->dev));
|
||||
_nl(f);
|
||||
|
||||
if (!print_flags(pv->status, PV_FLAGS,
|
||||
buffer, sizeof(buffer))) {
|
||||
if (!print_flags(pv->status, PV_FLAGS, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -319,8 +319,8 @@ static int _count_segments(struct logical_volume *lv)
|
||||
int r = 0;
|
||||
struct list *segh;
|
||||
|
||||
list_iterate (segh, &lv->segments)
|
||||
r++;
|
||||
list_iterate(segh, &lv->segments)
|
||||
r++;
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -333,29 +333,44 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
||||
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;
|
||||
|
||||
_out(f, "logical_volumes {");
|
||||
_nl(f);
|
||||
_inc_indent(f);
|
||||
|
||||
list_iterate (lvh, &vg->lvs) {
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
|
||||
_nl(f);
|
||||
_out(f, "%s {", lv->name);
|
||||
_inc_indent(f);
|
||||
|
||||
if (!print_flags(lv->status, LV_FLAGS,
|
||||
buffer, sizeof(buffer))) {
|
||||
/* FIXME: Write full lvid */
|
||||
if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_out(f, "id = \"%s\"", buffer);
|
||||
|
||||
if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_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) {
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct stripe_segment);
|
||||
|
||||
if (!_print_segment(f, vg, seg_count++, seg)) {
|
||||
@@ -374,13 +389,60 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
||||
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, "}");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _print_snapshots(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
struct list *sh;
|
||||
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;
|
||||
|
||||
if (!_print_snapshot(f, s, count++)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
_out(f, "}");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* In the text format we refer to pv's as 'pv1',
|
||||
* 'pv2' etc. This function builds a hash table
|
||||
* to enable a quick lookup from device -> name.
|
||||
*/
|
||||
static int _build_pv_names(struct formatter *f,
|
||||
struct volume_group *vg)
|
||||
static int _build_pv_names(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
int count = 0;
|
||||
struct list *pvh;
|
||||
@@ -397,11 +459,10 @@ static int _build_pv_names(struct formatter *f,
|
||||
goto bad;
|
||||
}
|
||||
|
||||
list_iterate (pvh, &vg->pvs) {
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
|
||||
if (lvm_snprintf(buffer, sizeof(buffer),
|
||||
"pv%d", count++) < 0) {
|
||||
if (lvm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
@@ -419,7 +480,7 @@ static int _build_pv_names(struct formatter *f,
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
if (f->mem)
|
||||
pool_destroy(f->mem);
|
||||
|
||||
@@ -429,7 +490,7 @@ static int _build_pv_names(struct formatter *f,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int text_vg_export(FILE *fp, struct volume_group *vg)
|
||||
int text_vg_export(FILE * fp, struct volume_group *vg, const char *desc)
|
||||
{
|
||||
int r = 0;
|
||||
struct formatter *f;
|
||||
@@ -447,10 +508,9 @@ int text_vg_export(FILE *fp, struct volume_group *vg)
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#define fail do {stack; goto out;} while(0)
|
||||
|
||||
if (!_print_header(f, vg))
|
||||
if (!_print_header(f, vg, desc))
|
||||
fail;
|
||||
|
||||
_out(f, "%s {", vg->name);
|
||||
@@ -460,22 +520,24 @@ int text_vg_export(FILE *fp, struct volume_group *vg)
|
||||
fail;
|
||||
|
||||
_nl(f);
|
||||
|
||||
if (!_print_pvs(f, vg))
|
||||
fail;
|
||||
|
||||
_nl(f);
|
||||
|
||||
if (!_print_lvs(f, vg))
|
||||
fail;
|
||||
|
||||
_nl(f);
|
||||
if (!_print_snapshots(f, vg))
|
||||
fail;
|
||||
|
||||
#undef fail
|
||||
|
||||
_dec_indent(f);
|
||||
_out(f, "}");
|
||||
r = !ferror(f->fp);
|
||||
|
||||
out:
|
||||
out:
|
||||
if (f->mem)
|
||||
pool_destroy(f->mem);
|
||||
|
||||
|
||||
@@ -41,8 +41,7 @@ static struct flag _lv_flags[] = {
|
||||
{ALLOC_SIMPLE, "ALLOC_SIMPLE"},
|
||||
{ALLOC_STRICT, "ALLOC_STRICT"},
|
||||
{ALLOC_CONTIGUOUS, "ALLOC_CONTIGUOUS"},
|
||||
{SNAPSHOT, "SNASHOT"},
|
||||
{SNAPSHOT_ORG, "SNAPSHOT_ORIGIN"},
|
||||
{FIXED_MINOR, "FIXED_MINOR"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
@@ -63,7 +62,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;
|
||||
@@ -125,7 +124,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;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
* Copyright (C) 2001-2002 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
@@ -12,72 +12,98 @@
|
||||
#include "pool.h"
|
||||
#include "config.h"
|
||||
#include "hash.h"
|
||||
#include "display.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "toolcontext.h"
|
||||
#include "vgcache.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/file.h>
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
|
||||
/* Arbitrary limits copied from format1/disk_rep.h */
|
||||
#define MAX_PV 256
|
||||
#define MAX_LV 256
|
||||
#define MAX_VG 99
|
||||
#define MAX_PV_SIZE ((uint32_t) -1) /* 2TB in sectors - 1 */
|
||||
|
||||
struct dir_list {
|
||||
struct list list;
|
||||
char dir[0];
|
||||
};
|
||||
|
||||
struct text_context {
|
||||
char *path_live; /* Path to file holding live metadata */
|
||||
char *path_edit; /* Path to file holding edited metadata */
|
||||
char *desc; /* Description placed inside file */
|
||||
};
|
||||
|
||||
/*
|
||||
* NOTE: Currently there can be only one vg per file.
|
||||
*/
|
||||
|
||||
struct text_c {
|
||||
char *path;
|
||||
struct uuid_map *um;
|
||||
};
|
||||
|
||||
static void _not_written(const char *cmd)
|
||||
{
|
||||
log_err("The text format is lacking an implementation for '%s'", cmd);
|
||||
}
|
||||
|
||||
static struct list *_get_vgs(struct format_instance *fi)
|
||||
{
|
||||
_not_written("_get_vgs");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct list *_get_pvs(struct format_instance *fi)
|
||||
{
|
||||
_not_written("_get_vgs");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct physical_volume *_pv_read(struct format_instance *fi,
|
||||
const char *pv_name)
|
||||
{
|
||||
_not_written("_get_vgs");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _pv_setup(struct format_instance *fi, struct physical_volume *pv,
|
||||
struct volume_group *vg)
|
||||
{
|
||||
_not_written("_get_vgs");
|
||||
return 0;
|
||||
}
|
||||
/* 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");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
|
||||
{
|
||||
_not_written("_get_vgs");
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _vg_setup(struct format_instance *fi, struct volume_group *vg)
|
||||
{
|
||||
_not_written("_get_vgs");
|
||||
return 0;
|
||||
/* just check max_pv and max_lv */
|
||||
if (vg->max_lv >= MAX_LV)
|
||||
vg->max_lv = MAX_LV - 1;
|
||||
|
||||
if (vg->max_pv >= MAX_PV)
|
||||
vg->max_pv = MAX_PV - 1;
|
||||
|
||||
if (vg->extent_size & (vg->extent_size - 1)) {
|
||||
log_error("Extent size must be power of 2");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lv_setup(struct format_instance *fi, struct logical_volume *lv)
|
||||
{
|
||||
uint64_t max_size = UINT_MAX;
|
||||
|
||||
if (!*lv->lvid.s)
|
||||
lvid_create(&lv->lvid, &lv->vg->id);
|
||||
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct volume_group *_vg_read(struct format_instance *fi,
|
||||
const char *vg_name)
|
||||
const char *vgname, void *mdl)
|
||||
{
|
||||
struct text_c *tc = (struct text_c *) fi->private;
|
||||
struct text_context *tc = (struct text_context *) mdl;
|
||||
struct volume_group *vg;
|
||||
time_t when;
|
||||
char *desc;
|
||||
|
||||
if (!(vg = text_vg_import(fi->cmd, tc->path, tc->um))) {
|
||||
if (!(vg = text_vg_import(fi, tc->path_live, fi->fmt->cmd->um, &when,
|
||||
&desc))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
@@ -87,42 +113,43 @@ static struct volume_group *_vg_read(struct format_instance *fi,
|
||||
* text file (this restriction may remain). We need to
|
||||
* check that it contains the correct volume group.
|
||||
*/
|
||||
if (strcmp(vg_name, vg->name)) {
|
||||
pool_free(fi->cmd->mem, vg);
|
||||
if (strcmp(vgname, vg->name)) {
|
||||
pool_free(fi->fmt->cmd->mem, vg);
|
||||
log_err("'%s' does not contain volume group '%s'.",
|
||||
tc->path, vg_name);
|
||||
tc->path_live, vgname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return vg;
|
||||
}
|
||||
|
||||
static int _vg_write(struct format_instance *fi, struct volume_group *vg)
|
||||
static int _vg_write(struct format_instance *fi, struct volume_group *vg,
|
||||
void *mdl)
|
||||
{
|
||||
struct text_c *tc = (struct text_c *) fi->private;
|
||||
struct text_context *tc = (struct text_context *) mdl;
|
||||
|
||||
FILE *fp;
|
||||
int fd;
|
||||
char *slash;
|
||||
char temp_file[PATH_MAX], temp_dir[PATH_MAX];
|
||||
|
||||
slash = rindex(tc->path, '/');
|
||||
slash = rindex(tc->path_edit, '/');
|
||||
|
||||
if (slash == 0)
|
||||
strcpy(temp_dir, ".");
|
||||
else if (slash - tc->path < PATH_MAX) {
|
||||
strncpy(temp_dir, tc->path, slash - tc->path);
|
||||
temp_dir[slash - tc->path] = '\0';
|
||||
else if (slash - tc->path_edit < PATH_MAX) {
|
||||
strncpy(temp_dir, tc->path_edit, slash - tc->path_edit);
|
||||
temp_dir[slash - tc->path_edit] = '\0';
|
||||
|
||||
} else {
|
||||
log_error("Text format failed to determine directory.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!create_temp_name(temp_dir, temp_file, sizeof(temp_file), &fd)) {
|
||||
log_err("Couldn't create temporary text file name.");
|
||||
return 0;
|
||||
}
|
||||
if (!create_temp_name(temp_dir, temp_file, sizeof(temp_file), &fd)) {
|
||||
log_err("Couldn't create temporary text file name.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(fp = fdopen(fd, "w"))) {
|
||||
log_sys_error("fdopen", temp_file);
|
||||
@@ -130,81 +157,482 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!text_vg_export(fp, vg)) {
|
||||
if (!text_vg_export(fp, vg, tc->desc)) {
|
||||
log_error("Failed to write metadata to %s.", temp_file);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fclose(fp)) {
|
||||
log_sys_error("fclose", tc->path);
|
||||
if (fsync(fd)) {
|
||||
log_sys_error("fsync", tc->path_edit);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rename(temp_file, tc->path)) {
|
||||
log_error("%s: rename to %s failed: %s", temp_file, tc->path,
|
||||
strerror(errno));
|
||||
if (fclose(fp)) {
|
||||
log_sys_error("fclose", tc->path_edit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rename(temp_file, tc->path_edit)) {
|
||||
log_error("%s: rename to %s failed: %s", temp_file,
|
||||
tc->path_edit, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _destroy(struct format_instance *fi)
|
||||
static int _pv_commit(struct format_instance *fi, struct physical_volume *pv,
|
||||
void *mdl)
|
||||
{
|
||||
struct text_c *tc = (struct text_c *) fi->private;
|
||||
// struct text_context *tc = (struct text_context *) mdl;
|
||||
|
||||
dbg_free(tc->path);
|
||||
dbg_free(tc);
|
||||
dbg_free(fi);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _vg_commit(struct format_instance *fi, struct volume_group *vg,
|
||||
void *mdl)
|
||||
{
|
||||
struct text_context *tc = (struct text_context *) mdl;
|
||||
|
||||
if (rename(tc->path_edit, tc->path_live)) {
|
||||
log_error("%s: rename to %s failed: %s", tc->path_edit,
|
||||
tc->path_edit, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
sync();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _vg_remove(struct format_instance *fi, struct volume_group *vg,
|
||||
void *mdl)
|
||||
{
|
||||
struct text_context *tc = (struct text_context *) mdl;
|
||||
|
||||
if (path_exists(tc->path_edit) && unlink(tc->path_edit)) {
|
||||
log_sys_error("unlink", tc->path_edit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (path_exists(tc->path_live) && unlink(tc->path_live)) {
|
||||
log_sys_error("unlink", tc->path_live);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sync();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Add vgname to list if it's not already there */
|
||||
static int _add_vgname(struct format_type *fmt, struct list *names,
|
||||
char *vgname)
|
||||
{
|
||||
struct list *nlh;
|
||||
struct name_list *nl;
|
||||
|
||||
list_iterate(nlh, names) {
|
||||
nl = list_item(nlh, struct name_list);
|
||||
if (!strcmp(vgname, nl->name))
|
||||
return 1;
|
||||
}
|
||||
|
||||
vgcache_add(vgname, NULL, NULL, fmt);
|
||||
|
||||
if (!(nl = pool_alloc(fmt->cmd->mem, sizeof(*nl)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(nl->name = pool_strdup(fmt->cmd->mem, vgname))) {
|
||||
log_error("strdup %s failed", vgname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_add(names, &nl->list);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct list *_get_vgs(struct format_type *fmt, struct list *names)
|
||||
{
|
||||
struct dirent *dirent;
|
||||
struct dir_list *dl;
|
||||
struct list *dlh, *dir_list;
|
||||
char *tmp;
|
||||
DIR *d;
|
||||
|
||||
dir_list = (struct list *) fmt->private;
|
||||
|
||||
list_iterate(dlh, dir_list) {
|
||||
dl = list_item(dlh, struct dir_list);
|
||||
if (!(d = opendir(dl->dir))) {
|
||||
log_sys_error("opendir", dl->dir);
|
||||
continue;
|
||||
}
|
||||
while ((dirent = readdir(d)))
|
||||
if (strcmp(dirent->d_name, ".") &&
|
||||
strcmp(dirent->d_name, "..") &&
|
||||
(!(tmp = strstr(dirent->d_name, ".tmp")) ||
|
||||
tmp != dirent->d_name + strlen(dirent->d_name)
|
||||
- 4))
|
||||
if (!_add_vgname(fmt, names, dirent->d_name))
|
||||
return NULL;
|
||||
|
||||
if (closedir(d))
|
||||
log_sys_error("closedir", dl->dir);
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
static struct list *_get_pvs(struct format_type *fmt, struct list *results)
|
||||
{
|
||||
struct pv_list *pvl, *rhl;
|
||||
struct list *vgh;
|
||||
struct list *pvh;
|
||||
struct list *names = pool_alloc(fmt->cmd->mem, sizeof(*names));
|
||||
struct list *rh;
|
||||
struct name_list *nl;
|
||||
struct volume_group *vg;
|
||||
|
||||
list_init(names);
|
||||
if (!_get_vgs(fmt, names)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_iterate(vgh, names) {
|
||||
|
||||
nl = list_item(vgh, struct name_list);
|
||||
if (!(vg = vg_read(fmt->cmd, nl->name))) {
|
||||
log_error("format_text: _get_pvs failed to read VG %s",
|
||||
nl->name);
|
||||
continue;
|
||||
}
|
||||
/* FIXME Use temp hash! */
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pvl = list_item(pvh, struct pv_list);
|
||||
|
||||
/* If in use, remove from list of orphans */
|
||||
list_iterate(rh, results) {
|
||||
rhl = list_item(rh, struct pv_list);
|
||||
if (id_equal(&rhl->pv->id, &pvl->pv->id)) {
|
||||
if (*rhl->pv->vg_name)
|
||||
log_err("PV %s in two VGs "
|
||||
"%s and %s",
|
||||
dev_name(rhl->pv->dev),
|
||||
rhl->pv->vg_name,
|
||||
vg->name);
|
||||
else
|
||||
memcpy(&rhl->pv, &pvl->pv,
|
||||
sizeof(struct
|
||||
physical_volume));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pool_free(fmt->cmd->mem, names);
|
||||
return results;
|
||||
}
|
||||
|
||||
static int _pv_write(struct format_instance *fi, struct physical_volume *pv,
|
||||
void *mdl)
|
||||
{
|
||||
/* No on-disk PV structure change required! */
|
||||
/* FIXME vgcache could be wrong */
|
||||
return 1;
|
||||
//return (fi->fmt->cmd->fmt1->ops->pv_write(fi, pv, NULL));
|
||||
/*** FIXME Not required?
|
||||
struct volume_group *vg;
|
||||
struct list *pvh;
|
||||
|
||||
vg = _vg_read(fi, pv->vg_name);
|
||||
|
||||
// Find the PV in this VG
|
||||
if (vg) {
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
struct pv_list *vgpv = list_item(pvh, struct pv_list);
|
||||
|
||||
if (id_equal(&pv->id, &vgpv->pv->id)) {
|
||||
vgpv->pv->status = pv->status;
|
||||
vgpv->pv->size = pv->size;
|
||||
|
||||
// Not sure if it's worth doing these
|
||||
vgpv->pv->pe_size = pv->pe_size;
|
||||
vgpv->pv->pe_count = pv->pe_count;
|
||||
vgpv->pv->pe_start = pv->pe_start;
|
||||
vgpv->pv->pe_alloc_count = pv->pe_alloc_count;
|
||||
|
||||
// Write it back
|
||||
_vg_write(fi, vg);
|
||||
pool_free(fi->fmt->cmd->mem, vg);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
pool_free(fi->fmt->cmd->mem, vg);
|
||||
}
|
||||
|
||||
// Can't handle PVs not in a VG
|
||||
return 0;
|
||||
***/
|
||||
}
|
||||
|
||||
static int _pv_read(struct format_type *fmt, const char *pv_name,
|
||||
struct physical_volume *pv)
|
||||
{
|
||||
struct pv_list *pvl;
|
||||
struct list *vgh;
|
||||
struct list *pvh;
|
||||
struct list *names = pool_alloc(fmt->cmd->mem, sizeof(*names));
|
||||
struct name_list *nl;
|
||||
struct volume_group *vg;
|
||||
struct id *id;
|
||||
|
||||
/* FIXME Push up to pv_read */
|
||||
if (!(id = uuid_map_lookup_label(fmt->cmd->mem, fmt->cmd->um, pv_name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_init(names);
|
||||
if (!_get_vgs(fmt, names)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate(vgh, names) {
|
||||
|
||||
nl = list_item(vgh, struct name_list);
|
||||
if (!(vg = vg_read(fmt->cmd, nl->name))) {
|
||||
log_error("format_text: _pv_read failed to read VG %s",
|
||||
nl->name);
|
||||
return 0;
|
||||
}
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pvl = list_item(pvh, struct pv_list);
|
||||
if (id_equal(&pvl->pv->id, id)) {
|
||||
memcpy(pv, pvl->pv, sizeof(*pv));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pool_free(fmt->cmd->mem, names);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _destroy_instance(struct format_instance *fid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void _free_dirs(struct list *dir_list)
|
||||
{
|
||||
struct list *dl, *tmp;
|
||||
|
||||
list_iterate_safe(dl, tmp, dir_list) {
|
||||
list_del(dl);
|
||||
dbg_free(dl);
|
||||
}
|
||||
}
|
||||
|
||||
static void _destroy(struct format_type *fmt)
|
||||
{
|
||||
if (fmt->private) {
|
||||
_free_dirs((struct list *) fmt->private);
|
||||
dbg_free(fmt->private);
|
||||
}
|
||||
|
||||
dbg_free(fmt);
|
||||
}
|
||||
|
||||
static struct format_instance *_create_text_instance(struct format_type *fmt,
|
||||
const char *vgname,
|
||||
void *context)
|
||||
{
|
||||
struct format_instance *fid;
|
||||
struct metadata_area *mda;
|
||||
struct dir_list *dl;
|
||||
struct list *dlh, *dir_list;
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (!(fid = pool_alloc(fmt->cmd->mem, sizeof(*fid)))) {
|
||||
log_error("Couldn't allocate format instance object.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fid->fmt = fmt;
|
||||
|
||||
list_init(&fid->metadata_areas);
|
||||
|
||||
if (!vgname) {
|
||||
if (!(mda = pool_alloc(fmt->cmd->mem, sizeof(*mda)))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
mda->metadata_locn = context;
|
||||
list_add(&fid->metadata_areas, &mda->list);
|
||||
} else {
|
||||
dir_list = (struct list *) fmt->private;
|
||||
|
||||
list_iterate(dlh, dir_list) {
|
||||
dl = list_item(dlh, struct dir_list);
|
||||
if (lvm_snprintf(path, PATH_MAX, "%s/%s",
|
||||
dl->dir, vgname) < 0) {
|
||||
log_error("Name too long %s/%s", dl->dir,
|
||||
vgname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
context = create_text_context(fmt, path, NULL);
|
||||
if (!(mda = pool_alloc(fmt->cmd->mem, sizeof(*mda)))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
mda->metadata_locn = context;
|
||||
list_add(&fid->metadata_areas, &mda->list);
|
||||
}
|
||||
}
|
||||
|
||||
return fid;
|
||||
|
||||
}
|
||||
|
||||
void *create_text_context(struct format_type *fmt, const char *path,
|
||||
const char *desc)
|
||||
{
|
||||
struct text_context *tc;
|
||||
char *tmp;
|
||||
|
||||
if ((tmp = strstr(path, ".tmp")) && (tmp == path + strlen(path) - 4)) {
|
||||
log_error("%s: Volume group filename may not end in .tmp",
|
||||
path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(tc = pool_alloc(fmt->cmd->mem, sizeof(*tc)))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(tc->path_live = pool_strdup(fmt->cmd->mem, path))) {
|
||||
stack;
|
||||
goto no_mem;
|
||||
}
|
||||
|
||||
if (!(tc->path_edit = pool_alloc(fmt->cmd->mem, strlen(path) + 5))) {
|
||||
stack;
|
||||
goto no_mem;
|
||||
}
|
||||
sprintf(tc->path_edit, "%s.tmp", path);
|
||||
|
||||
if (!desc)
|
||||
desc = "";
|
||||
|
||||
if (!(tc->desc = pool_strdup(fmt->cmd->mem, desc))) {
|
||||
stack;
|
||||
goto no_mem;
|
||||
}
|
||||
|
||||
return (void *) tc;
|
||||
|
||||
no_mem:
|
||||
pool_free(fmt->cmd->mem, tc);
|
||||
|
||||
log_err("Couldn't allocate text format context object.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct format_handler _text_handler = {
|
||||
get_vgs: _get_vgs,
|
||||
get_pvs: _get_pvs,
|
||||
pv_read: _pv_read,
|
||||
pv_setup: _pv_setup,
|
||||
pv_write: _pv_write,
|
||||
vg_setup: _vg_setup,
|
||||
vg_read: _vg_read,
|
||||
vg_write: _vg_write,
|
||||
destroy: _destroy
|
||||
get_vgs: _get_vgs,
|
||||
get_pvs: _get_pvs,
|
||||
pv_read: _pv_read,
|
||||
pv_setup: _pv_setup,
|
||||
pv_write: _pv_write,
|
||||
pv_commit: _pv_commit,
|
||||
vg_setup: _vg_setup,
|
||||
lv_setup: _lv_setup,
|
||||
vg_read: _vg_read,
|
||||
vg_write: _vg_write,
|
||||
vg_remove: _vg_remove,
|
||||
vg_commit: _vg_commit,
|
||||
create_instance:_create_text_instance,
|
||||
destroy_instance:_destroy_instance,
|
||||
destroy: _destroy
|
||||
};
|
||||
|
||||
struct format_instance *text_format_create(struct cmd_context *cmd,
|
||||
const char *file,
|
||||
struct uuid_map *um)
|
||||
static int _add_dir(const char *dir, struct list *dir_list)
|
||||
{
|
||||
const char *no_alloc = "Couldn't allocate text format object.";
|
||||
struct dir_list *dl;
|
||||
|
||||
struct format_instance *fi;
|
||||
char *path;
|
||||
struct text_c *tc;
|
||||
|
||||
if (!(fi = dbg_malloc(sizeof(*fi)))) {
|
||||
log_err(no_alloc);
|
||||
return NULL;
|
||||
if (create_dir(dir)) {
|
||||
if (!(dl = dbg_malloc(sizeof(struct list) + strlen(dir) + 1))) {
|
||||
log_error("_add_dir allocation failed");
|
||||
return 0;
|
||||
}
|
||||
strcpy(dl->dir, dir);
|
||||
list_add(dir_list, &dl->list);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(path = dbg_strdup(file))) {
|
||||
dbg_free(fi);
|
||||
log_err(no_alloc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(tc = dbg_malloc(sizeof(*tc)))) {
|
||||
dbg_free(fi);
|
||||
dbg_free(path);
|
||||
log_err(no_alloc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tc->path = path;
|
||||
tc->um = um;
|
||||
|
||||
fi->cmd = cmd;
|
||||
fi->ops = &_text_handler;
|
||||
fi->private = tc;
|
||||
|
||||
return fi;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct format_type *create_text_format(struct cmd_context *cmd)
|
||||
{
|
||||
struct format_type *fmt;
|
||||
struct config_node *cn;
|
||||
struct config_value *cv;
|
||||
struct list *dir_list;
|
||||
|
||||
if (!(fmt = dbg_malloc(sizeof(*fmt)))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fmt->cmd = cmd;
|
||||
fmt->ops = &_text_handler;
|
||||
fmt->name = FMT_TEXT_NAME;
|
||||
fmt->features = FMT_SEGMENTS;
|
||||
|
||||
if (!(dir_list = dbg_malloc(sizeof(struct list)))) {
|
||||
log_error("Failed to allocate dir_list");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_init(dir_list);
|
||||
fmt->private = (void *) dir_list;
|
||||
|
||||
if (!(cn = find_config_node(cmd->cf->root, "metadata/dirs", '/'))) {
|
||||
log_verbose("metadata/dirs not in config file: Defaulting "
|
||||
"to /etc/lvm/metadata");
|
||||
_add_dir("/etc/lvm/metadata", dir_list);
|
||||
return fmt;
|
||||
}
|
||||
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != CFG_STRING) {
|
||||
log_error("Invalid string in config file: "
|
||||
"metadata/dirs");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!_add_dir(cv->v.str, dir_list)) {
|
||||
log_error("Failed to add %s to internal device cache",
|
||||
cv->v.str);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return fmt;
|
||||
|
||||
err:
|
||||
_free_dirs(dir_list);
|
||||
|
||||
dbg_free(fmt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -12,26 +12,28 @@
|
||||
#include "uuid-map.h"
|
||||
|
||||
/*
|
||||
* The archive format is used to maintain a set of metadata backup files
|
||||
* in an archive directory.
|
||||
* 'retain_days' is the minimum number of days that an archive file must
|
||||
* be held for.
|
||||
*
|
||||
* 'min_archives' is the minimum number of archives required to be kept
|
||||
* for each volume group.
|
||||
* Archives a vg config. 'retain_days' is the minimum number of
|
||||
* days that an archive file must be held for. 'min_archives' is
|
||||
* the minimum number of archives required to be kept for each
|
||||
* volume group.
|
||||
*/
|
||||
struct format_instance *archive_format_create(struct cmd_context *cmd,
|
||||
const char *dir,
|
||||
uint32_t retain_days,
|
||||
uint32_t min_archives);
|
||||
int archive_vg(struct volume_group *vg,
|
||||
const char *dir,
|
||||
const char *desc,
|
||||
uint32_t retain_days,
|
||||
uint32_t min_archive);
|
||||
|
||||
void backup_expire(struct format_instance *fi);
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* The text format can read and write a volume_group to a file.
|
||||
*/
|
||||
struct format_instance *text_format_create(struct cmd_context *cmd,
|
||||
const char *file,
|
||||
struct uuid_map *um);
|
||||
struct format_type *create_text_format(struct cmd_context *cmd);
|
||||
void *create_text_context(struct format_type *fmt, const char *path,
|
||||
const char *desc);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,8 +24,10 @@ 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);
|
||||
struct volume_group *text_vg_import(struct cmd_context *cmd, const char *file,
|
||||
struct uuid_map *um);
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,16 +10,19 @@
|
||||
#include "log.h"
|
||||
#include "uuid.h"
|
||||
#include "hash.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
|
||||
typedef int (*section_fn)(struct pool *mem,
|
||||
struct volume_group *vg, struct config_node *pvn,
|
||||
struct config_node *vgn, struct hash_table *pv_hash,
|
||||
struct uuid_map *um);
|
||||
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)
|
||||
|
||||
@@ -46,11 +49,10 @@ static int _read_id(struct id *id, struct config_node *cn, const char *path)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_pv(struct pool *mem,
|
||||
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 hash_table *pv_hash, struct uuid_map *um)
|
||||
{
|
||||
struct physical_volume *pv;
|
||||
struct pv_list *pvl;
|
||||
@@ -89,13 +91,15 @@ static int _read_pv(struct pool *mem,
|
||||
if (!(pv->dev = uuid_map_lookup(um, &pv->id))) {
|
||||
char buffer[64];
|
||||
|
||||
if (!id_write_format(&pv->id, buffer, sizeof(buffer))) {
|
||||
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
|
||||
log_err("Couldn't find device.");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
log_err("Couldn't find device with uuid '%s'.", buffer);
|
||||
|
||||
log_err("Couldn't find device with uuid '%s'.", buffer);
|
||||
return 0;
|
||||
if (partial_mode())
|
||||
vg->status |= PARTIAL_VG;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(pv->vg_name = pool_strdup(mem, vg->name))) {
|
||||
@@ -130,7 +134,8 @@ static int _read_pv(struct pool *mem,
|
||||
|
||||
pv->pe_size = vg->extent_size;
|
||||
pv->size = pv->pe_size * (uint64_t) pv->pe_count;
|
||||
pv->pe_allocated = 0;
|
||||
pv->pe_alloc_count = 0;
|
||||
pv->fid = fid;
|
||||
|
||||
vg->pv_count++;
|
||||
list_add(&vg->pvs, &pvl->list);
|
||||
@@ -144,7 +149,7 @@ static void _insert_segment(struct logical_volume *lv,
|
||||
struct list *segh;
|
||||
struct stripe_segment *comp;
|
||||
|
||||
list_iterate (segh, &lv->segments) {
|
||||
list_iterate(segh, &lv->segments) {
|
||||
comp = list_item(segh, struct stripe_segment);
|
||||
|
||||
if (comp->le > seg->le) {
|
||||
@@ -174,8 +179,7 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
|
||||
}
|
||||
|
||||
if (!_read_int32(sn, "stripes", &stripes)) {
|
||||
log_err("Couldn't read 'stripes' for segment '%s'.",
|
||||
sn->key);
|
||||
log_err("Couldn't read 'stripes' for segment '%s'.", sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -185,6 +189,7 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
|
||||
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'.",
|
||||
@@ -236,9 +241,8 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
|
||||
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;
|
||||
cn->v->v.str ? cn->v->v.str : "NULL", seg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
seg->area[s].pv = pv;
|
||||
@@ -259,7 +263,7 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
|
||||
* Adjust the extent counts in the pv and vg.
|
||||
*/
|
||||
allocated = seg->len / seg->stripes;
|
||||
pv->pe_allocated += allocated;
|
||||
pv->pe_alloc_count += allocated;
|
||||
vg->free_count -= allocated;
|
||||
}
|
||||
|
||||
@@ -331,7 +335,7 @@ static int _read_segments(struct pool *mem, struct volume_group *vg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_lv(struct pool *mem,
|
||||
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)
|
||||
@@ -360,6 +364,13 @@ static int _read_lv(struct pool *mem,
|
||||
|
||||
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.");
|
||||
@@ -371,6 +382,13 @@ static int _read_lv(struct pool *mem,
|
||||
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.");
|
||||
@@ -390,21 +408,75 @@ static int _read_lv(struct pool *mem,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_sections(const char *section, section_fn fn,
|
||||
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)
|
||||
struct uuid_map *um, int optional)
|
||||
{
|
||||
struct config_node *n;
|
||||
|
||||
if (!(n = find_config_node(vgn, section, '/'))) {
|
||||
log_err("Couldn't find section '%s'.", section);
|
||||
return 0;
|
||||
if (!optional) {
|
||||
log_err("Couldn't find section '%s'.", section);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (n = n->child; n; n = n->sib) {
|
||||
if (!fn(mem, vg, n, vgn, pv_hash, um)) {
|
||||
if (!fn(fid, mem, vg, n, vgn, pv_hash, um)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -413,19 +485,19 @@ static int _read_sections(const char *section, section_fn fn,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct volume_group *_read_vg(struct pool *mem, struct config_file *cf,
|
||||
static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
struct config_file *cf,
|
||||
struct uuid_map *um)
|
||||
{
|
||||
struct config_node *vgn = cf->root, *cn;
|
||||
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.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(vgn = cf->root)) {
|
||||
log_err("Couldn't find volume group in file.");
|
||||
return NULL;
|
||||
}
|
||||
@@ -434,16 +506,39 @@ static struct volume_group *_read_vg(struct pool *mem, struct config_file *cf,
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -492,29 +587,42 @@ static struct volume_group *_read_vg(struct pool *mem, struct config_file *cf,
|
||||
}
|
||||
|
||||
list_init(&vg->pvs);
|
||||
if (!_read_sections("physical_volumes", _read_pv, mem, vg,
|
||||
vgn, pv_hash, um)) {
|
||||
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("logical_volumes", _read_lv, mem, vg,
|
||||
vgn, pv_hash, um)) {
|
||||
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:
|
||||
bad:
|
||||
if (pv_hash)
|
||||
hash_destroy(pv_hash);
|
||||
|
||||
@@ -522,13 +630,30 @@ static struct volume_group *_read_vg(struct pool *mem, struct config_file *cf,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct volume_group *text_vg_import(struct cmd_context *cmd,
|
||||
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)
|
||||
struct uuid_map *um,
|
||||
time_t * when, char **desc)
|
||||
{
|
||||
struct volume_group *vg = NULL;
|
||||
struct config_file *cf;
|
||||
|
||||
*desc = NULL;
|
||||
*when = 0;
|
||||
|
||||
if (!(cf = create_config_file())) {
|
||||
stack;
|
||||
goto out;
|
||||
@@ -539,14 +664,14 @@ struct volume_group *text_vg_import(struct cmd_context *cmd,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(vg = _read_vg(cmd->mem, cf, um))) {
|
||||
if (!(vg = _read_vg(fid, cf, um))) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
vg->cmd = cmd;
|
||||
_read_desc(fid->fmt->cmd->mem, cf, when, desc);
|
||||
|
||||
out:
|
||||
out:
|
||||
destroy_config_file(cf);
|
||||
return vg;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ struct labeller_i {
|
||||
|
||||
static struct list _labellers;
|
||||
|
||||
|
||||
static struct labeller_i *_alloc_li(const char *name, struct labeller *l)
|
||||
{
|
||||
struct labeller_i *li;
|
||||
@@ -45,7 +44,6 @@ static void _free_li(struct labeller_i *li)
|
||||
dbg_free(li);
|
||||
}
|
||||
|
||||
|
||||
int label_init(void)
|
||||
{
|
||||
list_init(&_labellers);
|
||||
@@ -82,7 +80,7 @@ struct labeller *label_get_handler(const char *name)
|
||||
struct list *lih;
|
||||
struct labeller_i *li;
|
||||
|
||||
list_iterate (lih, &_labellers) {
|
||||
list_iterate(lih, &_labellers) {
|
||||
li = list_item(lih, struct labeller_i);
|
||||
if (!strcmp(li->name, name))
|
||||
return li->l;
|
||||
@@ -96,7 +94,7 @@ static struct labeller *_find_labeller(struct device *dev)
|
||||
struct list *lih;
|
||||
struct labeller_i *li;
|
||||
|
||||
list_iterate (lih, &_labellers) {
|
||||
list_iterate(lih, &_labellers) {
|
||||
li = list_item(lih, struct labeller_i);
|
||||
if (li->l->ops->can_handle(li->l, dev))
|
||||
return li->l;
|
||||
@@ -124,7 +122,7 @@ int label_read(struct device *dev, struct label **result)
|
||||
struct list *lih;
|
||||
struct labeller_i *li;
|
||||
|
||||
list_iterate (lih, &_labellers) {
|
||||
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;
|
||||
|
||||
@@ -27,324 +27,337 @@
|
||||
#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;
|
||||
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];
|
||||
uint32_t version[3];
|
||||
char disk_type[32];
|
||||
};
|
||||
|
||||
struct filter_private
|
||||
{
|
||||
void *mem;
|
||||
char disk_type[32];
|
||||
uint32_t version[3];
|
||||
int version_match;
|
||||
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 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;
|
||||
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;
|
||||
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;
|
||||
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);
|
||||
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;
|
||||
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)
|
||||
static inline void get_label_locations(uint64_t size, uint32_t sectsize,
|
||||
long *first, long *second)
|
||||
{
|
||||
*first = sectsize;
|
||||
*second = size*BLOCK_SIZE - sectsize;
|
||||
*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)
|
||||
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];
|
||||
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, §size))
|
||||
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)
|
||||
{
|
||||
if (!dev_get_size(dev, &size))
|
||||
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);
|
||||
if (!dev_get_sectsize(dev, §size))
|
||||
return 0;
|
||||
|
||||
/* Make sure datalen is a sensible size too */
|
||||
if (incore->extra_len > sectsize)
|
||||
continue;
|
||||
if (!dev_open(dev, O_RDONLY))
|
||||
return 0;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
block = dbg_malloc(sectsize);
|
||||
if (!block) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
memcpy(incore->extra_info, block + sizeof(struct label_ondisk), incore->extra_len);
|
||||
|
||||
dbg_free(block);
|
||||
dev_close(dev);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
ondisk = (struct label_ondisk *) block;
|
||||
get_label_locations(size, sectsize, &offset[0], &offset[1]);
|
||||
|
||||
dbg_free(block);
|
||||
dev_close(dev);
|
||||
/* 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;
|
||||
|
||||
return 0;
|
||||
/* 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)
|
||||
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];
|
||||
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_size(dev, &size))
|
||||
return 0;
|
||||
|
||||
if (!dev_get_sectsize(dev, §size))
|
||||
return 0;
|
||||
if (!dev_get_sectsize(dev, §size))
|
||||
return 0;
|
||||
|
||||
/* Can the metata fit in the remaining space ? */
|
||||
if (label->extra_len > sectsize - sizeof(struct label_ondisk))
|
||||
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;
|
||||
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]);
|
||||
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));
|
||||
/* 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");
|
||||
}
|
||||
|
||||
/* Write metadata to disk */
|
||||
if (!dev_open(dev, O_RDWR))
|
||||
{
|
||||
dbg_free(block);
|
||||
return 0;
|
||||
}
|
||||
dev_close(dev);
|
||||
|
||||
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 ((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;
|
||||
struct label *label;
|
||||
int status;
|
||||
|
||||
status = lvm2_label_read(l, dev, &label);
|
||||
if (status) label_free(label);
|
||||
status = lvm2_label_read(l, dev, &label);
|
||||
if (status)
|
||||
label_free(label);
|
||||
|
||||
return status;
|
||||
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;
|
||||
struct label *l;
|
||||
int status;
|
||||
struct filter_private *fp = (struct filter_private *) f->private;
|
||||
|
||||
status = lvm2_label_read(NULL, dev, &l);
|
||||
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;
|
||||
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_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_LESSEQUAL:
|
||||
if (l->version[0] == fp->version[0] &&
|
||||
l->version[1] <= fp->version[1])
|
||||
return 1;
|
||||
break;
|
||||
|
||||
case VERSION_MATCH_ANY:
|
||||
return 1;
|
||||
}
|
||||
case VERSION_MATCH_ANY:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
label_free(l);
|
||||
}
|
||||
label_free(l);
|
||||
}
|
||||
return 0;
|
||||
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);
|
||||
return lvm2_is_labelled(NULL, dev);
|
||||
}
|
||||
|
||||
static void _destroy(struct dev_filter *f)
|
||||
{
|
||||
struct filter_private *fp = (struct filter_private *) f->private;
|
||||
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 dev_filter *lvm2_label_format_filter_create(char *disk_type,
|
||||
uint32_t version[3],
|
||||
int match_type)
|
||||
{
|
||||
struct pool *mem;
|
||||
struct pool *mem;
|
||||
struct filter_private *fp;
|
||||
struct dev_filter *f;
|
||||
|
||||
@@ -353,7 +366,7 @@ struct dev_filter *lvm2_label_format_filter_create(char *disk_type, uint32_t ver
|
||||
match_type != VERSION_MATCH_LESSTHAN &&
|
||||
match_type != VERSION_MATCH_LESSEQUAL &&
|
||||
match_type != VERSION_MATCH_ANY)
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
mem = pool_create(10 * 1024);
|
||||
if (!mem) {
|
||||
@@ -362,13 +375,13 @@ struct dev_filter *lvm2_label_format_filter_create(char *disk_type, uint32_t ver
|
||||
}
|
||||
|
||||
if (!(f = pool_zalloc(mem, sizeof(*f)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(fp = pool_zalloc(mem, sizeof(*fp)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
fp->mem = mem;
|
||||
@@ -383,7 +396,7 @@ struct dev_filter *lvm2_label_format_filter_create(char *disk_type, uint32_t ver
|
||||
|
||||
return f;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
pool_destroy(mem);
|
||||
return NULL;
|
||||
}
|
||||
@@ -401,13 +414,13 @@ struct dev_filter *lvm2_label_filter_create()
|
||||
}
|
||||
|
||||
if (!(f = pool_zalloc(mem, sizeof(*f)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(fp = pool_zalloc(mem, sizeof(*fp)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
fp->mem = mem;
|
||||
@@ -417,7 +430,7 @@ struct dev_filter *lvm2_label_filter_create()
|
||||
|
||||
return f;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
pool_destroy(mem);
|
||||
return NULL;
|
||||
}
|
||||
@@ -425,137 +438,132 @@ struct dev_filter *lvm2_label_filter_create()
|
||||
/* 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];
|
||||
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_size(dev, &size))
|
||||
return 0;
|
||||
|
||||
if (!dev_get_sectsize(dev, §size))
|
||||
return 0;
|
||||
if (!dev_get_sectsize(dev, §size))
|
||||
return 0;
|
||||
|
||||
/* Allocate some space for the blocks we are going to read in */
|
||||
block1 = dbg_malloc(sectsize);
|
||||
if (!block1)
|
||||
{
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
block1 = dbg_malloc(sectsize);
|
||||
if (!block1) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
block2 = dbg_malloc(sectsize);
|
||||
if (!block2)
|
||||
{
|
||||
stack;
|
||||
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 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;
|
||||
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];
|
||||
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_size(dev, &size))
|
||||
return 0;
|
||||
|
||||
if (!dev_get_sectsize(dev, §size))
|
||||
return 0;
|
||||
if (!dev_get_sectsize(dev, §size))
|
||||
return 0;
|
||||
|
||||
if (!dev_open(dev, O_RDWR))
|
||||
{
|
||||
dbg_free(block);
|
||||
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);
|
||||
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");
|
||||
/* 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");
|
||||
/* ...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);
|
||||
dev_close(dev);
|
||||
|
||||
return ((status1 != 0) && (status2 != 0));
|
||||
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 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,
|
||||
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);
|
||||
label_register_handler("LVM2", &this_labeller);
|
||||
}
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
#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;
|
||||
@@ -67,4 +67,33 @@ struct device *uuid_map_lookup(struct uuid_map *um, struct id *id)
|
||||
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
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "uuid.h"
|
||||
#include "dev-cache.h"
|
||||
#include "pool.h"
|
||||
|
||||
/*
|
||||
* Holds a mapping from uuid -> device.
|
||||
@@ -22,5 +23,7 @@ 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
|
||||
|
||||
115
lib/locking/external_locking.c
Normal file
115
lib/locking/external_locking.c
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "log.h"
|
||||
#include "locking.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 <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 int lock_resource(struct cmd_context *cmd, const char *resource,
|
||||
int flags)
|
||||
{
|
||||
if (lock_fn)
|
||||
return lock_fn(cmd, resource, flags);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fin_external_locking(void)
|
||||
{
|
||||
if (end_fn)
|
||||
end_fn();
|
||||
|
||||
dlclose(locking_module);
|
||||
|
||||
locking_module = NULL;
|
||||
end_fn = NULL;
|
||||
lock_fn = NULL;
|
||||
}
|
||||
|
||||
int init_external_locking(struct locking_type *locking, struct config_file *cf)
|
||||
{
|
||||
char _lock_lib[PATH_MAX];
|
||||
|
||||
if (locking_module) {
|
||||
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));
|
||||
|
||||
/* 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];
|
||||
|
||||
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);
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_verbose("Opened external locking module %s", _lock_lib);
|
||||
return init_fn(2, cf);
|
||||
}
|
||||
260
lib/locking/file_locking.c
Normal file
260
lib/locking/file_locking.c
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "log.h"
|
||||
#include "locking.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 <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
|
||||
struct lock_list {
|
||||
struct list list;
|
||||
int lf;
|
||||
char *res;
|
||||
};
|
||||
|
||||
static struct list _lock_list;
|
||||
static char _lock_dir[NAME_LEN];
|
||||
|
||||
static sig_t _oldhandler;
|
||||
static sigset_t _fullsigset, _intsigset;
|
||||
static int _handler_installed;
|
||||
|
||||
static int _release_lock(const char *file)
|
||||
{
|
||||
struct lock_list *ll;
|
||||
struct list *llh, *llt;
|
||||
|
||||
struct stat buf1, buf2;
|
||||
|
||||
list_iterate_safe(llh, llt, &_lock_list) {
|
||||
ll = list_item(llh, struct lock_list);
|
||||
|
||||
if (!file || !strcmp(ll->res, file)) {
|
||||
list_del(llh);
|
||||
log_very_verbose("Unlocking %s", ll->res);
|
||||
|
||||
if (flock(ll->lf, LOCK_NB | LOCK_UN))
|
||||
log_sys_error("flock", ll->res);
|
||||
|
||||
if (!flock(ll->lf, LOCK_NB | LOCK_EX) &&
|
||||
!stat(ll->res, &buf1) &&
|
||||
!fstat(ll->lf, &buf2) &&
|
||||
!memcmp(&buf1.st_ino, &buf2.st_ino, sizeof(ino_t)))
|
||||
if (unlink(ll->res))
|
||||
log_sys_error("unlink", ll->res);
|
||||
|
||||
if (close(ll->lf) < 0)
|
||||
log_sys_error("close", ll->res);
|
||||
|
||||
dbg_free(ll->res);
|
||||
dbg_free(llh);
|
||||
|
||||
if (file)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fin_file_locking(void)
|
||||
{
|
||||
_release_lock(NULL);
|
||||
}
|
||||
|
||||
static void _remove_ctrl_c_handler()
|
||||
{
|
||||
siginterrupt(SIGINT, 0);
|
||||
if (!_handler_installed || _oldhandler == SIG_ERR)
|
||||
return;
|
||||
|
||||
sigprocmask(SIG_SETMASK, &_fullsigset, NULL);
|
||||
if (signal(SIGINT, _oldhandler) == SIG_ERR)
|
||||
log_sys_error("signal", "_remove_ctrl_c_handler");
|
||||
|
||||
_handler_installed = 0;
|
||||
}
|
||||
|
||||
void _trap_ctrl_c(int signal)
|
||||
{
|
||||
_remove_ctrl_c_handler();
|
||||
log_error("CTRL-c detected: giving up waiting for lock");
|
||||
return;
|
||||
}
|
||||
|
||||
static void _install_ctrl_c_handler()
|
||||
{
|
||||
if ((_oldhandler = signal(SIGINT, _trap_ctrl_c)) == SIG_ERR)
|
||||
return;
|
||||
|
||||
sigprocmask(SIG_SETMASK, &_intsigset, NULL);
|
||||
siginterrupt(SIGINT, 1);
|
||||
|
||||
_handler_installed = 1;
|
||||
}
|
||||
|
||||
static int _lock_file(const char *file, int flags)
|
||||
{
|
||||
int operation;
|
||||
int r = 1;
|
||||
|
||||
struct lock_list *ll;
|
||||
struct stat buf1, buf2;
|
||||
|
||||
switch (flags & LCK_TYPE_MASK) {
|
||||
case LCK_READ:
|
||||
operation = LOCK_SH;
|
||||
break;
|
||||
case LCK_WRITE:
|
||||
operation = LOCK_EX;
|
||||
break;
|
||||
case LCK_UNLOCK:
|
||||
return _release_lock(file);
|
||||
default:
|
||||
log_error("Unrecognised lock type: %d", flags & LCK_TYPE_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(ll = dbg_malloc(sizeof(struct lock_list))))
|
||||
return 0;
|
||||
|
||||
if (!(ll->res = dbg_strdup(file))) {
|
||||
dbg_free(ll);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ll->lf = -1;
|
||||
|
||||
log_very_verbose("Locking %s", ll->res);
|
||||
do {
|
||||
if (ll->lf > -1)
|
||||
close(ll->lf);
|
||||
|
||||
if ((ll->lf = open(file, O_CREAT | O_APPEND | O_RDWR, 0777))
|
||||
< 0) {
|
||||
log_sys_error("open", file);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if ((flags & LCK_NONBLOCK))
|
||||
operation |= LOCK_NB;
|
||||
else
|
||||
_install_ctrl_c_handler();
|
||||
|
||||
r = flock(ll->lf, operation);
|
||||
if (!(flags & LCK_NONBLOCK))
|
||||
_remove_ctrl_c_handler();
|
||||
|
||||
if (r) {
|
||||
log_sys_error("flock", ll->res);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!stat(ll->res, &buf1) && !fstat(ll->lf, &buf2) &&
|
||||
!memcmp(&buf1.st_ino, &buf2.st_ino, sizeof(ino_t)))
|
||||
break;
|
||||
} while (!(flags & LCK_NONBLOCK));
|
||||
|
||||
list_add(&_lock_list, &ll->list);
|
||||
return 1;
|
||||
|
||||
err:
|
||||
dbg_free(ll->res);
|
||||
dbg_free(ll);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lock_resource(struct cmd_context *cmd, const char *resource, int flags)
|
||||
{
|
||||
char lockfile[PATH_MAX];
|
||||
|
||||
switch (flags & LCK_SCOPE_MASK) {
|
||||
case LCK_VG:
|
||||
if (!resource || !*resource)
|
||||
lvm_snprintf(lockfile, sizeof(lockfile),
|
||||
"%s/P_orphans", _lock_dir);
|
||||
else
|
||||
lvm_snprintf(lockfile, sizeof(lockfile),
|
||||
"%s/V_%s", _lock_dir, resource);
|
||||
if (!_lock_file(lockfile, 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))
|
||||
return 0;
|
||||
break;
|
||||
case LCK_READ:
|
||||
if (!lv_activate(cmd, resource))
|
||||
return 0;
|
||||
break;
|
||||
case LCK_WRITE:
|
||||
if (!lv_suspend_if_active(cmd, resource))
|
||||
return 0;
|
||||
break;
|
||||
case LCK_EXCL:
|
||||
if (!lv_deactivate(cmd, resource))
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log_error("Unrecognised lock scope: %d",
|
||||
flags & LCK_SCOPE_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int init_file_locking(struct locking_type *locking, struct config_file *cf)
|
||||
{
|
||||
locking->lock_resource = lock_resource;
|
||||
locking->fin_locking = fin_file_locking;
|
||||
|
||||
/* Get lockfile directory from config file */
|
||||
strncpy(_lock_dir, find_config_str(cf->root, "global/locking_dir",
|
||||
'/', DEFAULT_LOCK_DIR),
|
||||
sizeof(_lock_dir));
|
||||
|
||||
if (!create_dir(_lock_dir))
|
||||
return 0;
|
||||
|
||||
list_init(&_lock_list);
|
||||
|
||||
if (sigfillset(&_intsigset) || sigfillset(&_fullsigset)) {
|
||||
log_sys_error("sigfillset", "init_file_locking");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sigdelset(&_intsigset, SIGINT)) {
|
||||
log_sys_error("sigdelset", "init_file_locking");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
149
lib/locking/locking.c
Normal file
149
lib/locking/locking.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "log.h"
|
||||
#include "locking.h"
|
||||
#include "locking_types.h"
|
||||
#include "lvm-string.h"
|
||||
#include "activate.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
static struct locking_type _locking;
|
||||
static sigset_t _oldset;
|
||||
|
||||
static int _lock_count = 0; /* Number of locks held */
|
||||
static int _signals_blocked = 0;
|
||||
|
||||
static void _block_signals(void)
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
if (_signals_blocked)
|
||||
return;
|
||||
|
||||
if (sigfillset(&set)) {
|
||||
log_sys_error("sigfillset", "_block_signals");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sigprocmask(SIG_SETMASK, &set, &_oldset)) {
|
||||
log_sys_error("sigprocmask", "_block_signals");
|
||||
return;
|
||||
}
|
||||
|
||||
_signals_blocked = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void _unblock_signals(void)
|
||||
{
|
||||
/* Don't unblock signals while any locks are held */
|
||||
if (!_signals_blocked || _lock_count)
|
||||
return;
|
||||
|
||||
if (sigprocmask(SIG_SETMASK, &_oldset, NULL)) {
|
||||
log_sys_error("sigprocmask", "_block_signals");
|
||||
return;
|
||||
}
|
||||
|
||||
_signals_blocked = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void _update_lock_count(int flags)
|
||||
{
|
||||
if ((flags & LCK_TYPE_MASK) == LCK_UNLOCK)
|
||||
_lock_count--;
|
||||
else
|
||||
_lock_count++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select a locking type
|
||||
*/
|
||||
int init_locking(int type, struct config_file *cf)
|
||||
{
|
||||
switch (type) {
|
||||
case 0:
|
||||
init_no_locking(&_locking, cf);
|
||||
log_print("WARNING: Locking disabled. Be careful! "
|
||||
"This could corrupt your metadata.");
|
||||
break;
|
||||
case 1:
|
||||
if (!init_file_locking(&_locking, cf))
|
||||
return 0;
|
||||
log_very_verbose("File-based locking enabled.");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (!init_external_locking(&_locking, cf))
|
||||
return 0;
|
||||
log_very_verbose("External locking enabled.");
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("Unknown locking type requested.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void fin_locking(void)
|
||||
{
|
||||
_locking.fin_locking();
|
||||
}
|
||||
|
||||
/*
|
||||
* VG locking is by VG name.
|
||||
* FIXME This should become VG uuid.
|
||||
*/
|
||||
int _lock_vol(struct cmd_context *cmd, const char *resource, int flags)
|
||||
{
|
||||
_block_signals();
|
||||
|
||||
if (!(_locking.lock_resource(cmd, resource, flags))) {
|
||||
_unblock_signals();
|
||||
return 0;
|
||||
}
|
||||
|
||||
_update_lock_count(flags);
|
||||
_unblock_signals();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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. */
|
||||
strncpy(resource, (char *) vol, sizeof(resource));
|
||||
break;
|
||||
default:
|
||||
log_error("Unrecognised lock scope: %d",
|
||||
flags & LCK_SCOPE_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_lock_vol(cmd, resource, flags))
|
||||
return 0;
|
||||
|
||||
/* Perform immediate unlock unless LCK_HOLD set */
|
||||
if (!(flags & LCK_HOLD) && ((flags & LCK_TYPE_MASK) != LCK_UNLOCK)) {
|
||||
if (!_lock_vol(cmd, resource,
|
||||
(flags & ~LCK_TYPE_MASK) | LCK_UNLOCK))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
67
lib/locking/locking.h
Normal file
67
lib/locking/locking.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "metadata.h"
|
||||
#include "uuid.h"
|
||||
#include "config.h"
|
||||
|
||||
int init_locking(int type, struct config_file *cf);
|
||||
void fin_locking(void);
|
||||
|
||||
/*
|
||||
* LCK_VG:
|
||||
* Lock/unlock on-disk volume group data
|
||||
* Use "" to lock orphan PVs
|
||||
* char *vol holds volume group name
|
||||
*
|
||||
* LCK_LV:
|
||||
* Lock/unlock an individual logical volume
|
||||
* char *vol holds lvid
|
||||
*/
|
||||
int lock_vol(struct cmd_context *cmd, const char *vol, int flags);
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
|
||||
/*
|
||||
* Lock scope
|
||||
*/
|
||||
#define LCK_SCOPE_MASK 0x0000FF00
|
||||
#define LCK_VG 0x00000000
|
||||
#define LCK_LV 0x00000100
|
||||
|
||||
/*
|
||||
* Lock bits
|
||||
*/
|
||||
#define LCK_NONBLOCK 0x00010000 /* Don't block waiting for lock? */
|
||||
#define LCK_HOLD 0x00020000 /* Hold lock when lock_vol returns? */
|
||||
|
||||
/*
|
||||
* Common combinations
|
||||
*/
|
||||
#define LCK_VG_READ (LCK_VG | LCK_READ | LCK_HOLD)
|
||||
#define LCK_VG_WRITE (LCK_VG | LCK_WRITE | LCK_HOLD)
|
||||
#define LCK_VG_UNLOCK (LCK_VG | LCK_UNLOCK)
|
||||
|
||||
#define LCK_LV_DEACTIVATE (LCK_LV | LCK_EXCL)
|
||||
#define LCK_LV_SUSPEND (LCK_LV | LCK_WRITE)
|
||||
#define LCK_LV_ACTIVATE (LCK_LV | LCK_READ)
|
||||
#define LCK_LV_UNLOCK (LCK_LV | LCK_UNLOCK)
|
||||
|
||||
#define unlock_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_UNLOCK)
|
||||
#define unlock_vg(cmd, vol) lock_vol(cmd, vol, LCK_VG_UNLOCK)
|
||||
|
||||
32
lib/locking/locking_types.h
Normal file
32
lib/locking/locking_types.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "metadata.h"
|
||||
#include "config.h"
|
||||
|
||||
typedef int (*lock_resource_fn)(struct cmd_context *cmd, const char *resource,
|
||||
int flags);
|
||||
|
||||
typedef void (*fin_lock_fn)(void);
|
||||
|
||||
|
||||
struct locking_type {
|
||||
lock_resource_fn lock_resource;
|
||||
|
||||
fin_lock_fn fin_locking;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Locking types
|
||||
*/
|
||||
int init_no_locking(struct locking_type *locking, struct config_file *cf);
|
||||
|
||||
int init_file_locking(struct locking_type *locking, struct config_file *cf);
|
||||
|
||||
int init_external_locking(struct locking_type *locking, struct config_file *cf);
|
||||
|
||||
60
lib/locking/no_locking.c
Normal file
60
lib/locking/no_locking.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "log.h"
|
||||
#include "locking.h"
|
||||
#include "locking_types.h"
|
||||
#include "lvm-string.h"
|
||||
#include "activate.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
/*
|
||||
* No locking
|
||||
*/
|
||||
|
||||
static void _no_fin_locking(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static int _no_lock_resource(struct cmd_context *cmd, const char *resource,
|
||||
int flags)
|
||||
{
|
||||
switch (flags & LCK_SCOPE_MASK) {
|
||||
case LCK_VG:
|
||||
break;
|
||||
case LCK_LV:
|
||||
switch (flags & LCK_TYPE_MASK) {
|
||||
case LCK_UNLOCK:
|
||||
return lv_resume_if_active(cmd, resource);
|
||||
case LCK_READ:
|
||||
return lv_activate(cmd, resource);
|
||||
case LCK_WRITE:
|
||||
return lv_suspend_if_active(cmd, resource);
|
||||
case LCK_EXCL:
|
||||
return lv_deactivate(cmd, resource);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log_error("Unrecognised lock scope: %d",
|
||||
flags & LCK_SCOPE_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int init_no_locking(struct locking_type *locking, struct config_file *cf)
|
||||
{
|
||||
locking->lock_resource = _no_lock_resource;
|
||||
locking->fin_locking = _no_fin_locking;
|
||||
|
||||
return 1;
|
||||
}
|
||||
150
lib/log/log.c
150
lib/log/log.c
@@ -17,137 +17,162 @@ static int _debug_level = 0;
|
||||
static int _syslog = 0;
|
||||
static int _indent = 1;
|
||||
static int _log_cmd_name = 0;
|
||||
static int _log_suppress = 0;
|
||||
static char _cmd_name[30] = "";
|
||||
static char _msg_prefix[30] = " ";
|
||||
|
||||
void init_log(FILE *fp) {
|
||||
void init_log(FILE * fp)
|
||||
{
|
||||
_log = fp;
|
||||
}
|
||||
|
||||
void init_syslog(int facility) {
|
||||
void init_syslog(int facility)
|
||||
{
|
||||
openlog("lvm", LOG_PID, facility);
|
||||
_syslog = 1;
|
||||
}
|
||||
|
||||
void fin_log() {
|
||||
void log_suppress(int suppress)
|
||||
{
|
||||
_log_suppress = suppress;
|
||||
}
|
||||
|
||||
void fin_log()
|
||||
{
|
||||
_log = 0;
|
||||
}
|
||||
|
||||
void fin_syslog() {
|
||||
void fin_syslog()
|
||||
{
|
||||
if (_syslog)
|
||||
closelog();
|
||||
_syslog = 0;
|
||||
}
|
||||
|
||||
void init_verbose(int level) {
|
||||
void init_verbose(int level)
|
||||
{
|
||||
_verbose_level = level;
|
||||
}
|
||||
|
||||
void init_test(int level) {
|
||||
void init_test(int level)
|
||||
{
|
||||
_test = level;
|
||||
if (_test)
|
||||
log_print("Test mode. Metadata will NOT be updated.");
|
||||
}
|
||||
|
||||
void init_partial(int level) {
|
||||
void init_partial(int level)
|
||||
{
|
||||
_partial = level;
|
||||
}
|
||||
|
||||
void init_cmd_name(int status) {
|
||||
void init_cmd_name(int status)
|
||||
{
|
||||
_log_cmd_name = status;
|
||||
}
|
||||
|
||||
void set_cmd_name(const char *cmd) {
|
||||
void set_cmd_name(const char *cmd)
|
||||
{
|
||||
if (!_log_cmd_name)
|
||||
return;
|
||||
strncpy(_cmd_name, cmd, sizeof(_cmd_name));
|
||||
_cmd_name[sizeof(_cmd_name) - 1] = '\0';
|
||||
}
|
||||
|
||||
void init_msg_prefix(const char *prefix) {
|
||||
void init_msg_prefix(const char *prefix)
|
||||
{
|
||||
strncpy(_msg_prefix, prefix, sizeof(_msg_prefix));
|
||||
_msg_prefix[sizeof(_msg_prefix) - 1] = '\0';
|
||||
}
|
||||
|
||||
void init_indent(int indent) {
|
||||
void init_indent(int indent)
|
||||
{
|
||||
_indent = indent;
|
||||
}
|
||||
|
||||
int test_mode() {
|
||||
int test_mode()
|
||||
{
|
||||
return _test;
|
||||
}
|
||||
|
||||
int partial_mode() {
|
||||
int partial_mode()
|
||||
{
|
||||
return _partial;
|
||||
}
|
||||
|
||||
void init_debug(int level) {
|
||||
void init_debug(int level)
|
||||
{
|
||||
_debug_level = level;
|
||||
}
|
||||
|
||||
int debug_level() {
|
||||
int debug_level()
|
||||
{
|
||||
return _debug_level;
|
||||
}
|
||||
|
||||
void print_log(int level, const char *file, int line, const char *format, ...) {
|
||||
void print_log(int level, const char *file, int line, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
switch(level) {
|
||||
case _LOG_DEBUG:
|
||||
if (_verbose_level > 2 && format[1]) {
|
||||
printf("%s%s", _cmd_name, _msg_prefix);
|
||||
if (_indent)
|
||||
printf(" ");
|
||||
vprintf(format, ap);
|
||||
putchar('\n');
|
||||
}
|
||||
break;
|
||||
if (!_log_suppress) {
|
||||
va_start(ap, format);
|
||||
switch (level) {
|
||||
case _LOG_DEBUG:
|
||||
if (!strcmp("<backtrace>", format))
|
||||
break;
|
||||
if (_verbose_level > 2) {
|
||||
printf("%s%s", _cmd_name, _msg_prefix);
|
||||
if (_indent)
|
||||
printf(" ");
|
||||
vprintf(format, ap);
|
||||
putchar('\n');
|
||||
}
|
||||
break;
|
||||
|
||||
case _LOG_INFO:
|
||||
if (_verbose_level > 1) {
|
||||
case _LOG_INFO:
|
||||
if (_verbose_level > 1) {
|
||||
printf("%s%s", _cmd_name, _msg_prefix);
|
||||
if (_indent)
|
||||
printf(" ");
|
||||
vprintf(format, ap);
|
||||
putchar('\n');
|
||||
}
|
||||
break;
|
||||
case _LOG_NOTICE:
|
||||
if (_verbose_level) {
|
||||
printf("%s%s", _cmd_name, _msg_prefix);
|
||||
if (_indent)
|
||||
printf(" ");
|
||||
vprintf(format, ap);
|
||||
putchar('\n');
|
||||
}
|
||||
break;
|
||||
case _LOG_WARN:
|
||||
printf("%s%s", _cmd_name, _msg_prefix);
|
||||
if (_indent)
|
||||
printf(" ");
|
||||
vprintf(format, ap);
|
||||
putchar('\n');
|
||||
break;
|
||||
case _LOG_ERR:
|
||||
fprintf(stderr, "%s%s", _cmd_name, _msg_prefix);
|
||||
vfprintf(stderr, format, ap);
|
||||
fputc('\n', stderr);
|
||||
break;
|
||||
case _LOG_FATAL:
|
||||
default:
|
||||
fprintf(stderr, "%s%s", _cmd_name, _msg_prefix);
|
||||
vfprintf(stderr, format, ap);
|
||||
fputc('\n', stderr);
|
||||
break;
|
||||
;
|
||||
}
|
||||
break;
|
||||
case _LOG_NOTICE:
|
||||
if (_verbose_level) {
|
||||
printf("%s%s", _cmd_name, _msg_prefix);
|
||||
if (_indent)
|
||||
printf(" ");
|
||||
vprintf(format, ap);
|
||||
putchar('\n');
|
||||
}
|
||||
break;
|
||||
case _LOG_WARN:
|
||||
printf("%s%s", _cmd_name, _msg_prefix);
|
||||
vprintf(format, ap);
|
||||
putchar('\n');
|
||||
break;
|
||||
case _LOG_ERR:
|
||||
fprintf(stderr, "%s%s", _cmd_name, _msg_prefix);
|
||||
vfprintf(stderr, format, ap);
|
||||
fputc('\n',stderr);
|
||||
break;
|
||||
case _LOG_FATAL:
|
||||
default:
|
||||
fprintf(stderr, "%s%s", _cmd_name, _msg_prefix);
|
||||
vfprintf(stderr, format, ap);
|
||||
fputc('\n',stderr);
|
||||
break;
|
||||
;
|
||||
va_end(ap);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
if (level > _debug_level)
|
||||
return;
|
||||
|
||||
if (_log) {
|
||||
fprintf(_log, "%s:%d %s%s", file, line, _cmd_name,
|
||||
_msg_prefix);
|
||||
fprintf(_log, "%s:%d %s%s", file, line, _cmd_name, _msg_prefix);
|
||||
|
||||
va_start(ap, format);
|
||||
vfprintf(_log, format, ap);
|
||||
@@ -158,9 +183,8 @@ void print_log(int level, const char *file, int line, const char *format, ...) {
|
||||
}
|
||||
|
||||
if (_syslog) {
|
||||
va_start(ap, format);
|
||||
va_start(ap, format);
|
||||
vsyslog(level, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
* log_verbose - print to stdout if verbose is set (-v)
|
||||
* log_very_verbose - print to stdout if verbose is set twice (-vv)
|
||||
* log_debug - print to stdout if verbose is set three times (-vvv)
|
||||
* (suppressed if single-character string such as with 'stack')
|
||||
*
|
||||
* In addition, messages will be logged to file or syslog if they
|
||||
* are more serious than the log level specified with the log/debug_level
|
||||
@@ -60,6 +59,9 @@ int test_mode(void);
|
||||
int partial_mode(void);
|
||||
int debug_level(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) ));
|
||||
|
||||
@@ -72,7 +74,7 @@ void print_log(int level, const char *file, int line, const char *format, ...)
|
||||
#define log_err(x...) plog(_LOG_ERR, x)
|
||||
#define log_fatal(x...) plog(_LOG_FATAL, x)
|
||||
|
||||
#define stack log_debug( "s" ) /* Backtrace on error */
|
||||
#define stack log_debug("<backtrace>") /* Backtrace on error */
|
||||
|
||||
#define log_error(fmt, args...) log_err(fmt , ## args)
|
||||
#define log_print(fmt, args...) log_warn(fmt , ## args)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "log.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "lvm-string.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
@@ -24,7 +25,7 @@ static void _get_extents(struct stripe_segment *seg)
|
||||
for (s = 0; s < seg->stripes; s++) {
|
||||
pv = seg->area[s].pv;
|
||||
count = seg->len / seg->stripes;
|
||||
pv->pe_allocated += count;
|
||||
pv->pe_alloc_count += count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +38,8 @@ static void _put_extents(struct stripe_segment *seg)
|
||||
pv = seg->area[s].pv;
|
||||
count = seg->len / seg->stripes;
|
||||
|
||||
assert(pv->pe_allocated >= count);
|
||||
pv->pe_allocated -= count;
|
||||
assert(pv->pe_alloc_count >= count);
|
||||
pv->pe_alloc_count -= count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +58,7 @@ 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;
|
||||
@@ -116,8 +117,8 @@ static int _alloc_striped(struct logical_volume *lv,
|
||||
struct pv_map *pvm;
|
||||
size_t len;
|
||||
|
||||
list_iterate (pvmh, pvms)
|
||||
pv_count++;
|
||||
list_iterate(pvmh, pvms)
|
||||
pv_count++;
|
||||
|
||||
/* allocate an array of pv_areas, one candidate per pv */
|
||||
len = sizeof(*areas) * pv_count;
|
||||
@@ -129,7 +130,7 @@ static int _alloc_striped(struct logical_volume *lv,
|
||||
while (allocated != lv->le_count) {
|
||||
|
||||
index = 0;
|
||||
list_iterate (pvmh, pvms) {
|
||||
list_iterate(pvmh, pvms) {
|
||||
pvm = list_item(pvmh, struct pv_map);
|
||||
|
||||
if (list_empty(&pvm->areas))
|
||||
@@ -142,8 +143,7 @@ static int _alloc_striped(struct logical_volume *lv,
|
||||
if (index < stripes) {
|
||||
log_error("Insufficient allocatable extents suitable "
|
||||
"for striping for logical volume "
|
||||
"%s: %u required",
|
||||
lv->name, lv->le_count);
|
||||
"%s: %u required", lv->name, lv->le_count);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -158,19 +158,18 @@ static int _alloc_striped(struct logical_volume *lv,
|
||||
}
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
out:
|
||||
dbg_free(areas);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The heart of the allocation code. This function takes a
|
||||
* pv_area and allocates it to the lv. If the lv doesn't need
|
||||
* 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;
|
||||
@@ -267,7 +266,7 @@ static int _alloc_simple(struct logical_volume *lv,
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
done:
|
||||
if (allocated != lv->le_count) {
|
||||
log_error("Insufficient allocatable logical extents (%u) "
|
||||
"for logical volume %s: %u required",
|
||||
@@ -395,7 +394,7 @@ struct logical_volume *lv_create(struct format_instance *fi,
|
||||
if (stripes > list_size(acceptable_pvs)) {
|
||||
log_error("Number of stripes (%u) must not exceed "
|
||||
"number of physical volumes (%d)", stripes,
|
||||
list_size(acceptable_pvs));
|
||||
list_size(acceptable_pvs));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -415,7 +414,7 @@ struct logical_volume *lv_create(struct format_instance *fi,
|
||||
|
||||
lv = ll->lv;
|
||||
|
||||
strcpy(lv->id.uuid, "");
|
||||
lv->vg = vg;
|
||||
|
||||
if (!(lv->name = pool_strdup(cmd->mem, name))) {
|
||||
stack;
|
||||
@@ -424,9 +423,9 @@ struct logical_volume *lv_create(struct format_instance *fi,
|
||||
|
||||
lv->status = status;
|
||||
lv->read_ahead = 0;
|
||||
lv->size = extents * vg->extent_size;
|
||||
lv->minor = -1;
|
||||
lv->size = (uint64_t) extents *vg->extent_size;
|
||||
lv->le_count = extents;
|
||||
lv->vg = vg;
|
||||
list_init(&lv->segments);
|
||||
|
||||
if (!_allocate(vg, lv, acceptable_pvs, 0u, stripes, stripe_size)) {
|
||||
@@ -434,7 +433,7 @@ struct logical_volume *lv_create(struct format_instance *fi,
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (fi->ops->lv_setup && !fi->ops->lv_setup(fi, lv)) {
|
||||
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
@@ -444,7 +443,7 @@ struct logical_volume *lv_create(struct format_instance *fi,
|
||||
|
||||
return lv;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
if (ll)
|
||||
pool_free(cmd->mem, ll);
|
||||
|
||||
@@ -459,8 +458,7 @@ int lv_reduce(struct format_instance *fi,
|
||||
uint32_t count = extents;
|
||||
|
||||
for (segh = lv->segments.p;
|
||||
(segh != &lv->segments) && count;
|
||||
segh = segh->p) {
|
||||
(segh != &lv->segments) && count; segh = segh->p) {
|
||||
seg = list_item(segh, struct stripe_segment);
|
||||
|
||||
if (seg->len <= count) {
|
||||
@@ -478,9 +476,9 @@ int lv_reduce(struct format_instance *fi,
|
||||
}
|
||||
|
||||
lv->le_count -= extents;
|
||||
lv->size = lv->le_count * lv->vg->extent_size;
|
||||
lv->size = (uint64_t) lv->le_count * lv->vg->extent_size;
|
||||
|
||||
if (fi->ops->lv_setup && !fi->ops->lv_setup(fi, lv)) {
|
||||
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -491,16 +489,13 @@ int lv_reduce(struct format_instance *fi,
|
||||
int lv_extend(struct format_instance *fi,
|
||||
struct logical_volume *lv,
|
||||
uint32_t stripes, uint32_t stripe_size,
|
||||
uint32_t extents,
|
||||
struct list *acceptable_pvs)
|
||||
uint32_t extents, struct list *acceptable_pvs)
|
||||
{
|
||||
uint32_t old_le_count = lv->le_count;
|
||||
uint64_t old_size = lv->size;
|
||||
|
||||
lv->le_count += extents;
|
||||
lv->size += extents * lv->vg->extent_size;
|
||||
|
||||
/* FIXME: Format1 must ensure stripes is consistent with 1st seg */
|
||||
lv->size += (uint64_t) extents *lv->vg->extent_size;
|
||||
|
||||
if (!_allocate(lv->vg, lv, acceptable_pvs, old_le_count,
|
||||
stripes, stripe_size)) {
|
||||
@@ -515,7 +510,7 @@ int lv_extend(struct format_instance *fi,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fi->ops->lv_setup && !fi->ops->lv_setup(fi, lv)) {
|
||||
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -535,8 +530,8 @@ 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));
|
||||
list_iterate(segh, &lv->segments)
|
||||
_put_extents(list_item(segh, struct stripe_segment));
|
||||
|
||||
vg->lv_count--;
|
||||
vg->free_count += lv->le_count;
|
||||
|
||||
@@ -41,7 +41,7 @@ int lv_merge_segments(struct logical_volume *lv)
|
||||
struct list *segh;
|
||||
struct stripe_segment *current, *prev = NULL;
|
||||
|
||||
list_iterate (segh, &lv->segments) {
|
||||
list_iterate(segh, &lv->segments) {
|
||||
current = list_item(segh, struct stripe_segment);
|
||||
|
||||
if (_merge(prev, current))
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
#include "device.h"
|
||||
#include "dev-cache.h"
|
||||
#include "metadata.h"
|
||||
#include "toolcontext.h"
|
||||
#include "lvm-string.h"
|
||||
#include "uuid.h"
|
||||
#include "vgcache.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -17,17 +21,17 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
|
||||
{
|
||||
struct pv_list *pvl;
|
||||
struct physical_volume *pv;
|
||||
struct pool *mem = fi->cmd->mem;
|
||||
struct pool *mem = fi->fmt->cmd->mem;
|
||||
|
||||
log_verbose("Adding physical volume '%s' to volume group '%s'",
|
||||
pv_name, vg->name);
|
||||
|
||||
if (!(pvl = pool_alloc(mem, sizeof (*pvl)))) {
|
||||
if (!(pvl = pool_alloc(mem, sizeof(*pvl)))) {
|
||||
log_error("pv_list allocation for '%s' failed", pv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(pv = fi->ops->pv_read(fi, pv_name))) {
|
||||
if (!(pv = pv_read(fi->fmt->cmd, pv_name))) {
|
||||
log_error("Failed to read existing physical volume '%s'",
|
||||
pv_name);
|
||||
return 0;
|
||||
@@ -44,25 +48,23 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Units of 512-byte sectors */
|
||||
if (!dev_get_size(pv->dev, &pv->size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Units of 512-byte sectors */
|
||||
pv->pe_size = vg->extent_size;
|
||||
|
||||
/* FIXME Do proper rounding-up alignment? */
|
||||
/* Reserved space for label; this holds 0 for PVs created by LVM1 */
|
||||
if (pv->pe_start < PE_ALIGN)
|
||||
pv->pe_start = PE_ALIGN;
|
||||
|
||||
/*
|
||||
* The next two fields should be corrected
|
||||
* by fi->pv_setup.
|
||||
*/
|
||||
pv->pe_start = 0;
|
||||
pv->pe_count = pv->size / pv->pe_size;
|
||||
pv->pe_count = (pv->size - pv->pe_start) / pv->pe_size;
|
||||
|
||||
pv->pe_allocated = 0;
|
||||
pv->pe_alloc_count = 0;
|
||||
|
||||
if (!fi->ops->pv_setup(fi, pv, vg)) {
|
||||
if (!fi->fmt->ops->pv_setup(fi, pv, vg)) {
|
||||
log_error("Format-specific setup of physical volume '%s' "
|
||||
"failed.", pv_name);
|
||||
return 0;
|
||||
@@ -116,42 +118,43 @@ const char *strip_dir(const char *vg_name, const char *dev_dir)
|
||||
return vg_name;
|
||||
}
|
||||
|
||||
struct volume_group *vg_create(struct format_instance *fi, const char *vg_name,
|
||||
struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||
uint32_t extent_size, int max_pv, int max_lv,
|
||||
int pv_count, char **pv_names)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
struct pool *mem = fi->cmd->mem;
|
||||
struct pool *mem = cmd->mem;
|
||||
|
||||
if (!(vg = pool_alloc(mem, sizeof (*vg)))) {
|
||||
if (!(vg = pool_zalloc(mem, sizeof(*vg)))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* is this vg name already in use ? */
|
||||
init_partial(1);
|
||||
if (fi->ops->vg_read(fi, vg_name)) {
|
||||
if (vg_read(cmd, vg_name)) {
|
||||
log_err("A volume group called '%s' already exists.", vg_name);
|
||||
goto bad;
|
||||
}
|
||||
init_partial(0);
|
||||
|
||||
if (!id_create(&vg->id)) {
|
||||
log_err("Couldn't create uuid for volume group '%s'.",
|
||||
vg_name);
|
||||
log_err("Couldn't create uuid for volume group '%s'.", vg_name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Strip dev_dir if present */
|
||||
vg_name = strip_dir(vg_name, fi->cmd->dev_dir);
|
||||
vg_name = strip_dir(vg_name, cmd->dev_dir);
|
||||
|
||||
vg->cmd = fi->cmd;
|
||||
vg->cmd = cmd;
|
||||
|
||||
if (!(vg->name = pool_strdup(mem, vg_name))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
vg->seqno = 0;
|
||||
|
||||
vg->status = (RESIZEABLE_VG | LVM_READ | LVM_WRITE);
|
||||
vg->system_id = pool_alloc(mem, NAME_LEN);
|
||||
*vg->system_id = '\0';
|
||||
@@ -169,29 +172,38 @@ struct volume_group *vg_create(struct format_instance *fi, const char *vg_name,
|
||||
vg->lv_count = 0;
|
||||
list_init(&vg->lvs);
|
||||
|
||||
if (!fi->ops->vg_setup(fi, vg)) {
|
||||
vg->snapshot_count = 0;
|
||||
list_init(&vg->snapshots);
|
||||
|
||||
if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg_name,
|
||||
NULL))) {
|
||||
log_error("Failed to create format instance");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!vg->fid->fmt->ops->vg_setup(vg->fid, vg)) {
|
||||
log_error("Format specific setup of volume group '%s' failed.",
|
||||
vg_name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* attach the pv's */
|
||||
if (!vg_extend(fi, vg, pv_count, pv_names))
|
||||
if (!vg_extend(vg->fid, vg, pv_count, pv_names))
|
||||
goto bad;
|
||||
|
||||
return vg;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
pool_free(mem, vg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct physical_volume *pv_create(struct format_instance *fi,
|
||||
struct physical_volume *pv_create(struct format_instance *fid,
|
||||
const char *name,
|
||||
struct id *id)
|
||||
struct id *id, uint64_t size)
|
||||
{
|
||||
struct pool *mem = fi->cmd->mem;
|
||||
struct physical_volume *pv = pool_alloc(mem, sizeof (*pv));
|
||||
struct pool *mem = fid->fmt->cmd->mem;
|
||||
struct physical_volume *pv = pool_alloc(mem, sizeof(*pv));
|
||||
|
||||
if (!pv) {
|
||||
stack;
|
||||
@@ -203,8 +215,8 @@ struct physical_volume *pv_create(struct format_instance *fi,
|
||||
else
|
||||
memcpy(&pv->id, id, sizeof(*id));
|
||||
|
||||
if (!(pv->dev = dev_cache_get(name, fi->cmd->filter))) {
|
||||
log_err("Couldn't find device '%s'", name);
|
||||
if (!(pv->dev = dev_cache_get(name, fid->fmt->cmd->filter))) {
|
||||
log_error("%s: Couldn't find device.", name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
@@ -217,14 +229,36 @@ struct physical_volume *pv_create(struct format_instance *fi,
|
||||
pv->status = ALLOCATABLE_PV;
|
||||
|
||||
if (!dev_get_size(pv->dev, &pv->size)) {
|
||||
log_err("Couldn't get size of device '%s'", name);
|
||||
log_error("%s: Couldn't get size.", name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (size) {
|
||||
if (size > pv->size)
|
||||
log_print("WARNING: %s: Overriding real size. "
|
||||
"You could lose data.", name);
|
||||
log_verbose("%s: Pretending size is %" PRIu64 " sectors.",
|
||||
name, size);
|
||||
pv->size = size;
|
||||
}
|
||||
|
||||
if (pv->size < PV_MIN_SIZE) {
|
||||
log_error("%s: Size must exceed minimum of %lu sectors.",
|
||||
name, PV_MIN_SIZE);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
pv->pe_size = 0;
|
||||
pv->pe_start = 0;
|
||||
pv->pe_count = 0;
|
||||
pv->pe_allocated = 0;
|
||||
pv->pe_alloc_count = 0;
|
||||
pv->fid = fid;
|
||||
|
||||
if (!fid->fmt->ops->pv_setup(fid, pv, NULL)) {
|
||||
log_error("%s: Format-specific setup of physical volume "
|
||||
"failed.", name);
|
||||
goto bad;
|
||||
}
|
||||
return pv;
|
||||
|
||||
bad:
|
||||
@@ -268,6 +302,20 @@ struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg, union lvid *lvid)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct lv_list *lvl;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lvl = list_item(lvh, struct lv_list);
|
||||
if (!strncmp(lvl->lv->lvid.s, lvid->s, sizeof(*lvid)))
|
||||
return lvl;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct logical_volume *find_lv(struct volume_group *vg, const char *lv_name)
|
||||
{
|
||||
struct lv_list *lvl = find_lv_in_vg(vg, lv_name);
|
||||
@@ -287,3 +335,244 @@ struct physical_volume *find_pv(struct volume_group *vg, struct device *dev)
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int vg_remove(struct volume_group *vg)
|
||||
{
|
||||
struct list *mdah;
|
||||
void *mdl;
|
||||
|
||||
if (!vg->fid->fmt->ops->vg_remove)
|
||||
return 1;
|
||||
|
||||
/* 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)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vg_write(struct volume_group *vg)
|
||||
{
|
||||
struct list *mdah;
|
||||
void *mdl;
|
||||
|
||||
if (vg->status & PARTIAL_VG) {
|
||||
log_error("Cannot change metadata for partial volume group %s",
|
||||
vg->name);
|
||||
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)) {
|
||||
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)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name)
|
||||
{
|
||||
struct format_instance *fid;
|
||||
struct format_type *fmt;
|
||||
struct volume_group *vg, *correct_vg;
|
||||
struct list *mdah, *names;
|
||||
void *mdl;
|
||||
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 (!(fid = fmt->ops->create_instance(fmt, vg_name, 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))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
if (first_time) {
|
||||
correct_vg = vg;
|
||||
first_time = 0;
|
||||
continue;
|
||||
}
|
||||
if (correct_vg->seqno != vg->seqno) {
|
||||
inconsistent = 1;
|
||||
if (vg->seqno > correct_vg->seqno)
|
||||
correct_vg = vg;
|
||||
}
|
||||
}
|
||||
|
||||
if (inconsistent) {
|
||||
log_print("Inconsistent metadata copies found - updating "
|
||||
"to use version %u", correct_vg->seqno);
|
||||
if (!vg_write(correct_vg)) {
|
||||
log_error("Automatic metadata correction failed");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
vgcache_add(vg_name, correct_vg->id.uuid, NULL, fmt);
|
||||
|
||||
return vg;
|
||||
}
|
||||
|
||||
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid)
|
||||
{
|
||||
char *vgname;
|
||||
struct list *vgs, *vgh;
|
||||
struct volume_group *vg;
|
||||
|
||||
if (!(vgs = get_vgs(cmd))) {
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct physical_volume *pv;
|
||||
|
||||
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))) {
|
||||
log_error("Failed to read existing physical volume '%s'",
|
||||
pv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pv->size)
|
||||
return NULL;
|
||||
else
|
||||
return pv;
|
||||
}
|
||||
|
||||
struct list *get_vgs(struct cmd_context *cmd)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
struct list *get_pvs(struct cmd_context *cmd)
|
||||
{
|
||||
struct list *results;
|
||||
|
||||
if (!(results = pool_alloc(cmd->mem, sizeof(*results)))) {
|
||||
log_error("PV list allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
int pv_write(struct cmd_context *cmd, struct physical_volume *pv)
|
||||
{
|
||||
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->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;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#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 */
|
||||
|
||||
|
||||
/* Various flags */
|
||||
@@ -36,6 +38,7 @@
|
||||
|
||||
#define SPINDOWN_LV 0x00000010 /* LV */
|
||||
#define BADBLOCK_ON 0x00000020 /* LV */
|
||||
#define FIXED_MINOR 0x00000080 /* LV */
|
||||
|
||||
/* FIXME: do we really set read/write for a whole vg ? */
|
||||
#define LVM_READ 0x00000100 /* LV VG */
|
||||
@@ -49,13 +52,15 @@
|
||||
#define ALLOC_STRICT 0x00002000 /* LV */
|
||||
#define ALLOC_CONTIGUOUS 0x00004000 /* LV */
|
||||
|
||||
#define SNAPSHOT 0x00010000 /* LV */
|
||||
#define SNAPSHOT_ORG 0x00020000 /* LV */
|
||||
#define FMT_SEGMENTS 0x00000001 /* Arbitrary segment parameters? */
|
||||
|
||||
#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;
|
||||
@@ -65,13 +70,33 @@ struct physical_volume {
|
||||
uint64_t pe_size;
|
||||
uint64_t pe_start;
|
||||
uint32_t pe_count;
|
||||
uint32_t pe_allocated; /* FIXME: change the name to alloc_count ? */
|
||||
uint32_t pe_alloc_count;
|
||||
};
|
||||
|
||||
struct cmd_context;
|
||||
|
||||
struct format_type {
|
||||
struct cmd_context *cmd;
|
||||
struct format_handler *ops;
|
||||
const char *name;
|
||||
uint32_t features;
|
||||
void *private;
|
||||
};
|
||||
|
||||
struct metadata_area {
|
||||
struct list list;
|
||||
void *metadata_locn;
|
||||
};
|
||||
|
||||
struct format_instance {
|
||||
struct format_type *fmt;
|
||||
struct list metadata_areas; /* e.g. metadata locations */
|
||||
};
|
||||
|
||||
struct volume_group {
|
||||
struct cmd_context *cmd;
|
||||
struct format_instance *fid;
|
||||
uint32_t seqno; /* Metadata sequence number */
|
||||
|
||||
struct id id;
|
||||
char *name;
|
||||
@@ -93,6 +118,10 @@ struct volume_group {
|
||||
/* logical volumes */
|
||||
uint32_t lv_count;
|
||||
struct list lvs;
|
||||
|
||||
/* snapshots */
|
||||
uint32_t snapshot_count;
|
||||
struct list snapshots;
|
||||
};
|
||||
|
||||
struct stripe_segment {
|
||||
@@ -112,13 +141,14 @@ struct stripe_segment {
|
||||
};
|
||||
|
||||
struct logical_volume {
|
||||
struct id id;
|
||||
union lvid lvid;
|
||||
char *name;
|
||||
|
||||
struct volume_group *vg;
|
||||
|
||||
uint32_t status;
|
||||
uint32_t read_ahead;
|
||||
int32_t minor;
|
||||
|
||||
uint64_t size;
|
||||
uint32_t le_count;
|
||||
@@ -126,6 +156,14 @@ struct logical_volume {
|
||||
struct list segments;
|
||||
};
|
||||
|
||||
struct snapshot {
|
||||
int persistent; /* boolean */
|
||||
uint32_t chunk_size; /* in 512 byte sectors */
|
||||
|
||||
struct logical_volume *origin;
|
||||
struct logical_volume *cow;
|
||||
};
|
||||
|
||||
struct name_list {
|
||||
struct list list;
|
||||
char *name;
|
||||
@@ -141,21 +179,12 @@ struct lv_list {
|
||||
struct logical_volume *lv;
|
||||
};
|
||||
|
||||
struct cmd_context {
|
||||
/* format handler allocates all objects from here */
|
||||
struct pool *mem;
|
||||
struct snapshot_list {
|
||||
struct list list;
|
||||
|
||||
/* misc. vars needed by format handler */
|
||||
char *dev_dir;
|
||||
struct dev_filter *filter;
|
||||
struct config_file *cf;
|
||||
struct snapshot *snapshot;
|
||||
};
|
||||
|
||||
struct format_instance {
|
||||
struct cmd_context *cmd;
|
||||
struct format_handler *ops;
|
||||
void *private;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
@@ -165,18 +194,19 @@ struct format_handler {
|
||||
/*
|
||||
* Returns a name_list of vg's.
|
||||
*/
|
||||
struct list *(*get_vgs)(struct format_instance *fi);
|
||||
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_instance *fi);
|
||||
struct list *(*get_pvs)(struct format_type *fmt, struct list *results);
|
||||
|
||||
/*
|
||||
* Return PV with given path.
|
||||
*/
|
||||
struct physical_volume *(*pv_read)(struct format_instance *fi,
|
||||
const char *pv_name);
|
||||
int (*pv_read)(struct format_type *fmt,
|
||||
const char *pv_name,
|
||||
struct physical_volume *pv);
|
||||
|
||||
/*
|
||||
* Tweak an already filled out a pv ready for importing into a
|
||||
@@ -189,8 +219,10 @@ struct format_handler {
|
||||
* 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);
|
||||
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);
|
||||
|
||||
/*
|
||||
* Tweak an already filled out a lv eg, check there
|
||||
@@ -203,13 +235,16 @@ struct format_handler {
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
const char *vg_name, void *mdl);
|
||||
|
||||
/*
|
||||
* Write out complete VG metadata. You must ensure internal
|
||||
@@ -225,24 +260,50 @@ struct format_handler {
|
||||
* in the volume_group structure it is handed. Note: format1
|
||||
* does read all pv's currently.
|
||||
*/
|
||||
int (*vg_write)(struct format_instance *fi, struct volume_group *vg);
|
||||
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);
|
||||
|
||||
/*
|
||||
* Destructor for this object.
|
||||
* Destructor for format instance
|
||||
*/
|
||||
void (*destroy)(struct format_instance *fi);
|
||||
void (*destroy_instance)(struct format_instance *fid);
|
||||
|
||||
/*
|
||||
* Destructor for format type
|
||||
*/
|
||||
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_by_vgid(struct cmd_context *cmd, const char *vgid);
|
||||
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name);
|
||||
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);
|
||||
|
||||
|
||||
struct physical_volume *pv_create(struct format_instance *fi,
|
||||
const char *name,
|
||||
struct id *id);
|
||||
struct id *id,
|
||||
uint64_t size);
|
||||
|
||||
struct volume_group *vg_create(struct format_instance *fi, const char *name,
|
||||
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
|
||||
@@ -265,7 +326,7 @@ struct logical_volume *lv_create(struct format_instance *fi,
|
||||
struct volume_group *vg,
|
||||
struct list *acceptable_pvs);
|
||||
|
||||
int lv_reduce(struct format_instance *fi,
|
||||
int lv_reduce(struct format_instance *fi,
|
||||
struct logical_volume *lv, uint32_t extents);
|
||||
|
||||
int lv_extend(struct format_instance *fi,
|
||||
@@ -294,6 +355,8 @@ struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name);
|
||||
|
||||
/* 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,
|
||||
union lvid *lvid);
|
||||
|
||||
/* Return the VG that contains a given LV (based on path given in lv_name) */
|
||||
/* or environment var */
|
||||
@@ -323,4 +386,21 @@ int lv_check_segments(struct logical_volume *lv);
|
||||
int lv_merge_segments(struct logical_volume *lv);
|
||||
|
||||
|
||||
/*
|
||||
* Useful functions for managing snapshots.
|
||||
*/
|
||||
int lv_is_origin(struct logical_volume *lv);
|
||||
int lv_is_cow(struct logical_volume *lv);
|
||||
|
||||
struct snapshot *find_cow(struct logical_volume *lv);
|
||||
struct snapshot *find_origin(struct logical_volume *lv);
|
||||
|
||||
int vg_add_snapshot(struct logical_volume *origin,
|
||||
struct logical_volume *cow,
|
||||
int persistent,
|
||||
uint32_t chunk_size);
|
||||
|
||||
int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -82,7 +82,7 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps)
|
||||
}
|
||||
|
||||
/* populate the hash table */
|
||||
list_iterate (pvmh, maps) {
|
||||
list_iterate(pvmh, maps) {
|
||||
pvm = list_item(pvmh, struct pv_map);
|
||||
if (!hash_insert(hash, dev_name(pvm->pv->dev), pvm)) {
|
||||
stack;
|
||||
@@ -91,18 +91,18 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps)
|
||||
}
|
||||
|
||||
/* iterate through all the lv's setting bit's for used pe's */
|
||||
list_iterate (lvh, &vg->lvs) {
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
|
||||
list_iterate (segh, &lv->segments) {
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct stripe_segment);
|
||||
|
||||
for (s = 0; s < seg->stripes; s++) {
|
||||
for (pe = 0; pe < (seg->len / seg->stripes);
|
||||
pe++) {
|
||||
if (!_set_allocated(hash,
|
||||
seg->area[s].pv,
|
||||
seg->area[s].pe
|
||||
seg->area[s].pv,
|
||||
seg->area[s].pe
|
||||
+ pe)) {
|
||||
stack;
|
||||
goto out;
|
||||
@@ -113,7 +113,7 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps)
|
||||
}
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
out:
|
||||
hash_destroy(hash);
|
||||
return r;
|
||||
}
|
||||
@@ -131,7 +131,7 @@ static void _insert_area(struct list *head, struct pv_area *a)
|
||||
return;
|
||||
}
|
||||
|
||||
list_iterate (pvah, head) {
|
||||
list_iterate(pvah, head) {
|
||||
pva = list_item(pvah, struct pv_area);
|
||||
|
||||
if (pva->count < a->count)
|
||||
@@ -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;
|
||||
|
||||
122
lib/metadata/snapshot_manip.c
Normal file
122
lib/metadata/snapshot_manip.c
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "log.h"
|
||||
#include "metadata.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
int lv_is_origin(struct logical_volume *lv)
|
||||
{
|
||||
struct list *slh;
|
||||
struct snapshot *s;
|
||||
|
||||
list_iterate(slh, &lv->vg->snapshots) {
|
||||
s = list_item(slh, struct snapshot_list)->snapshot;
|
||||
if (s->origin == lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lv_is_cow(struct logical_volume *lv)
|
||||
{
|
||||
struct list *slh;
|
||||
struct snapshot *s;
|
||||
|
||||
list_iterate(slh, &lv->vg->snapshots) {
|
||||
s = list_item(slh, struct snapshot_list)->snapshot;
|
||||
if (s->cow == lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snapshot *find_origin(struct logical_volume *lv)
|
||||
{
|
||||
struct list *slh;
|
||||
struct snapshot *s;
|
||||
|
||||
list_iterate(slh, &lv->vg->snapshots) {
|
||||
s = list_item(slh, struct snapshot_list)->snapshot;
|
||||
if (s->origin == lv)
|
||||
return s;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct snapshot *find_cow(struct logical_volume *lv)
|
||||
{
|
||||
struct list *slh;
|
||||
struct snapshot *s;
|
||||
|
||||
list_iterate(slh, &lv->vg->snapshots) {
|
||||
s = list_item(slh, struct snapshot_list)->snapshot;
|
||||
if (s->cow == lv)
|
||||
return s;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int vg_add_snapshot(struct logical_volume *origin,
|
||||
struct logical_volume *cow,
|
||||
int persistent, uint32_t chunk_size)
|
||||
{
|
||||
struct snapshot *s;
|
||||
struct snapshot_list *sl;
|
||||
struct pool *mem = origin->vg->cmd->mem;
|
||||
|
||||
/*
|
||||
* Is the cow device already being used ?
|
||||
*/
|
||||
if (lv_is_cow(cow)) {
|
||||
log_err("'%s' is already in use as a snapshot.", cow->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(s = pool_alloc(mem, sizeof(*s)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s->persistent = persistent;
|
||||
s->chunk_size = chunk_size;
|
||||
s->origin = origin;
|
||||
s->cow = cow;
|
||||
|
||||
if (!(sl = pool_alloc(mem, sizeof(*sl)))) {
|
||||
stack;
|
||||
pool_free(mem, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sl->snapshot = s;
|
||||
list_add(&origin->vg->snapshots, &sl->list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow)
|
||||
{
|
||||
struct list *slh;
|
||||
struct snapshot_list *sl;
|
||||
|
||||
list_iterate(slh, &vg->snapshots) {
|
||||
sl = list_item(slh, struct snapshot_list);
|
||||
|
||||
if (sl->snapshot->cow == cow) {
|
||||
list_del(slh);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* fail */
|
||||
log_err("Asked to remove an unknown snapshot.");
|
||||
return 0;
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
|
||||
/*
|
||||
* Creates a temporary filename, and opens a descriptor to the
|
||||
@@ -21,17 +22,16 @@
|
||||
* rename the file after successfully writing it. Grab
|
||||
* NFS-supported exclusive fcntl discretionary lock.
|
||||
*/
|
||||
int create_temp_name(const char *dir, char *buffer, size_t len,
|
||||
int *fd)
|
||||
int create_temp_name(const char *dir, char *buffer, size_t len, int *fd)
|
||||
{
|
||||
int i, num;
|
||||
pid_t pid;
|
||||
char hostname[255];
|
||||
struct flock lock = {
|
||||
l_type: F_WRLCK,
|
||||
l_whence: 0,
|
||||
l_start: 0,
|
||||
l_len: 0
|
||||
l_type:F_WRLCK,
|
||||
l_whence:0,
|
||||
l_start:0,
|
||||
l_len:0
|
||||
};
|
||||
|
||||
num = rand();
|
||||
@@ -99,3 +99,75 @@ int lvm_rename(const char *old, const char *new)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int path_exists(const char *path)
|
||||
{
|
||||
struct stat info;
|
||||
|
||||
if (!*path)
|
||||
return 0;
|
||||
|
||||
if (stat(path, &info) < 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dir_exists(const char *path)
|
||||
{
|
||||
struct stat info;
|
||||
|
||||
if (!*path)
|
||||
return 0;
|
||||
|
||||
if (stat(path, &info) < 0)
|
||||
return 0;
|
||||
|
||||
if (!S_ISDIR(info.st_mode))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME: Make this create directories recursively */
|
||||
int create_dir(const char *dir)
|
||||
{
|
||||
struct stat info;
|
||||
|
||||
if (!*dir)
|
||||
return 1;
|
||||
|
||||
if (stat(dir, &info) < 0) {
|
||||
log_verbose("Creating directory \"%s\"", dir);
|
||||
if (!mkdir(dir, 0777))
|
||||
return 1;
|
||||
log_sys_error("mkdir", dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (S_ISDIR(info.st_mode))
|
||||
return 1;
|
||||
|
||||
log_error("Directory \"%s\" not found", dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int is_empty_dir(const char *dir)
|
||||
{
|
||||
struct dirent *dirent;
|
||||
DIR *d;
|
||||
|
||||
if (!(d = opendir(dir))) {
|
||||
log_sys_error("opendir", dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((dirent = readdir(d)))
|
||||
if (strcmp(dirent->d_name, ".") && strcmp(dirent->d_name, ".."))
|
||||
break;
|
||||
|
||||
if (closedir(d)) {
|
||||
log_sys_error("closedir", dir);
|
||||
}
|
||||
|
||||
return dirent ? 0 : 1;
|
||||
}
|
||||
|
||||
@@ -16,3 +16,19 @@ int create_temp_name(const char *dir, char *buffer, size_t len, int *fd);
|
||||
*/
|
||||
int lvm_rename(const char *old, const char *new);
|
||||
|
||||
/*
|
||||
* Return 1 if path exists else return 0
|
||||
*/
|
||||
int path_exists(const char *path);
|
||||
int dir_exists(const char *path);
|
||||
|
||||
/*
|
||||
* Return 1 if dir is empty
|
||||
*/
|
||||
int is_empty_dir(const char *dir);
|
||||
|
||||
/*
|
||||
* Create directory (but not recursively) if necessary
|
||||
* Return 1 if directory exists on return, else 0
|
||||
*/
|
||||
int create_dir(const char *dir);
|
||||
|
||||
@@ -14,19 +14,20 @@
|
||||
#include "log.h"
|
||||
|
||||
struct memblock {
|
||||
struct memblock *prev, *next; /* All allocated blocks are linked */
|
||||
size_t length; /* Size of the requested block */
|
||||
int id; /* Index of the block */
|
||||
const char *file; /* File that allocated */
|
||||
int line; /* Line that allocated */
|
||||
void *magic; /* Address of this block */
|
||||
struct memblock *prev, *next; /* All allocated blocks are linked */
|
||||
size_t length; /* Size of the requested block */
|
||||
int id; /* Index of the block */
|
||||
const char *file; /* File that allocated */
|
||||
int line; /* Line that allocated */
|
||||
void *magic; /* Address of this block */
|
||||
};
|
||||
|
||||
static struct {
|
||||
unsigned int blocks, mblocks;
|
||||
unsigned int bytes, mbytes;
|
||||
|
||||
} _mem_stats = {0, 0, 0, 0};
|
||||
} _mem_stats = {
|
||||
0, 0, 0, 0};
|
||||
|
||||
static struct memblock *_head = 0;
|
||||
static struct memblock *_tail = 0;
|
||||
@@ -104,7 +105,7 @@ void free_aux(void *p)
|
||||
/* check data at the far boundary */
|
||||
ptr = ((char *) mb) + sizeof(struct memblock) + mb->length;
|
||||
for (i = 0; i < sizeof(unsigned long); i++)
|
||||
if(*ptr++ != (char) mb->id)
|
||||
if (*ptr++ != (char) mb->id)
|
||||
assert(!"Damage at far end of block");
|
||||
|
||||
/* have we freed this before ? */
|
||||
@@ -159,7 +160,7 @@ int dump_memory(void)
|
||||
log_very_verbose("You have a memory leak:");
|
||||
|
||||
for (mb = _head; mb; mb = mb->next) {
|
||||
print_log(_LOG_INFO, mb->file, mb->line,
|
||||
print_log(_LOG_INFO, mb->file, mb->line,
|
||||
"block %d at %p, size %" PRIdPTR,
|
||||
mb->id, mb->magic, mb->length);
|
||||
tot += mb->length;
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
* Copyright (C) 2001-2002 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "pool.h"
|
||||
#include "dbg_malloc.h"
|
||||
@@ -17,11 +18,11 @@ struct chunk {
|
||||
};
|
||||
|
||||
struct pool {
|
||||
struct chunk *chunk, *spare_chunk; /* spare_chunk is a one entry free
|
||||
list to stop 'bobbling' */
|
||||
struct chunk *chunk, *spare_chunk; /* spare_chunk is a one entry free
|
||||
list to stop 'bobbling' */
|
||||
size_t chunk_size;
|
||||
size_t object_len;
|
||||
unsigned object_alignment;
|
||||
unsigned object_alignment;
|
||||
};
|
||||
|
||||
void _align_chunk(struct chunk *c, unsigned alignment);
|
||||
@@ -36,7 +37,7 @@ struct pool *pool_create(size_t chunk_hint)
|
||||
struct pool *p = dbg_malloc(sizeof(*p));
|
||||
|
||||
if (!p) {
|
||||
log_error("Couldn't create memory pool (size %u)",
|
||||
log_error("Couldn't create memory pool (size %" PRIuPTR ")",
|
||||
sizeof(*p));
|
||||
return 0;
|
||||
}
|
||||
@@ -74,12 +75,12 @@ void *pool_alloc_aligned(struct pool *p, size_t s, unsigned alignment)
|
||||
struct chunk *c = p->chunk;
|
||||
void *r;
|
||||
|
||||
/* realign begin */
|
||||
/* realign begin */
|
||||
if (c)
|
||||
_align_chunk(c, alignment);
|
||||
|
||||
/* have we got room ? */
|
||||
if(!c || (c->begin > c->end) || (c->end - c->begin < s)) {
|
||||
if (!c || (c->begin > c->end) || (c->end - c->begin < s)) {
|
||||
/* allocate new chunk */
|
||||
int needed = s + alignment + sizeof(struct chunk);
|
||||
c = _new_chunk(p, (needed > p->chunk_size) ?
|
||||
@@ -224,7 +225,8 @@ struct chunk *_new_chunk(struct pool *p, size_t s)
|
||||
p->spare_chunk = 0;
|
||||
} else {
|
||||
if (!(c = dbg_malloc(s))) {
|
||||
log_err("Out of memory. Requested %u bytes.", s);
|
||||
log_err("Out of memory. Requested %" PRIuPTR " bytes.",
|
||||
s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -237,4 +239,3 @@ struct chunk *_new_chunk(struct pool *p, size_t s)
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ struct state_queue {
|
||||
struct state_queue *next;
|
||||
};
|
||||
|
||||
struct matcher { /* Instance variables for the lexer */
|
||||
struct matcher { /* Instance variables for the lexer */
|
||||
struct dfa_state *start;
|
||||
int num_nodes, nodes_entered;
|
||||
struct rx_node **nodes;
|
||||
@@ -38,10 +38,10 @@ static int _count_nodes(struct rx_node *rx)
|
||||
{
|
||||
int r = 1;
|
||||
|
||||
if(rx->left)
|
||||
if (rx->left)
|
||||
r += _count_nodes(rx->left);
|
||||
|
||||
if(rx->right)
|
||||
if (rx->right)
|
||||
r += _count_nodes(rx->right);
|
||||
|
||||
return r;
|
||||
@@ -51,10 +51,10 @@ static void _fill_table(struct matcher *m, struct rx_node *rx)
|
||||
{
|
||||
assert((rx->type != OR) || (rx->left && rx->right));
|
||||
|
||||
if(rx->left)
|
||||
if (rx->left)
|
||||
_fill_table(m, rx->left);
|
||||
|
||||
if(rx->right)
|
||||
if (rx->right)
|
||||
_fill_table(m, rx->right);
|
||||
|
||||
m->nodes[m->nodes_entered++] = rx;
|
||||
@@ -64,7 +64,7 @@ static void _create_bitsets(struct matcher *m)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < m->num_nodes; i++) {
|
||||
for (i = 0; i < m->num_nodes; i++) {
|
||||
struct rx_node *n = m->nodes[i];
|
||||
n->firstpos = bitset_create(m->scratch, m->num_nodes);
|
||||
n->lastpos = bitset_create(m->scratch, m->num_nodes);
|
||||
@@ -77,23 +77,23 @@ static void _calc_functions(struct matcher *m)
|
||||
int i, j, final = 1;
|
||||
struct rx_node *rx, *c1, *c2;
|
||||
|
||||
for(i = 0; i < m->num_nodes; i++) {
|
||||
for (i = 0; i < m->num_nodes; i++) {
|
||||
rx = m->nodes[i];
|
||||
c1 = rx->left;
|
||||
c2 = rx->right;
|
||||
|
||||
if(bit(rx->charset, TARGET_TRANS))
|
||||
if (bit(rx->charset, TARGET_TRANS))
|
||||
rx->final = final++;
|
||||
|
||||
switch(rx->type) {
|
||||
switch (rx->type) {
|
||||
case CAT:
|
||||
if(c1->nullable)
|
||||
if (c1->nullable)
|
||||
bit_union(rx->firstpos,
|
||||
c1->firstpos, c2->firstpos);
|
||||
else
|
||||
bit_copy(rx->firstpos, c1->firstpos);
|
||||
|
||||
if(c2->nullable)
|
||||
if (c2->nullable)
|
||||
bit_union(rx->lastpos,
|
||||
c1->lastpos, c2->lastpos);
|
||||
else
|
||||
@@ -136,10 +136,10 @@ static void _calc_functions(struct matcher *m)
|
||||
* because PLUS and STAR do the
|
||||
* same thing.
|
||||
*/
|
||||
switch(rx->type) {
|
||||
switch (rx->type) {
|
||||
case CAT:
|
||||
for(j = 0; j < m->num_nodes; j++) {
|
||||
if(bit(c1->lastpos, j)) {
|
||||
for (j = 0; j < m->num_nodes; j++) {
|
||||
if (bit(c1->lastpos, j)) {
|
||||
struct rx_node *n = m->nodes[j];
|
||||
bit_union(n->followpos,
|
||||
n->followpos, c2->firstpos);
|
||||
@@ -149,8 +149,8 @@ static void _calc_functions(struct matcher *m)
|
||||
|
||||
case PLUS:
|
||||
case STAR:
|
||||
for(j = 0; j < m->num_nodes; j++) {
|
||||
if(bit(rx->lastpos, j)) {
|
||||
for (j = 0; j < m->num_nodes; j++) {
|
||||
if (bit(rx->lastpos, j)) {
|
||||
struct rx_node *n = m->nodes[j];
|
||||
bit_union(n->followpos,
|
||||
n->followpos, rx->firstpos);
|
||||
@@ -178,7 +178,7 @@ static struct state_queue *_create_state_queue(struct pool *mem,
|
||||
}
|
||||
|
||||
r->s = dfa;
|
||||
r->bits = bitset_create(mem, bits[0]); /* first element is the size */
|
||||
r->bits = bitset_create(mem, bits[0]); /* first element is the size */
|
||||
bit_copy(r->bits, bits);
|
||||
r->next = 0;
|
||||
return r;
|
||||
@@ -218,28 +218,30 @@ static int _calc_states(struct matcher *m, struct rx_node *rx)
|
||||
|
||||
/* iterate through all the inputs for this state */
|
||||
bit_clear_all(bs);
|
||||
for(a = 0; a < 256; a++) {
|
||||
for (a = 0; a < 256; a++) {
|
||||
/* iterate through all the states in firstpos */
|
||||
for(i = bit_get_first(dfa_bits);
|
||||
i >=0;
|
||||
i = bit_get_next(dfa_bits, i)) {
|
||||
if(bit(m->nodes[i]->charset, a)) {
|
||||
if(a == TARGET_TRANS)
|
||||
for (i = bit_get_first(dfa_bits);
|
||||
i >= 0; i = bit_get_next(dfa_bits, i)) {
|
||||
if (bit(m->nodes[i]->charset, a)) {
|
||||
if (a == TARGET_TRANS)
|
||||
dfa->final = m->nodes[i]->final;
|
||||
|
||||
bit_union(bs, bs, m->nodes[i]->followpos);
|
||||
bit_union(bs, bs,
|
||||
m->nodes[i]->followpos);
|
||||
set_bits = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(set_bits) {
|
||||
if (set_bits) {
|
||||
ldfa = ttree_lookup(tt, bs + 1);
|
||||
if(!ldfa) {
|
||||
if (!ldfa) {
|
||||
/* push */
|
||||
ldfa = _create_dfa_state(m->mem);
|
||||
ttree_insert(tt, bs + 1, ldfa);
|
||||
tmp = _create_state_queue(m->scratch, ldfa, bs);
|
||||
if(!h)
|
||||
tmp =
|
||||
_create_state_queue(m->scratch,
|
||||
ldfa, bs);
|
||||
if (!h)
|
||||
h = t = tmp;
|
||||
else {
|
||||
t->next = tmp;
|
||||
@@ -260,8 +262,7 @@ static int _calc_states(struct matcher *m, struct rx_node *rx)
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct matcher *matcher_create(struct pool *mem,
|
||||
const char **patterns, int num)
|
||||
struct matcher *matcher_create(struct pool *mem, const char **patterns, int num)
|
||||
{
|
||||
char *all, *ptr;
|
||||
int i, len = 0;
|
||||
@@ -282,7 +283,7 @@ struct matcher *matcher_create(struct pool *mem,
|
||||
memset(m, 0, sizeof(*m));
|
||||
|
||||
/* join the regexps together, delimiting with zero */
|
||||
for(i = 0; i < num; i++)
|
||||
for (i = 0; i < num; i++)
|
||||
len += strlen(patterns[i]) + 8;
|
||||
|
||||
ptr = all = pool_alloc(scratch, len + 1);
|
||||
@@ -292,15 +293,14 @@ struct matcher *matcher_create(struct pool *mem,
|
||||
goto bad;
|
||||
}
|
||||
|
||||
for(i = 0; i < num; i++) {
|
||||
ptr += sprintf(ptr, "(.*(%s)%c)", patterns[i],
|
||||
TARGET_TRANS);
|
||||
if(i < (num - 1))
|
||||
for (i = 0; i < num; i++) {
|
||||
ptr += sprintf(ptr, "(.*(%s)%c)", patterns[i], TARGET_TRANS);
|
||||
if (i < (num - 1))
|
||||
*ptr++ = '|';
|
||||
}
|
||||
|
||||
/* parse this expression */
|
||||
if(!(rx = rx_parse_tok(scratch, all, ptr))) {
|
||||
if (!(rx = rx_parse_tok(scratch, all, ptr))) {
|
||||
log_error("Couldn't parse regex");
|
||||
goto bad;
|
||||
}
|
||||
@@ -324,7 +324,7 @@ struct matcher *matcher_create(struct pool *mem,
|
||||
|
||||
return m;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
pool_destroy(scratch);
|
||||
pool_destroy(mem);
|
||||
return NULL;
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
struct parse_sp { /* scratch pad for the parsing process */
|
||||
struct pool *mem;
|
||||
int type; /* token type, 0 indicates a charset */
|
||||
@@ -21,10 +20,8 @@ struct parse_sp { /* scratch pad for the parsing process */
|
||||
const char *rx_end; /* 1pte for the expression being parsed */
|
||||
};
|
||||
|
||||
|
||||
static struct rx_node *_or_term(struct parse_sp *ps);
|
||||
|
||||
|
||||
/*
|
||||
* Get the next token from the regular expression.
|
||||
* Returns: 1 success, 0 end of input, -1 error.
|
||||
@@ -34,16 +31,16 @@ static int _get_token(struct parse_sp *ps)
|
||||
int neg = 0, range = 0;
|
||||
char c, lc = 0;
|
||||
const char *ptr = ps->cursor;
|
||||
if(ptr == ps->rx_end) { /* end of input ? */
|
||||
if (ptr == ps->rx_end) { /* end of input ? */
|
||||
ps->type = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch(*ptr) {
|
||||
/* charsets and ncharsets */
|
||||
switch (*ptr) {
|
||||
/* charsets and ncharsets */
|
||||
case '[':
|
||||
ptr++;
|
||||
if(*ptr == '^') {
|
||||
if (*ptr == '^') {
|
||||
bit_set_all(ps->charset);
|
||||
|
||||
/* never transition on zero */
|
||||
@@ -54,40 +51,46 @@ static int _get_token(struct parse_sp *ps)
|
||||
} else
|
||||
bit_clear_all(ps->charset);
|
||||
|
||||
while((ptr < ps->rx_end) && (*ptr != ']')) {
|
||||
if(*ptr == '\\') {
|
||||
while ((ptr < ps->rx_end) && (*ptr != ']')) {
|
||||
if (*ptr == '\\') {
|
||||
/* an escaped character */
|
||||
ptr++;
|
||||
switch(*ptr) {
|
||||
case 'n': c = '\n'; break;
|
||||
case 'r': c = '\r'; break;
|
||||
case 't': c = '\t'; break;
|
||||
switch (*ptr) {
|
||||
case 'n':
|
||||
c = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
c = '\r';
|
||||
break;
|
||||
case 't':
|
||||
c = '\t';
|
||||
break;
|
||||
default:
|
||||
c = *ptr;
|
||||
}
|
||||
} else if(*ptr == '-' && lc) {
|
||||
} else if (*ptr == '-' && lc) {
|
||||
/* we've got a range on our hands */
|
||||
range = 1;
|
||||
ptr++;
|
||||
if(ptr == ps->rx_end) {
|
||||
if (ptr == ps->rx_end) {
|
||||
log_error("Incomplete range"
|
||||
"specification");
|
||||
"specification");
|
||||
return -1;
|
||||
}
|
||||
c = *ptr;
|
||||
} else
|
||||
c = *ptr;
|
||||
|
||||
if(range) {
|
||||
if (range) {
|
||||
/* add lc - c into the bitset */
|
||||
if(lc > c) {
|
||||
if (lc > c) {
|
||||
char tmp = c;
|
||||
c = lc;
|
||||
lc = tmp;
|
||||
}
|
||||
|
||||
for(; lc <= c; lc++) {
|
||||
if(neg)
|
||||
for (; lc <= c; lc++) {
|
||||
if (neg)
|
||||
bit_clear(ps->charset, lc);
|
||||
else
|
||||
bit_set(ps->charset, lc);
|
||||
@@ -95,7 +98,7 @@ static int _get_token(struct parse_sp *ps)
|
||||
range = 0;
|
||||
} else {
|
||||
/* add c into the bitset */
|
||||
if(neg)
|
||||
if (neg)
|
||||
bit_clear(ps->charset, c);
|
||||
else
|
||||
bit_set(ps->charset, c);
|
||||
@@ -104,7 +107,7 @@ static int _get_token(struct parse_sp *ps)
|
||||
lc = c;
|
||||
}
|
||||
|
||||
if(ptr >= ps->rx_end) {
|
||||
if (ptr >= ps->rx_end) {
|
||||
ps->type = -1;
|
||||
return -1;
|
||||
}
|
||||
@@ -141,7 +144,7 @@ static int _get_token(struct parse_sp *ps)
|
||||
case '\\':
|
||||
/* escaped character */
|
||||
ptr++;
|
||||
if(ptr >= ps->rx_end) {
|
||||
if (ptr >= ps->rx_end) {
|
||||
log_error("Badly quoted character at end "
|
||||
"of expression");
|
||||
ps->type = -1;
|
||||
@@ -151,10 +154,16 @@ static int _get_token(struct parse_sp *ps)
|
||||
ps->type = 0;
|
||||
ps->cursor = ptr + 1;
|
||||
bit_clear_all(ps->charset);
|
||||
switch(*ptr) {
|
||||
case 'n': bit_set(ps->charset, (int) '\n'); break;
|
||||
case 'r': bit_set(ps->charset, (int) '\r'); break;
|
||||
case 't': bit_set(ps->charset, (int) '\t'); break;
|
||||
switch (*ptr) {
|
||||
case 'n':
|
||||
bit_set(ps->charset, (int) '\n');
|
||||
break;
|
||||
case 'r':
|
||||
bit_set(ps->charset, (int) '\r');
|
||||
break;
|
||||
case 't':
|
||||
bit_set(ps->charset, (int) '\t');
|
||||
break;
|
||||
default:
|
||||
bit_set(ps->charset, (int) *ptr);
|
||||
}
|
||||
@@ -195,7 +204,7 @@ static struct rx_node *_term(struct parse_sp *ps)
|
||||
{
|
||||
struct rx_node *n;
|
||||
|
||||
switch(ps->type) {
|
||||
switch (ps->type) {
|
||||
case 0:
|
||||
if (!(n = _node(ps->mem, CHARSET, NULL, NULL))) {
|
||||
stack;
|
||||
@@ -203,17 +212,17 @@ static struct rx_node *_term(struct parse_sp *ps)
|
||||
}
|
||||
|
||||
bit_copy(n->charset, ps->charset);
|
||||
_get_token(ps); /* match charset */
|
||||
_get_token(ps); /* match charset */
|
||||
break;
|
||||
|
||||
case '(':
|
||||
_get_token(ps); /* match '(' */
|
||||
_get_token(ps); /* match '(' */
|
||||
n = _or_term(ps);
|
||||
if(ps->type != ')') {
|
||||
if (ps->type != ')') {
|
||||
log_error("missing ')' in regular expression");
|
||||
return 0;
|
||||
}
|
||||
_get_token(ps); /* match ')' */
|
||||
_get_token(ps); /* match ')' */
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -227,11 +236,11 @@ static struct rx_node *_closure_term(struct parse_sp *ps)
|
||||
{
|
||||
struct rx_node *l, *n;
|
||||
|
||||
if(!(l = _term(ps)))
|
||||
if (!(l = _term(ps)))
|
||||
return NULL;
|
||||
|
||||
for (;;) {
|
||||
switch(ps->type) {
|
||||
switch (ps->type) {
|
||||
case '*':
|
||||
n = _node(ps->mem, STAR, l, NULL);
|
||||
break;
|
||||
@@ -289,7 +298,7 @@ static struct rx_node *_or_term(struct parse_sp *ps)
|
||||
if (ps->type != '|')
|
||||
return l;
|
||||
|
||||
_get_token(ps); /* match '|' */
|
||||
_get_token(ps); /* match '|' */
|
||||
|
||||
if (!(r = _or_term(ps))) {
|
||||
log_error("Badly formed 'or' expression");
|
||||
@@ -317,7 +326,7 @@ struct rx_node *rx_parse_tok(struct pool *mem,
|
||||
ps->charset = bitset_create(mem, 256);
|
||||
ps->cursor = begin;
|
||||
ps->rx_end = end;
|
||||
_get_token(ps); /* load the first token */
|
||||
_get_token(ps); /* load the first token */
|
||||
|
||||
if (!(r = _or_term(ps))) {
|
||||
log_error("Parse error in regex");
|
||||
|
||||
@@ -74,7 +74,6 @@ int ttree_insert(struct ttree *tt, unsigned int *key, void *data)
|
||||
|
||||
} while (*c && count);
|
||||
|
||||
|
||||
if (!*c) {
|
||||
count++;
|
||||
|
||||
|
||||
@@ -19,6 +19,44 @@ static unsigned char _c[] =
|
||||
static int _built_inverse;
|
||||
static unsigned char _inverse_c[256];
|
||||
|
||||
int lvid_create(union lvid *lvid, struct id *vgid)
|
||||
{
|
||||
memcpy(lvid->id, vgid, sizeof(*lvid->id));
|
||||
id_create(&lvid->id[1]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lvid_from_lvnum(union lvid *lvid, struct id *vgid, int lv_num)
|
||||
{
|
||||
int i;
|
||||
|
||||
memcpy(lvid->id, vgid, sizeof(*lvid->id));
|
||||
|
||||
for (i = ID_LEN; i; i--) {
|
||||
lvid->id[1].uuid[i - 1] = _c[lv_num % (sizeof(_c) - 1)];
|
||||
lv_num /= sizeof(_c) - 1;
|
||||
}
|
||||
|
||||
lvid->s[sizeof(lvid->s) - 1] = '\0';
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lvnum_from_lvid(union lvid *lvid)
|
||||
{
|
||||
int i, lv_num = 0;
|
||||
unsigned char *c;
|
||||
|
||||
for (i = 0; i < ID_LEN; i++) {
|
||||
lv_num *= sizeof(_c) - 1;
|
||||
if ((c = strchr(_c, lvid->id[1].uuid[i])))
|
||||
lv_num += (int) (c - _c);
|
||||
}
|
||||
|
||||
return lv_num;
|
||||
}
|
||||
|
||||
int id_create(struct id *id)
|
||||
{
|
||||
int random, i, len = sizeof(id->uuid);
|
||||
@@ -86,7 +124,7 @@ int id_write_format(struct id *id, char *buffer, size_t size)
|
||||
{
|
||||
int i, tot;
|
||||
|
||||
static int group_size[] = {6, 4, 4, 4, 4, 4, 6};
|
||||
static int group_size[] = { 6, 4, 4, 4, 4, 4, 6 };
|
||||
|
||||
assert(ID_LEN == 32);
|
||||
|
||||
|
||||
@@ -10,11 +10,25 @@
|
||||
#include "lvm-types.h"
|
||||
|
||||
#define ID_LEN 32
|
||||
#define ID_LEN_S "32"
|
||||
|
||||
struct id {
|
||||
uint8_t uuid[ID_LEN];
|
||||
};
|
||||
|
||||
/*
|
||||
* Unique logical volume identifier
|
||||
* With format1 this is VG uuid + LV uuid + '\0'
|
||||
*/
|
||||
union lvid {
|
||||
struct id id[2];
|
||||
char s[2 * sizeof(struct id) + 1];
|
||||
};
|
||||
|
||||
int lvid_from_lvnum(union lvid *lvid, struct id *vgid, int lv_num);
|
||||
int lvnum_from_lvid(union lvid *lvid);
|
||||
|
||||
int lvid_create(union lvid *lvid, struct id *vgid);
|
||||
int id_create(struct id *id);
|
||||
int id_valid(struct id *id);
|
||||
int id_equal(struct id *lhs, struct id *rhs);
|
||||
|
||||
@@ -10,8 +10,11 @@
|
||||
#include "hash.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "log.h"
|
||||
#include "uuid.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
static struct hash_table *_vghash;
|
||||
static struct hash_table *_vgidhash;
|
||||
static struct hash_table *_pvhash;
|
||||
|
||||
const char *all_devices = "\0";
|
||||
@@ -21,6 +24,9 @@ int vgcache_init()
|
||||
if (!(_vghash = hash_create(128)))
|
||||
return 0;
|
||||
|
||||
if (!(_vgidhash = hash_create(128)))
|
||||
return 0;
|
||||
|
||||
if (!(_pvhash = hash_create(128)))
|
||||
return 0;
|
||||
|
||||
@@ -44,6 +50,39 @@ struct list *vgcache_find(const char *vg_name)
|
||||
return &vgn->pvdevs;
|
||||
}
|
||||
|
||||
struct format_type *vgcache_find_format(const char *vg_name)
|
||||
{
|
||||
struct vgname_entry *vgn;
|
||||
|
||||
if (!_vghash)
|
||||
return NULL;
|
||||
|
||||
if (!vg_name)
|
||||
vg_name = all_devices;
|
||||
|
||||
if (!(vgn = hash_lookup(_vghash, vg_name)))
|
||||
return NULL;
|
||||
|
||||
return vgn->fmt;
|
||||
}
|
||||
|
||||
struct list *vgcache_find_by_vgid(const char *vgid)
|
||||
{
|
||||
struct vgname_entry *vgn;
|
||||
char vgid_s[ID_LEN + 1];
|
||||
|
||||
if (!_vgidhash || !vgid)
|
||||
return NULL;
|
||||
|
||||
memcpy(vgid_s, vgid, ID_LEN);
|
||||
vgid_s[ID_LEN] = '\0';
|
||||
|
||||
if (!(vgn = hash_lookup(_vgidhash, vgid_s)))
|
||||
return NULL;
|
||||
|
||||
return &vgn->pvdevs;
|
||||
}
|
||||
|
||||
void vgcache_del_orphan(struct device *dev)
|
||||
{
|
||||
struct pvdev_list *pvdev;
|
||||
@@ -55,7 +94,8 @@ void vgcache_del_orphan(struct device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
int vgcache_add_entry(const char *vg_name, struct device *dev)
|
||||
int vgcache_add_entry(const char *vg_name, const char *vgid, struct device *dev,
|
||||
struct format_type *fmt)
|
||||
{
|
||||
const char *pv_name;
|
||||
struct vgname_entry *vgn;
|
||||
@@ -67,7 +107,9 @@ int vgcache_add_entry(const char *vg_name, struct device *dev)
|
||||
log_error("struct vgname_entry allocation failed");
|
||||
return 0;
|
||||
}
|
||||
memset(vgn, 0, sizeof(struct vgname_entry));
|
||||
|
||||
vgn->fmt = fmt;
|
||||
pvdevs = &vgn->pvdevs;
|
||||
list_init(pvdevs);
|
||||
|
||||
@@ -80,8 +122,26 @@ int vgcache_add_entry(const char *vg_name, struct device *dev)
|
||||
log_error("vgcache_add: VG hash insertion failed");
|
||||
return 0;
|
||||
}
|
||||
} else if (!(vgn = hash_lookup(_vghash, vg_name))) {
|
||||
log_error("vgcache_add: VG name entry %s not found", vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vgid && strncmp(vgid, vgn->vgid, ID_LEN)) {
|
||||
hash_remove(_vgidhash, vgn->vgid);
|
||||
|
||||
memcpy(vgn->vgid, vgid, ID_LEN);
|
||||
vgn->vgid[ID_LEN] = '\0';
|
||||
|
||||
if (!hash_insert(_vgidhash, vgn->vgid, vgn)) {
|
||||
log_error("vgcache_add: vgid hash insertion " "failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dev)
|
||||
return 1;
|
||||
|
||||
list_iterate(pvdh, pvdevs) {
|
||||
pvdev = list_item(pvdh, struct pvdev_list);
|
||||
if (dev == pvdev->dev)
|
||||
@@ -115,21 +175,25 @@ int vgcache_add_entry(const char *vg_name, struct device *dev)
|
||||
}
|
||||
|
||||
/* vg_name of "\0" is an orphan PV; NULL means only add to all_devices */
|
||||
int vgcache_add(const char *vg_name, struct device *dev)
|
||||
int vgcache_add(const char *vg_name, const char *vgid, struct device *dev,
|
||||
struct format_type *fmt)
|
||||
{
|
||||
if (!_vghash && !vgcache_init())
|
||||
return 0;
|
||||
|
||||
/* If orphan PV remove it */
|
||||
if (vg_name && !*vg_name)
|
||||
if (dev && vg_name && !*vg_name)
|
||||
vgcache_del_orphan(dev);
|
||||
|
||||
/* Add PV if vg_name supplied */
|
||||
if (vg_name && *vg_name && !vgcache_add_entry(vg_name, dev))
|
||||
if (vg_name && *vg_name && !vgcache_add_entry(vg_name, vgid, dev, fmt))
|
||||
return 0;
|
||||
|
||||
/* Always add to all_devices */
|
||||
return vgcache_add_entry(all_devices, dev);
|
||||
/* Add to all_devices */
|
||||
if (dev)
|
||||
return vgcache_add_entry(all_devices, NULL, dev, fmt);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void vgcache_destroy_entry(struct vgname_entry *vgn)
|
||||
@@ -147,6 +211,8 @@ void vgcache_destroy_entry(struct vgname_entry *vgn)
|
||||
dbg_free(pvdev);
|
||||
}
|
||||
dbg_free(vgn->vgname);
|
||||
if (_vgidhash && vgn->vgid[0])
|
||||
hash_remove(_vgidhash, vgn->vgid);
|
||||
}
|
||||
dbg_free(vgn);
|
||||
}
|
||||
@@ -165,19 +231,65 @@ void vgcache_del(const char *vg_name)
|
||||
return;
|
||||
|
||||
hash_remove(_vghash, vg_name);
|
||||
if (vgn->vgid[0])
|
||||
hash_remove(_vgidhash, vgn->vgid);
|
||||
|
||||
vgcache_destroy_entry(vgn);
|
||||
}
|
||||
|
||||
void vgcache_del_by_vgid(const char *vgid)
|
||||
{
|
||||
struct vgname_entry *vgn;
|
||||
char vgid_s[ID_LEN + 1];
|
||||
|
||||
if (!_vgidhash || !vgid)
|
||||
return;
|
||||
|
||||
memcpy(vgid_s, vgid, ID_LEN);
|
||||
vgid_s[ID_LEN] = '\0';
|
||||
|
||||
if (!(vgn = hash_lookup(_vghash, vgid_s)))
|
||||
return;
|
||||
|
||||
hash_remove(_vgidhash, vgn->vgid);
|
||||
if (vgn->vgname[0])
|
||||
hash_remove(_vghash, vgn->vgname);
|
||||
|
||||
vgcache_destroy_entry(vgn);
|
||||
}
|
||||
|
||||
void vgcache_destroy()
|
||||
{
|
||||
if (_vghash) {
|
||||
hash_iterate(_vghash, (iterate_fn)vgcache_destroy_entry);
|
||||
hash_iter(_vghash, (iterate_fn) vgcache_destroy_entry);
|
||||
hash_destroy(_vghash);
|
||||
_vghash = NULL;
|
||||
}
|
||||
|
||||
if (_vgidhash) {
|
||||
hash_destroy(_vgidhash);
|
||||
_vgidhash = NULL;
|
||||
}
|
||||
|
||||
if (_pvhash) {
|
||||
hash_destroy(_pvhash);
|
||||
_pvhash = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char *vgname_from_vgid(struct cmd_context *cmd, struct id *vgid)
|
||||
{
|
||||
struct vgname_entry *vgn;
|
||||
char vgid_s[ID_LEN + 1];
|
||||
|
||||
if (!_vgidhash || !vgid)
|
||||
return NULL;
|
||||
|
||||
memcpy(vgid_s, vgid->uuid, ID_LEN);
|
||||
vgid_s[ID_LEN] = '\0';
|
||||
|
||||
if (!(vgn = hash_lookup(_vgidhash, vgid_s)))
|
||||
return NULL;
|
||||
|
||||
return pool_strdup(cmd->mem, vgn->vgname);
|
||||
}
|
||||
|
||||
@@ -12,10 +12,14 @@
|
||||
#include <asm/page.h>
|
||||
#include "dev-cache.h"
|
||||
#include "list.h"
|
||||
#include "uuid.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
struct vgname_entry {
|
||||
struct list pvdevs;
|
||||
char *vgname;
|
||||
char vgid[ID_LEN + 1];
|
||||
struct format_type *fmt;
|
||||
};
|
||||
|
||||
struct pvdev_list {
|
||||
@@ -28,9 +32,15 @@ void vgcache_destroy();
|
||||
|
||||
/* Return list of PVs in named VG */
|
||||
struct list *vgcache_find(const char *vg_name);
|
||||
struct format_type *vgcache_find_format(const char *vg_name);
|
||||
struct list *vgcache_find_by_vgid(const char *vgid);
|
||||
|
||||
/* FIXME Temporary function */
|
||||
char *vgname_from_vgid(struct cmd_context *cmd, struct id *vgid);
|
||||
|
||||
/* Add/delete a device */
|
||||
int vgcache_add(const char *vg_name, struct device *dev);
|
||||
int vgcache_add(const char *vg_name, const char *vgid, struct device *dev,
|
||||
struct format_type *fmt);
|
||||
void vgcache_del(const char *vg_name);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -44,5 +44,10 @@ ioctl_version: ioctl/libdevmapper.c
|
||||
ioctl/libdevmapper.c | \
|
||||
awk -F '[ \t\"]+' '/DM_IOCTL_VERSION/ {print $$3}' )"
|
||||
|
||||
.PHONY: ioctl_version
|
||||
distclean_lib:
|
||||
$(RM) libdm-common.h
|
||||
|
||||
distclean: distclean_lib
|
||||
|
||||
.PHONY: ioctl_version distclean_lib distclean
|
||||
|
||||
|
||||
@@ -25,26 +25,46 @@
|
||||
|
||||
#define ALIGNMENT sizeof(int)
|
||||
|
||||
static char *dm_cmd_list[] = {
|
||||
"create",
|
||||
"reload",
|
||||
"remove",
|
||||
"remove_all",
|
||||
"suspend",
|
||||
"resume",
|
||||
"info",
|
||||
"deps",
|
||||
"rename",
|
||||
"version"
|
||||
};
|
||||
|
||||
void dm_task_destroy(struct dm_task *dmt)
|
||||
{
|
||||
struct target *t, *n;
|
||||
|
||||
for (t = dmt->head; t; t = n) {
|
||||
n = t->next;
|
||||
free(t->params);
|
||||
free(t->type);
|
||||
free(t);
|
||||
}
|
||||
|
||||
if (dmt->dev_name)
|
||||
free(dmt->dev_name);
|
||||
|
||||
if (dmt->newname)
|
||||
free(dmt->newname);
|
||||
|
||||
if (dmt->dmi)
|
||||
free(dmt->dmi);
|
||||
|
||||
if (dmt->uuid)
|
||||
free(dmt->uuid);
|
||||
|
||||
free(dmt);
|
||||
}
|
||||
|
||||
int dm_task_get_driver_version(struct dm_task *dmt, char *version,
|
||||
size_t size)
|
||||
int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size)
|
||||
{
|
||||
if (!dmt->dmi)
|
||||
return 0;
|
||||
@@ -75,6 +95,16 @@ int dm_task_get_info(struct dm_task *dmt, struct dm_info *info)
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *dm_task_get_uuid(struct dm_task *dmt)
|
||||
{
|
||||
return (dmt->dmi->uuid);
|
||||
}
|
||||
|
||||
struct dm_deps *dm_task_get_deps(struct dm_task *dmt)
|
||||
{
|
||||
return (struct dm_deps *) (((void *) dmt->dmi) + dmt->dmi->data_start);
|
||||
}
|
||||
|
||||
int dm_task_set_ro(struct dm_task *dmt)
|
||||
{
|
||||
dmt->read_only = 1;
|
||||
@@ -92,13 +122,12 @@ int dm_task_set_newname(struct dm_task *dmt, const char *newname)
|
||||
}
|
||||
|
||||
struct target *create_target(uint64_t start,
|
||||
uint64_t len,
|
||||
const char *type, const char *params)
|
||||
uint64_t len, const char *type, const char *params)
|
||||
{
|
||||
struct target *t = malloc(sizeof(*t));
|
||||
|
||||
if (!t) {
|
||||
log_error("create_target: malloc(%d) failed", sizeof(*t));
|
||||
log_error("create_target: malloc(%d) failed", sizeof(*t));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -118,16 +147,17 @@ struct target *create_target(uint64_t start,
|
||||
t->length = len;
|
||||
return t;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
free(t->params);
|
||||
free(t->type);
|
||||
free(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *_align(void *ptr, unsigned int align)
|
||||
static void *_align(void *ptr, unsigned int a)
|
||||
{
|
||||
align--;
|
||||
register unsigned long align = --a;
|
||||
|
||||
return (void *) (((unsigned long) ptr + align) & ~align);
|
||||
}
|
||||
|
||||
@@ -171,6 +201,8 @@ static void *_add_target(struct target *t, void *out, void *end)
|
||||
|
||||
static struct dm_ioctl *_flatten(struct dm_task *dmt)
|
||||
{
|
||||
const size_t min_size = 16 * 1024;
|
||||
|
||||
struct dm_ioctl *dmi;
|
||||
struct target *t;
|
||||
size_t len = sizeof(struct dm_ioctl);
|
||||
@@ -191,6 +223,13 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt)
|
||||
if (dmt->newname)
|
||||
len += strlen(dmt->newname) + 1;
|
||||
|
||||
/*
|
||||
* Give len a minimum size so that we have space to store
|
||||
* dependencies or status information.
|
||||
*/
|
||||
if (len < min_size)
|
||||
len = min_size;
|
||||
|
||||
if (!(dmi = malloc(len)))
|
||||
return NULL;
|
||||
|
||||
@@ -208,11 +247,14 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt)
|
||||
if (dmt->read_only)
|
||||
dmi->flags |= DM_READONLY_FLAG;
|
||||
|
||||
if (dmt->minor > 0) {
|
||||
if (dmt->minor >= 0) {
|
||||
dmi->flags |= DM_PERSISTENT_DEV_FLAG;
|
||||
dmi->dev = MKDEV(0, dmt->minor);
|
||||
}
|
||||
|
||||
if (dmt->uuid)
|
||||
strncpy(dmi->uuid, dmt->uuid, sizeof(dmi->uuid));
|
||||
|
||||
dmi->target_count = count;
|
||||
|
||||
b = (void *) (dmi + 1);
|
||||
@@ -227,7 +269,7 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt)
|
||||
|
||||
return dmi;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
free(dmi);
|
||||
return NULL;
|
||||
}
|
||||
@@ -264,6 +306,10 @@ int dm_task_run(struct dm_task *dmt)
|
||||
command = DM_REMOVE;
|
||||
break;
|
||||
|
||||
case DM_DEVICE_REMOVE_ALL:
|
||||
command = DM_REMOVE_ALL;
|
||||
break;
|
||||
|
||||
case DM_DEVICE_SUSPEND:
|
||||
command = DM_SUSPEND;
|
||||
break;
|
||||
@@ -276,6 +322,10 @@ int dm_task_run(struct dm_task *dmt)
|
||||
command = DM_INFO;
|
||||
break;
|
||||
|
||||
case DM_DEVICE_DEPS:
|
||||
command = DM_DEPS;
|
||||
break;
|
||||
|
||||
case DM_DEVICE_RENAME:
|
||||
command = DM_RENAME;
|
||||
break;
|
||||
@@ -286,13 +336,15 @@ int dm_task_run(struct dm_task *dmt)
|
||||
|
||||
default:
|
||||
log_error("Internal error: unknown device-mapper task %d",
|
||||
dmt->type);
|
||||
dmt->type);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
log_debug("dm %s %s %s %s", dm_cmd_list[dmt->type], dmi->name,
|
||||
dmi->uuid, dmt->newname ? dmt->newname : "");
|
||||
if (ioctl(fd, command, dmi) < 0) {
|
||||
log_error("device-mapper ioctl cmd %d failed: %s", dmt->type,
|
||||
strerror(errno));
|
||||
strerror(errno));
|
||||
goto bad;
|
||||
}
|
||||
|
||||
@@ -304,15 +356,19 @@ int dm_task_run(struct dm_task *dmt)
|
||||
case DM_DEVICE_REMOVE:
|
||||
rm_dev_node(dmt->dev_name);
|
||||
break;
|
||||
|
||||
case DM_DEVICE_RENAME:
|
||||
rename_dev_node(dmt->dev_name, dmt->newname);
|
||||
break;
|
||||
}
|
||||
|
||||
dmt->dmi = dmi;
|
||||
close(fd);
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
free(dmi);
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,5 +23,7 @@ struct dm_task {
|
||||
int minor;
|
||||
struct dm_ioctl *dmi;
|
||||
char *newname;
|
||||
|
||||
char *uuid;
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* Since it is quite laborious to build the ioctl
|
||||
@@ -19,9 +20,8 @@
|
||||
* each ioctl command you want to execute.
|
||||
*/
|
||||
|
||||
|
||||
typedef void (*dm_log_fn)(int level, const char *file, int line,
|
||||
const char *f, ...);
|
||||
typedef void (*dm_log_fn) (int level, const char *file, int line,
|
||||
const char *f, ...);
|
||||
|
||||
/*
|
||||
* The library user may wish to register their own
|
||||
@@ -34,23 +34,25 @@ enum {
|
||||
DM_DEVICE_CREATE,
|
||||
DM_DEVICE_RELOAD,
|
||||
DM_DEVICE_REMOVE,
|
||||
DM_DEVICE_REMOVE_ALL,
|
||||
|
||||
DM_DEVICE_SUSPEND,
|
||||
DM_DEVICE_RESUME,
|
||||
|
||||
DM_DEVICE_INFO,
|
||||
DM_DEVICE_DEPS,
|
||||
DM_DEVICE_RENAME,
|
||||
|
||||
DM_DEVICE_VERSION,
|
||||
};
|
||||
|
||||
|
||||
struct dm_task;
|
||||
|
||||
struct dm_task *dm_task_create(int type);
|
||||
void dm_task_destroy(struct dm_task *dmt);
|
||||
|
||||
int dm_task_set_name(struct dm_task *dmt, const char *name);
|
||||
int dm_task_set_uuid(struct dm_task *dmt, const char *uuid);
|
||||
|
||||
/*
|
||||
* Retrieve attributes after an info.
|
||||
@@ -66,9 +68,17 @@ struct dm_info {
|
||||
unsigned int target_count;
|
||||
};
|
||||
|
||||
struct dm_deps {
|
||||
unsigned int count;
|
||||
__kernel_dev_t device[0];
|
||||
};
|
||||
|
||||
int dm_get_library_version(char *version, size_t size);
|
||||
int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size);
|
||||
int dm_task_get_info(struct dm_task *dmt, struct dm_info *dmi);
|
||||
const char *dm_task_get_uuid(struct dm_task *dmt);
|
||||
|
||||
struct dm_deps *dm_task_get_deps(struct dm_task *dmt);
|
||||
|
||||
int dm_task_set_ro(struct dm_task *dmt);
|
||||
int dm_task_set_newname(struct dm_task *dmt, const char *newname);
|
||||
@@ -79,9 +89,7 @@ int dm_task_set_minor(struct dm_task *dmt, int minor);
|
||||
*/
|
||||
int dm_task_add_target(struct dm_task *dmt,
|
||||
uint64_t start,
|
||||
uint64_t size,
|
||||
const char *ttype,
|
||||
const char *params);
|
||||
uint64_t size, const char *ttype, const char *params);
|
||||
|
||||
/*
|
||||
* Call this to actually run the ioctl.
|
||||
@@ -94,4 +102,4 @@ int dm_task_run(struct dm_task *dmt);
|
||||
int dm_set_dev_dir(const char *dir);
|
||||
const char *dm_dir(void);
|
||||
|
||||
#endif /* LIB_DEVICE_MAPPER_H */
|
||||
#endif /* LIB_DEVICE_MAPPER_H */
|
||||
|
||||
@@ -30,23 +30,30 @@ static char _dm_dir[PATH_MAX] = DEV_DIR DM_DIR;
|
||||
* Library users can provide their own logging
|
||||
* function.
|
||||
*/
|
||||
void _default_log(int level, const char *file, int line,
|
||||
const char *f, ...)
|
||||
void _default_log(int level, const char *file, int line, const char *f, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, f);
|
||||
vfprintf(stderr, f, ap);
|
||||
va_end(ap);
|
||||
if (level > _LOG_WARN)
|
||||
return;
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
va_start(ap, f);
|
||||
|
||||
if (level == _LOG_WARN)
|
||||
vprintf(f, ap);
|
||||
else
|
||||
vfprintf(stderr, f, ap);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
dm_log_fn _log = _default_log;
|
||||
|
||||
void dm_log_init(dm_log_fn fn)
|
||||
{
|
||||
_log = fn;
|
||||
_log = fn;
|
||||
}
|
||||
|
||||
void _build_dev_path(char *buffer, size_t len, const char *dev_name)
|
||||
@@ -55,7 +62,7 @@ void _build_dev_path(char *buffer, size_t len, const char *dev_name)
|
||||
if (strchr(dev_name, '/'))
|
||||
snprintf(buffer, len, "%s", dev_name);
|
||||
else
|
||||
snprintf(buffer, len, "%s/%s", _dm_dir, dev_name);
|
||||
snprintf(buffer, len, "%s/%s", _dm_dir, dev_name);
|
||||
}
|
||||
|
||||
int dm_get_library_version(char *version, size_t size)
|
||||
@@ -66,18 +73,18 @@ int dm_get_library_version(char *version, size_t size)
|
||||
|
||||
struct dm_task *dm_task_create(int type)
|
||||
{
|
||||
struct dm_task *dmt = malloc(sizeof(*dmt));
|
||||
struct dm_task *dmt = malloc(sizeof(*dmt));
|
||||
|
||||
if (!dmt) {
|
||||
log_error("dm_task_create: malloc(%d) failed", sizeof(*dmt));
|
||||
return NULL;
|
||||
}
|
||||
if (!dmt) {
|
||||
log_error("dm_task_create: malloc(%d) failed", sizeof(*dmt));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(dmt, 0, sizeof(*dmt));
|
||||
memset(dmt, 0, sizeof(*dmt));
|
||||
|
||||
dmt->type = type;
|
||||
dmt->type = type;
|
||||
dmt->minor = -1;
|
||||
return dmt;
|
||||
return dmt;
|
||||
}
|
||||
|
||||
int dm_task_set_name(struct dm_task *dmt, const char *name)
|
||||
@@ -86,8 +93,10 @@ int dm_task_set_name(struct dm_task *dmt, const char *name)
|
||||
char path[PATH_MAX];
|
||||
struct stat st1, st2;
|
||||
|
||||
if (dmt->dev_name)
|
||||
free(dmt->dev_name);
|
||||
if (dmt->dev_name) {
|
||||
free(dmt->dev_name);
|
||||
dmt->dev_name = NULL;
|
||||
}
|
||||
|
||||
/* If path was supplied, remove it if it points to the same device
|
||||
* as its last component.
|
||||
@@ -97,106 +106,156 @@ int dm_task_set_name(struct dm_task *dmt, const char *name)
|
||||
|
||||
if (stat(name, &st1) || stat(path, &st2) ||
|
||||
!(st1.st_dev == st2.st_dev)) {
|
||||
log_error("dm_task_set_name: Device %s not found", name);
|
||||
log_error("dm_task_set_name: Device %s not found",
|
||||
name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
name = pos + 1;
|
||||
}
|
||||
|
||||
if (!(dmt->dev_name = strdup(name))) {
|
||||
if (!(dmt->dev_name = strdup(name))) {
|
||||
log_error("dm_task_set_name: strdup(%s) failed", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_task_set_uuid(struct dm_task *dmt, const char *uuid)
|
||||
{
|
||||
if (dmt->uuid) {
|
||||
free(dmt->uuid);
|
||||
dmt->uuid = NULL;
|
||||
}
|
||||
|
||||
if (!(dmt->uuid = strdup(uuid))) {
|
||||
log_error("dm_task_set_uuid: strdup(%s) failed", uuid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_task_set_minor(struct dm_task *dmt, int minor)
|
||||
{
|
||||
dmt->minor = minor;
|
||||
return 1;
|
||||
dmt->minor = minor;
|
||||
log_debug("Setting minor: %d", dmt->minor);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int dm_task_add_target(struct dm_task *dmt,
|
||||
uint64_t start,
|
||||
uint64_t size,
|
||||
const char *ttype,
|
||||
const char *params)
|
||||
int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size,
|
||||
const char *ttype, const char *params)
|
||||
{
|
||||
struct target *t = create_target(start, size, ttype, params);
|
||||
struct target *t = create_target(start, size, ttype, params);
|
||||
|
||||
if (!t)
|
||||
return 0;
|
||||
if (!t)
|
||||
return 0;
|
||||
|
||||
if (!dmt->head)
|
||||
dmt->head = dmt->tail = t;
|
||||
else {
|
||||
dmt->tail->next = t;
|
||||
dmt->tail = t;
|
||||
}
|
||||
if (!dmt->head)
|
||||
dmt->head = dmt->tail = t;
|
||||
else {
|
||||
dmt->tail->next = t;
|
||||
dmt->tail = t;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int add_dev_node(const char *dev_name, dev_t dev)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
struct stat info;
|
||||
char path[PATH_MAX];
|
||||
struct stat info;
|
||||
|
||||
_build_dev_path(path, sizeof(path), dev_name);
|
||||
_build_dev_path(path, sizeof(path), dev_name);
|
||||
|
||||
if (stat(path, &info) >= 0) {
|
||||
if (!S_ISBLK(info.st_mode)) {
|
||||
log_error("A non-block device file at '%s' "
|
||||
"is already present", path);
|
||||
return 0;
|
||||
}
|
||||
if (stat(path, &info) >= 0) {
|
||||
if (!S_ISBLK(info.st_mode)) {
|
||||
log_error("A non-block device file at '%s' "
|
||||
"is already present", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info.st_rdev == dev)
|
||||
return 1;
|
||||
if (info.st_rdev == dev)
|
||||
return 1;
|
||||
|
||||
if (unlink(path) < 0) {
|
||||
log_error("Unable to unlink device node for '%s'", dev_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (unlink(path) < 0) {
|
||||
log_error("Unable to unlink device node for '%s'",
|
||||
dev_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (mknod(path, S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, dev) < 0) {
|
||||
log_error("Unable to make device node for '%s'", dev_name);
|
||||
return 0;
|
||||
}
|
||||
if (mknod(path, S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, dev) < 0) {
|
||||
log_error("Unable to make device node for '%s'", dev_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rename_dev_node(const char *old_name, const char *new_name)
|
||||
{
|
||||
char oldpath[PATH_MAX];
|
||||
char newpath[PATH_MAX];
|
||||
struct stat info;
|
||||
|
||||
_build_dev_path(oldpath, sizeof(oldpath), old_name);
|
||||
_build_dev_path(newpath, sizeof(newpath), new_name);
|
||||
|
||||
if (stat(newpath, &info) == 0) {
|
||||
if (!S_ISBLK(info.st_mode)) {
|
||||
log_error("A non-block device file at '%s' "
|
||||
"is already present", newpath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (unlink(newpath) < 0) {
|
||||
if (errno == EPERM) {
|
||||
/* devfs, entry has already been renamed */
|
||||
return 1;
|
||||
}
|
||||
log_error("Unable to unlink device node for '%s'",
|
||||
new_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (rename(oldpath, newpath) < 0) {
|
||||
log_error("Unable to rename device node from '%s' to '%s'",
|
||||
old_name, new_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rm_dev_node(const char *dev_name)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
struct stat info;
|
||||
char path[PATH_MAX];
|
||||
struct stat info;
|
||||
|
||||
_build_dev_path(path, sizeof(path), dev_name);
|
||||
_build_dev_path(path, sizeof(path), dev_name);
|
||||
|
||||
if (stat(path, &info) < 0)
|
||||
return 1;
|
||||
if (stat(path, &info) < 0)
|
||||
return 1;
|
||||
|
||||
if (unlink(path) < 0) {
|
||||
log_error("Unable to unlink device node for '%s'", dev_name);
|
||||
return 0;
|
||||
}
|
||||
if (unlink(path) < 0) {
|
||||
log_error("Unable to unlink device node for '%s'", dev_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_set_dev_dir(const char *dir)
|
||||
{
|
||||
snprintf(_dm_dir, sizeof(_dm_dir), "%s%s", dir, DM_DIR);
|
||||
return 1;
|
||||
snprintf(_dm_dir, sizeof(_dm_dir), "%s%s", dir, DM_DIR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *dm_dir(void)
|
||||
{
|
||||
return _dm_dir;
|
||||
return _dm_dir;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ extern struct target *create_target(uint64_t start,
|
||||
|
||||
int add_dev_node(const char *dev_name, dev_t dev);
|
||||
int rm_dev_node(const char *dev_name);
|
||||
int rename_dev_node(const char *old_name, const char *new_name);
|
||||
|
||||
#define DM_LIB_VERSION @DM_LIB_VERSION@
|
||||
|
||||
|
||||
@@ -21,7 +21,11 @@ top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
MAN5=lvm.conf.5
|
||||
MAN8=lvm.8
|
||||
MAN8=lvchange.8 lvcreate.8 lvdisplay.8 lvextend.8 lvm.8 lvmchange.8 \
|
||||
lvreduce.8 lvremove.8 lvrename.8 lvscan.8 pvchange.8 \
|
||||
pvcreate.8 pvdisplay.8 pvscan.8 vgcfgbackup.8 vgchange.8 vgck.8 \
|
||||
vgcreate.8 vgdisplay.8 vgextend.8 vgmerge.8 vgreduce.8 vgremove.8 \
|
||||
vgrename.8 vgscan.8
|
||||
MAN5DIR=${mandir}/man5
|
||||
MAN8DIR=${mandir}/man8
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user