mirror of
git://sourceware.org/git/lvm2.git
synced 2025-10-18 03:33:15 +03:00
Compare commits
152 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
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
|
||||
|
23
debian/changelog
vendored
Normal file
23
debian/changelog
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
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/.*/"
|
||||
|
||||
|
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 \
|
||||
|
101
lib/activate/activate-lv.c
Normal file
101
lib/activate/activate-lv.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "ll-activate.h"
|
||||
#include "lvm-string.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <libdevmapper.h>
|
||||
|
||||
/*
|
||||
* Emit a target for a given segment.
|
||||
* FIXME: tidy this function.
|
||||
*/
|
||||
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 device_populate_lv(struct dm_task *dmt, struct logical_volume *lv)
|
||||
{
|
||||
struct list *segh;
|
||||
struct stripe_segment *seg;
|
||||
|
||||
log_very_verbose("Generating devmapper table for %s", lv->name);
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct stripe_segment);
|
||||
if (!_emit_target(dmt, seg)) {
|
||||
log_error("Unable to build table for '%s'", lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
@@ -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,140 @@ 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;
|
||||
char *vgname;
|
||||
|
||||
lvid = (union lvid *) lvid_s;
|
||||
|
||||
/* FIXME Change vgread to accept vgid directly - can't rely on cache */
|
||||
if (!(vgname = vgname_from_vgid(cmd, &lvid->id[0]))) {
|
||||
log_error("Volume group for uuid not found: %s", lvid_s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log_verbose("Finding volume group \"%s\"", vgname);
|
||||
if (!(vg = cmd->fid->ops->vg_read(cmd->fid, vgname))) {
|
||||
log_error("Volume group \"%s\" doesn't exist", vgname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group \"%s\" is exported", vgname);
|
||||
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
|
||||
|
1525
lib/activate/dev_manager.c
Normal file
1525
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
|
@@ -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
|
||||
|
33
lib/commands/toolcontext.h
Normal file
33
lib/commands/toolcontext.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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_instance *fid;
|
||||
|
||||
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
|
@@ -22,6 +22,8 @@
|
||||
#define DEFAULT_DEV_DIR "/dev"
|
||||
#define DEFAULT_PROC_DIR "/proc"
|
||||
|
||||
#define DEFAULT_LOCK_DIR "/var/lock/lvm"
|
||||
|
||||
#define DEFAULT_UMASK 0077
|
||||
|
||||
#ifdef READLINE_SUPPORT
|
@@ -175,7 +175,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;
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -268,7 +268,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)
|
||||
|
@@ -96,6 +96,12 @@ int dev_open(struct device *dev, int flags)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _flush(int fd)
|
||||
{
|
||||
if (ioctl(fd, BLKFLSBUF, 0))
|
||||
log_error("couldn't flush device.");
|
||||
}
|
||||
|
||||
int dev_close(struct device *dev)
|
||||
{
|
||||
if (dev->fd < 0) {
|
||||
@@ -104,6 +110,8 @@ int dev_close(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
_flush(dev->fd);
|
||||
|
||||
if (close(dev->fd))
|
||||
log_sys_error("close", dev_name(dev));
|
||||
|
||||
|
@@ -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;
|
||||
@@ -108,7 +109,7 @@ void pvdisplay_full(struct physical_volume *pv)
|
||||
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);
|
||||
@@ -155,7 +156,7 @@ 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;
|
||||
@@ -195,12 +196,19 @@ void lvdisplay_colons(struct logical_volume *lv)
|
||||
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;
|
||||
|
||||
if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
inkernel = lv_info(lv, &info) && info.exists;
|
||||
|
||||
@@ -210,9 +218,14 @@ int lvdisplay_full(struct logical_volume *lv)
|
||||
lv->vg->name, lv->name);
|
||||
log_print("VG Name %s", lv->vg->name);
|
||||
|
||||
log_print("LV UUID %s", uuid);
|
||||
|
||||
log_print("LV Write Access %s",
|
||||
(lv->status & LVM_WRITE) ? "read/write" : "read only");
|
||||
|
||||
if ((snap = find_cow(lv)))
|
||||
log_print("Snapshot of %s", 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) {
|
||||
@@ -353,6 +366,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) ");
|
||||
@@ -466,7 +482,7 @@ void vgdisplay_full(struct volume_group *vg)
|
||||
log_print ( "Act PV %u", vg->pv_act);
|
||||
*********/
|
||||
|
||||
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);
|
||||
|
||||
@@ -477,13 +493,14 @@ 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);
|
||||
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);
|
||||
|
@@ -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 *);
|
||||
|
||||
void lvm_type_filter_destroy(struct dev_filter *f);
|
||||
|
||||
|
@@ -305,7 +305,7 @@ static struct disk_list *__read_disk(struct device *dev, struct pool *mem,
|
||||
log_very_verbose("%s is not a member of any VG", name);
|
||||
|
||||
/* Update VG cache */
|
||||
vgcache_add(data->pvd.vg_name, dev);
|
||||
vgcache_add(data->pvd.vg_name, NULL, dev);
|
||||
|
||||
return (vg_name) ? NULL : data;
|
||||
}
|
||||
@@ -319,7 +319,7 @@ static struct disk_list *__read_disk(struct device *dev, struct pool *mem,
|
||||
_munge_exported_vg(data);
|
||||
|
||||
/* Update VG cache with what we found */
|
||||
vgcache_add(data->pvd.vg_name, dev);
|
||||
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, dev);
|
||||
|
||||
if (vg_name && strcmp(vg_name, data->pvd.vg_name)) {
|
||||
log_very_verbose("%s is not a member of the VG %s",
|
||||
@@ -582,13 +582,18 @@ 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);
|
||||
/*
|
||||
* 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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!test_mode())
|
||||
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev);
|
||||
|
||||
if (!_write_vgd(data)) {
|
||||
log_error("Failed to write VG data to %s", pv_name);
|
||||
|
@@ -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 /* " */
|
||||
@@ -215,7 +217,7 @@ 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,
|
||||
@@ -229,6 +231,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);
|
||||
|
@@ -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);
|
||||
|
||||
@@ -81,8 +83,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 cmd_context *cmd,
|
||||
struct list *pvs)
|
||||
{
|
||||
struct pool *mem = cmd->mem;
|
||||
struct volume_group *vg = pool_alloc(mem, sizeof(*vg));
|
||||
struct disk_list *dl;
|
||||
int partial;
|
||||
@@ -95,8 +99,10 @@ static struct volume_group *_build_vg(struct pool *mem, struct list *pvs)
|
||||
|
||||
memset(vg, 0, sizeof(*vg));
|
||||
|
||||
vg->cmd = cmd;
|
||||
list_init(&vg->pvs);
|
||||
list_init(&vg->lvs);
|
||||
list_init(&vg->snapshots);
|
||||
|
||||
if (!_check_vgs(pvs, &partial))
|
||||
goto bad;
|
||||
@@ -115,6 +121,9 @@ 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:
|
||||
@@ -144,13 +153,11 @@ static struct volume_group *_vg_read(struct format_instance *fi,
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(vg = _build_vg(fi->cmd->mem, &pvs))) {
|
||||
if (!(vg = _build_vg(fi->cmd, &pvs))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
vg->cmd = fi->cmd;
|
||||
|
||||
bad:
|
||||
pool_destroy(mem);
|
||||
return vg;
|
||||
@@ -387,6 +394,19 @@ static struct list *_get_vgs(struct format_instance *fi)
|
||||
static int _pv_setup(struct format_instance *fi, 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,13 +418,48 @@ static int _pv_setup(struct format_instance *fi, struct physical_volume *pv,
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate/populate LV structure for format1.
|
||||
* Supplied LV structure can be for a new LV or for an already-existing one.
|
||||
*/
|
||||
static int _lv_setup(struct format_instance *fi, 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;
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <linux/kdev_t.h>
|
||||
|
||||
static int _check_vg_name(const char *name)
|
||||
{
|
||||
@@ -57,10 +58,10 @@ int import_pv(struct pool *mem, struct device *dev,
|
||||
if (vg &&
|
||||
strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id)))
|
||||
log_very_verbose("System ID %s on %s differs from %s for "
|
||||
"volume group", pvd->system_id,
|
||||
"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.
|
||||
*/
|
||||
@@ -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,7 +160,7 @@ 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);
|
||||
@@ -271,7 +272,8 @@ 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));
|
||||
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 +282,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;
|
||||
|
||||
@@ -329,15 +331,14 @@ 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;
|
||||
@@ -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,7 +437,6 @@ static struct logical_volume *_add_lv(struct pool *mem,
|
||||
}
|
||||
|
||||
list_add(&vg->lvs, &ll->list);
|
||||
lv->vg = vg;
|
||||
vg->lv_count++;
|
||||
|
||||
return lv;
|
||||
@@ -466,13 +467,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,32 +489,147 @@ 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) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int export_uuids(struct disk_list *dl, struct volume_group *vg)
|
||||
{
|
||||
struct uuid_list *ul;
|
||||
@@ -528,9 +652,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)
|
||||
{
|
||||
|
@@ -105,9 +105,8 @@ int calculate_layout(struct disk_list *dl)
|
||||
|
||||
|
||||
/*
|
||||
* It may seem strange to have a struct
|
||||
* physical_volume in here, but the number of
|
||||
* extents that can fit on a disk *is* metadata
|
||||
* 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 +116,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);
|
||||
|
||||
|
@@ -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,6 +21,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
/*
|
||||
@@ -34,97 +36,18 @@
|
||||
* 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.
|
||||
@@ -182,50 +105,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 +119,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);
|
||||
/*
|
||||
* Create a new archive_file.
|
||||
*/
|
||||
if (!(af = pool_alloc(mem, sizeof(*af)))) {
|
||||
log_err("Couldn't create new archive file.");
|
||||
results = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
af->index = index;
|
||||
af->path = path;
|
||||
|
||||
/*
|
||||
* Insert it to the correct part of the list.
|
||||
*/
|
||||
_insert_file(results, af);
|
||||
}
|
||||
r = 1;
|
||||
|
||||
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 +213,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 +224,82 @@ 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) {
|
||||
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;
|
||||
time_t when;
|
||||
char *desc;
|
||||
|
||||
log_print("path:\t\t%s", af->path);
|
||||
|
||||
/*
|
||||
* Read the archive file to ensure that it is valid, and
|
||||
* retrieve the archive time and description.
|
||||
*/
|
||||
if (!(vg = text_vg_import(cmd, af->path, um, &when, &desc))) {
|
||||
log_print("Unable to read archive file.");
|
||||
return;
|
||||
}
|
||||
|
||||
log_print("description:\t%s", desc ? desc : "<No description>");
|
||||
log_print("time:\t\t%s", ctime(&when));
|
||||
|
||||
pool_free(cmd->mem, vg);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@@ -172,7 +172,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 +182,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;
|
||||
}
|
||||
|
||||
@@ -217,7 +222,7 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
|
||||
static inline const char *
|
||||
_get_pv_name(struct formatter *f, struct physical_volume *pv)
|
||||
{
|
||||
return (pv) ? (const char *)
|
||||
return (pv) ? (const char *)
|
||||
hash_lookup(f->pv_names, dev_name(pv->dev)) :
|
||||
"Missing";
|
||||
}
|
||||
@@ -333,16 +338,30 @@ 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) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
|
||||
_nl(f);
|
||||
_out(f, "%s {", lv->name);
|
||||
_inc_indent(f);
|
||||
|
||||
/* FIXME: Write full lvid */
|
||||
if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_out(f, "id = \"%s\"", buffer);
|
||||
|
||||
if (!print_flags(lv->status, LV_FLAGS,
|
||||
buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
@@ -351,6 +370,8 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
||||
|
||||
_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);
|
||||
|
||||
@@ -374,6 +395,54 @@ 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
|
||||
@@ -429,7 +498,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;
|
||||
@@ -450,7 +519,7 @@ int text_vg_export(FILE *fp, struct volume_group *vg)
|
||||
|
||||
#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,15 +529,17 @@ 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);
|
||||
|
@@ -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}
|
||||
};
|
||||
|
||||
|
@@ -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,63 +12,70 @@
|
||||
#include "pool.h"
|
||||
#include "config.h"
|
||||
#include "hash.h"
|
||||
#include "display.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/file.h>
|
||||
#include <limits.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 */
|
||||
|
||||
/*
|
||||
* NOTE: Currently there can be only one vg per file.
|
||||
*/
|
||||
|
||||
struct text_c {
|
||||
char *path;
|
||||
char *desc;
|
||||
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;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lv_setup(struct format_instance *fi, struct logical_volume *lv)
|
||||
{
|
||||
uint64_t max_size = UINT_MAX;
|
||||
|
||||
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,
|
||||
@@ -76,8 +83,10 @@ static struct volume_group *_vg_read(struct format_instance *fi,
|
||||
{
|
||||
struct text_c *tc = (struct text_c *) fi->private;
|
||||
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->cmd, tc->path, tc->um, &when, &desc))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
@@ -119,10 +128,10 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg)
|
||||
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,7 +139,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, tc->desc)) {
|
||||
log_error("Failed to write metadata to %s.", temp_file);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
@@ -150,56 +159,232 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct list *_get_vgs(struct format_instance *fi)
|
||||
{
|
||||
struct text_c *tc = (struct text_c *) fi->private;
|
||||
struct list *names = pool_alloc(fi->cmd->mem, sizeof(*names));
|
||||
struct name_list *nl;
|
||||
struct volume_group *vg;
|
||||
char *slash;
|
||||
char *vgname;
|
||||
|
||||
if (!names) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_init(names);
|
||||
|
||||
/* Determine the VG name from the file name */
|
||||
slash = rindex(tc->path, '/');
|
||||
if (slash) {
|
||||
vgname = pool_alloc(fi->cmd->mem, strlen(slash));
|
||||
strcpy(vgname, slash + 1);
|
||||
} else {
|
||||
vgname = pool_alloc(fi->cmd->mem, strlen(tc->path) + 1);
|
||||
strcpy(vgname, tc->path);
|
||||
}
|
||||
|
||||
vg = _vg_read(fi, vgname);
|
||||
if (vg) {
|
||||
|
||||
pool_free(fi->cmd->mem, vg);
|
||||
if (!(nl = pool_alloc(fi->cmd->mem, sizeof(*nl)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
nl->name = vgname;
|
||||
|
||||
list_add(names, &nl->list);
|
||||
}
|
||||
|
||||
return names;
|
||||
|
||||
bad:
|
||||
pool_free(fi->cmd->mem, names);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct list *_get_pvs(struct format_instance *fi)
|
||||
{
|
||||
struct pv_list *pvl;
|
||||
struct list *vgh;
|
||||
struct list *pvh;
|
||||
struct list *results = pool_alloc(fi->cmd->mem, sizeof(*results));
|
||||
struct list *vgs = _get_vgs(fi);
|
||||
|
||||
list_init(results);
|
||||
|
||||
list_iterate(vgh, vgs) {
|
||||
struct volume_group *vg;
|
||||
struct name_list *nl;
|
||||
|
||||
nl = list_item(vgh, struct name_list);
|
||||
vg = _vg_read(fi, nl->name);
|
||||
if (vg) {
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
struct pv_list *vgpv =
|
||||
list_item(pvh, struct pv_list);
|
||||
|
||||
pvl = pool_alloc(fi->cmd->mem, sizeof(*pvl));
|
||||
if (!pvl) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
/* ?? do we need to clone the pv structure...really? Nah. */
|
||||
pvl->pv = vgpv->pv;
|
||||
list_add(results, &pvl->list);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
|
||||
bad:
|
||||
pool_free(fi->cmd->mem, vgs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
|
||||
{
|
||||
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_allocated = pv->pe_allocated;
|
||||
|
||||
/* Write it back */
|
||||
_vg_write(fi, vg);
|
||||
pool_free(fi->cmd->mem, vg);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
pool_free(fi->cmd->mem, vg);
|
||||
}
|
||||
|
||||
/* Can't handle PVs not in a VG */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct physical_volume *_pv_read(struct format_instance *fi,
|
||||
const char *pv_name)
|
||||
{
|
||||
struct list *vgs = _get_vgs(fi);
|
||||
struct list *vgh;
|
||||
struct list *pvh;
|
||||
struct physical_volume *pv;
|
||||
|
||||
/* Look for the PV */
|
||||
list_iterate(vgh, vgs) {
|
||||
struct volume_group *vg;
|
||||
struct name_list *nl;
|
||||
|
||||
nl = list_item(vgh, struct name_list);
|
||||
vg = _vg_read(fi, nl->name);
|
||||
if (vg) {
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
struct pv_list *vgpv =
|
||||
list_item(pvh, struct pv_list);
|
||||
|
||||
if (!strcmp(dev_name(vgpv->pv->dev), pv_name)) {
|
||||
pv = pool_alloc(fi->cmd->mem,
|
||||
sizeof(*pv));
|
||||
if (!pv) {
|
||||
stack;
|
||||
pool_free(fi->cmd->mem, vg);
|
||||
return NULL;
|
||||
}
|
||||
/* Memberwise copy */
|
||||
*pv = *vgpv->pv;
|
||||
|
||||
pv->vg_name =
|
||||
pool_alloc(fi->cmd->mem,
|
||||
strlen(vgpv->pv->
|
||||
vg_name) + 1);
|
||||
if (!pv->vg_name) {
|
||||
stack;
|
||||
pool_free(fi->cmd->mem, vg);
|
||||
return NULL;
|
||||
}
|
||||
strcpy(pv->vg_name, vgpv->pv->vg_name);
|
||||
pool_free(fi->cmd->mem, vg);
|
||||
return pv;
|
||||
}
|
||||
}
|
||||
pool_free(fi->cmd->mem, vg);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _destroy(struct format_instance *fi)
|
||||
{
|
||||
struct text_c *tc = (struct text_c *) fi->private;
|
||||
|
||||
dbg_free(tc->path);
|
||||
dbg_free(tc->desc);
|
||||
dbg_free(tc);
|
||||
dbg_free(fi);
|
||||
}
|
||||
|
||||
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,
|
||||
vg_setup: _vg_setup,
|
||||
lv_setup: _lv_setup,
|
||||
vg_read: _vg_read,
|
||||
vg_write: _vg_write,
|
||||
destroy: _destroy
|
||||
};
|
||||
|
||||
struct format_instance *text_format_create(struct cmd_context *cmd,
|
||||
const char *file,
|
||||
struct uuid_map *um)
|
||||
struct uuid_map *um,
|
||||
const char *desc)
|
||||
{
|
||||
const char *no_alloc = "Couldn't allocate text format object.";
|
||||
|
||||
struct format_instance *fi;
|
||||
char *path;
|
||||
char *path, *d;
|
||||
struct text_c *tc;
|
||||
|
||||
if (!(fi = dbg_malloc(sizeof(*fi)))) {
|
||||
log_err(no_alloc);
|
||||
return NULL;
|
||||
stack;
|
||||
goto no_mem;
|
||||
}
|
||||
|
||||
if (!(path = dbg_strdup(file))) {
|
||||
dbg_free(fi);
|
||||
log_err(no_alloc);
|
||||
return NULL;
|
||||
stack;
|
||||
goto no_mem;
|
||||
}
|
||||
|
||||
if (!(d = dbg_strdup(desc))) {
|
||||
stack;
|
||||
goto no_mem;
|
||||
}
|
||||
|
||||
if (!(tc = dbg_malloc(sizeof(*tc)))) {
|
||||
dbg_free(fi);
|
||||
dbg_free(path);
|
||||
log_err(no_alloc);
|
||||
return NULL;
|
||||
stack;
|
||||
goto no_mem;
|
||||
}
|
||||
|
||||
tc->path = path;
|
||||
tc->desc = d;
|
||||
tc->um = um;
|
||||
|
||||
fi->cmd = cmd;
|
||||
@@ -207,4 +392,17 @@ struct format_instance *text_format_create(struct cmd_context *cmd,
|
||||
fi->private = tc;
|
||||
|
||||
return fi;
|
||||
|
||||
no_mem:
|
||||
if (fi)
|
||||
dbg_free(fi);
|
||||
|
||||
if (path)
|
||||
dbg_free(path);
|
||||
|
||||
if (d)
|
||||
dbg_free(path);
|
||||
|
||||
log_err("Couldn't allocate text format object.");
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -12,26 +12,29 @@
|
||||
#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 uuid_map *um,
|
||||
const char *desc);
|
||||
|
||||
#endif
|
||||
|
@@ -24,8 +24,9 @@ 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);
|
||||
int text_vg_export(FILE *fp, struct volume_group *vg, const char *desc);
|
||||
struct volume_group *text_vg_import(struct cmd_context *cmd, const char *file,
|
||||
struct uuid_map *um);
|
||||
struct uuid_map *um,
|
||||
time_t *when, char **desc);
|
||||
|
||||
#endif
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include "log.h"
|
||||
#include "uuid.h"
|
||||
#include "hash.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
|
||||
typedef int (*section_fn)(struct pool *mem,
|
||||
@@ -20,6 +21,9 @@ typedef int (*section_fn)(struct pool *mem,
|
||||
#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)
|
||||
|
||||
@@ -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'.",
|
||||
@@ -360,6 +365,14 @@ 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 +384,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,17 +410,71 @@ static int _read_lv(struct pool *mem,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_snapshot(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(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) {
|
||||
@@ -413,19 +487,20 @@ 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 cmd_context *cmd,
|
||||
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 = 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,13 +509,28 @@ static struct volume_group *_read_vg(struct pool *mem, struct config_file *cf,
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
vg->cmd = cmd;
|
||||
|
||||
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);
|
||||
@@ -493,7 +583,7 @@ 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)) {
|
||||
vgn, pv_hash, um, 0)) {
|
||||
log_err("Couldn't find all physical volumes for volume "
|
||||
"group %s.", vg->name);
|
||||
goto bad;
|
||||
@@ -501,12 +591,20 @@ static struct volume_group *_read_vg(struct pool *mem, struct config_file *cf,
|
||||
|
||||
list_init(&vg->lvs);
|
||||
if (!_read_sections("logical_volumes", _read_lv, mem, vg,
|
||||
vgn, pv_hash, um)) {
|
||||
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("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);
|
||||
|
||||
/*
|
||||
@@ -522,13 +620,30 @@ static struct volume_group *_read_vg(struct pool *mem, struct config_file *cf,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _read_desc(struct pool *mem,
|
||||
struct config_file *cf, time_t *when, char **desc)
|
||||
{
|
||||
const char *d;
|
||||
unsigned int u = 0u;
|
||||
|
||||
d = find_config_str(cf->root, "description", '/', "");
|
||||
*desc = pool_strdup(mem, d);
|
||||
|
||||
get_config_uint32(cf->root, "creation_time", '/', &u);
|
||||
*when = u;
|
||||
}
|
||||
|
||||
struct volume_group *text_vg_import(struct cmd_context *cmd,
|
||||
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,13 +654,15 @@ struct volume_group *text_vg_import(struct cmd_context *cmd,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(vg = _read_vg(cmd->mem, cf, um))) {
|
||||
if (!(vg = _read_vg(cmd, cf, um))) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
vg->cmd = cmd;
|
||||
|
||||
_read_desc(cmd->mem, cf, when, desc);
|
||||
|
||||
out:
|
||||
destroy_config_file(cf);
|
||||
return vg;
|
||||
|
119
lib/locking/external_locking.c
Normal file
119
lib/locking/external_locking.c
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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\n");
|
||||
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\n", _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\n", _lock_lib);
|
||||
dlclose(locking_module);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_verbose("Opened external locking module %s", _lock_lib);
|
||||
return init_fn(2, cf);
|
||||
}
|
256
lib/locking/file_locking.c
Normal file
256
lib/locking/file_locking.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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:
|
||||
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>
|
||||
|
||||
@@ -415,7 +416,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 +425,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)) {
|
||||
@@ -478,7 +479,7 @@ 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)) {
|
||||
stack;
|
||||
@@ -498,7 +499,7 @@ int lv_extend(struct format_instance *fi,
|
||||
uint64_t old_size = lv->size;
|
||||
|
||||
lv->le_count += extents;
|
||||
lv->size += extents * lv->vg->extent_size;
|
||||
lv->size += (uint64_t) extents * lv->vg->extent_size;
|
||||
|
||||
/* FIXME: Format1 must ensure stripes is consistent with 1st seg */
|
||||
|
||||
|
@@ -9,6 +9,9 @@
|
||||
#include "device.h"
|
||||
#include "dev-cache.h"
|
||||
#include "metadata.h"
|
||||
#include "toolcontext.h"
|
||||
#include "lvm-string.h"
|
||||
#include "uuid.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -44,12 +47,6 @@ 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;
|
||||
|
||||
@@ -169,6 +166,9 @@ struct volume_group *vg_create(struct format_instance *fi, const char *vg_name,
|
||||
vg->lv_count = 0;
|
||||
list_init(&vg->lvs);
|
||||
|
||||
vg->snapshot_count = 0;
|
||||
list_init(&vg->snapshots);
|
||||
|
||||
if (!fi->ops->vg_setup(fi, vg)) {
|
||||
log_error("Format specific setup of volume group '%s' failed.",
|
||||
vg_name);
|
||||
@@ -188,7 +188,8 @@ struct volume_group *vg_create(struct format_instance *fi, const char *vg_name,
|
||||
|
||||
struct physical_volume *pv_create(struct format_instance *fi,
|
||||
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));
|
||||
@@ -204,7 +205,7 @@ struct physical_volume *pv_create(struct format_instance *fi,
|
||||
memcpy(&pv->id, id, sizeof(*id));
|
||||
|
||||
if (!(pv->dev = dev_cache_get(name, fi->cmd->filter))) {
|
||||
log_err("Couldn't find device '%s'", name);
|
||||
log_error("%s: Couldn't find device.", name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
@@ -217,7 +218,22 @@ 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;
|
||||
}
|
||||
|
||||
@@ -225,6 +241,12 @@ struct physical_volume *pv_create(struct format_instance *fi,
|
||||
pv->pe_start = 0;
|
||||
pv->pe_count = 0;
|
||||
pv->pe_allocated = 0;
|
||||
|
||||
if (!fi->ops->pv_setup(fi, pv, NULL)) {
|
||||
log_error("%s: Format-specific setup of physical volume "
|
||||
"failed.", name);
|
||||
goto bad;
|
||||
}
|
||||
return pv;
|
||||
|
||||
bad:
|
||||
@@ -268,6 +290,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 +323,4 @@ struct physical_volume *find_pv(struct volume_group *vg, struct device *dev)
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#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 */
|
||||
|
||||
|
||||
/* Various flags */
|
||||
@@ -36,6 +37,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,9 +51,6 @@
|
||||
#define ALLOC_STRICT 0x00002000 /* LV */
|
||||
#define ALLOC_CONTIGUOUS 0x00004000 /* LV */
|
||||
|
||||
#define SNAPSHOT 0x00010000 /* LV */
|
||||
#define SNAPSHOT_ORG 0x00020000 /* LV */
|
||||
|
||||
|
||||
struct physical_volume {
|
||||
struct id id;
|
||||
@@ -93,6 +92,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 +115,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 +130,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,14 +153,10 @@ 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 {
|
||||
@@ -238,7 +246,8 @@ struct format_handler {
|
||||
*/
|
||||
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,
|
||||
uint32_t extent_size, int max_pv, int max_lv,
|
||||
@@ -265,7 +274,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 +303,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 +334,20 @@ 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);
|
||||
|
||||
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
|
||||
|
109
lib/metadata/snapshot_manip.c
Normal file
109
lib/metadata/snapshot_manip.c
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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_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);
|
||||
|
@@ -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"
|
||||
@@ -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;
|
||||
}
|
||||
@@ -224,7 +225,7 @@ 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;
|
||||
}
|
||||
|
||||
|
@@ -19,6 +19,36 @@ static unsigned char _c[] =
|
||||
static int _built_inverse;
|
||||
static unsigned char _inverse_c[256];
|
||||
|
||||
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);
|
||||
|
@@ -10,11 +10,24 @@
|
||||
#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 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,23 @@ struct list *vgcache_find(const char *vg_name)
|
||||
return &vgn->pvdevs;
|
||||
}
|
||||
|
||||
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 +78,7 @@ 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)
|
||||
{
|
||||
const char *pv_name;
|
||||
struct vgname_entry *vgn;
|
||||
@@ -67,6 +90,7 @@ 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));
|
||||
|
||||
pvdevs = &vgn->pvdevs;
|
||||
list_init(pvdevs);
|
||||
@@ -80,6 +104,17 @@ int vgcache_add_entry(const char *vg_name, struct device *dev)
|
||||
log_error("vgcache_add: VG hash insertion failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list_iterate(pvdh, pvdevs) {
|
||||
@@ -115,7 +150,7 @@ 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)
|
||||
{
|
||||
if (!_vghash && !vgcache_init())
|
||||
return 0;
|
||||
@@ -125,11 +160,11 @@ int vgcache_add(const char *vg_name, struct device *dev)
|
||||
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))
|
||||
return 0;
|
||||
|
||||
/* Always add to all_devices */
|
||||
return vgcache_add_entry(all_devices, dev);
|
||||
return vgcache_add_entry(all_devices, NULL, dev);
|
||||
}
|
||||
|
||||
void vgcache_destroy_entry(struct vgname_entry *vgn)
|
||||
@@ -147,6 +182,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 +202,68 @@ 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,13 @@
|
||||
#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 pvdev_list {
|
||||
@@ -28,9 +31,13 @@ void vgcache_destroy();
|
||||
|
||||
/* Return list of PVs in named VG */
|
||||
struct list *vgcache_find(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);
|
||||
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
|
||||
|
||||
|
@@ -28,6 +28,7 @@ SOURCES=\
|
||||
lvextend.c \
|
||||
lvm.c \
|
||||
lvmchange.c \
|
||||
lvmdiskscan.c \
|
||||
lvreduce.c \
|
||||
lvremove.c \
|
||||
lvrename.c \
|
||||
@@ -61,11 +62,10 @@ include ../make.tmpl
|
||||
|
||||
lvm: $(OBJECTS) $(top_srcdir)/lib/liblvm.a
|
||||
$(CC) -o lvm $(OBJECTS) $(LD_FLAGS) -L$(top_srcdir)/lib \
|
||||
-L$(DESTDIR)/lib -llvm -ldevmapper $(LIBS)
|
||||
-L$(DESTDIR)/lib -llvm -ldevmapper $(LIBS) -ldl -rdynamic
|
||||
|
||||
.commands: commands.h
|
||||
$(CC) -E -P -Dxx\(a\)=a commands.h 2>/dev/null | \
|
||||
grep -v help > .commands
|
||||
.commands: commands.h cmdnames.h
|
||||
$(CC) -E -P cmdnames.h | grep -v help > .commands
|
||||
|
||||
install: $(TARGETS)
|
||||
$(INSTALL) -D -o $(OWNER) -g $(GROUP) -m 555 $(STRIP) lvm \
|
||||
|
@@ -16,7 +16,6 @@
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
static struct {
|
||||
int enabled;
|
||||
char *dir;
|
||||
@@ -25,8 +24,7 @@ static struct {
|
||||
|
||||
} _archive_params;
|
||||
|
||||
int archive_init(const char *dir,
|
||||
unsigned int keep_days, unsigned int keep_min)
|
||||
int archive_init(const char *dir, unsigned int keep_days, unsigned int keep_min)
|
||||
{
|
||||
_archive_params.dir = NULL;
|
||||
|
||||
@@ -59,24 +57,38 @@ void archive_enable(int flag)
|
||||
_archive_params.enabled = flag;
|
||||
}
|
||||
|
||||
static char *_build_desc(struct pool *mem, const char *line, int before)
|
||||
{
|
||||
size_t len = strlen(line) + 32;
|
||||
char *buffer;
|
||||
|
||||
if (!(buffer = pool_zalloc(mem, strlen(line) + 32))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (snprintf(buffer, len,
|
||||
"Created %s executing '%s'",
|
||||
before ? "*before*" : "*after*", line) < 0) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static int __archive(struct volume_group *vg)
|
||||
{
|
||||
int r;
|
||||
struct format_instance *archiver;
|
||||
char *desc;
|
||||
|
||||
if (!(archiver = archive_format_create(vg->cmd,
|
||||
_archive_params.dir,
|
||||
_archive_params.keep_days,
|
||||
_archive_params.keep_number))) {
|
||||
log_error("Couldn't create archiver object.");
|
||||
if (!(desc = _build_desc(vg->cmd->mem, vg->cmd->cmd_line, 1))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(r = archiver->ops->vg_write(archiver, vg)))
|
||||
stack;
|
||||
|
||||
archiver->ops->destroy(archiver);
|
||||
return r;
|
||||
return archive_vg(vg, _archive_params.dir, desc,
|
||||
_archive_params.keep_days,
|
||||
_archive_params.keep_number);
|
||||
}
|
||||
|
||||
int archive(struct volume_group *vg)
|
||||
@@ -99,7 +111,10 @@ int archive(struct volume_group *vg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int archive_display(struct cmd_context *cmd, const char *vg_name)
|
||||
{
|
||||
return archive_list(cmd, cmd->um, _archive_params.dir, vg_name);
|
||||
}
|
||||
|
||||
static struct {
|
||||
int enabled;
|
||||
@@ -141,6 +156,12 @@ static int __backup(struct volume_group *vg)
|
||||
int r;
|
||||
struct format_instance *tf;
|
||||
char name[PATH_MAX];
|
||||
char *desc;
|
||||
|
||||
if (!(desc = _build_desc(vg->cmd->mem, vg->cmd->cmd_line, 0))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(name, sizeof(name), "%s/%s",
|
||||
_backup_params.dir, vg->name) < 0) {
|
||||
@@ -151,7 +172,7 @@ static int __backup(struct volume_group *vg)
|
||||
|
||||
log_verbose("Creating volume group backup \"%s\"", name);
|
||||
|
||||
if (!(tf = text_format_create(vg->cmd, name, the_um))) {
|
||||
if (!(tf = text_format_create(vg->cmd, name, vg->cmd->um, desc))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -202,14 +223,14 @@ int backup_remove(const char *vg_name)
|
||||
}
|
||||
|
||||
static struct volume_group *_read_vg(struct cmd_context *cmd,
|
||||
const char *vg_name, const char *file)
|
||||
const char *vg_name, const char *file)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
struct format_instance *tf;
|
||||
|
||||
if (!(tf = text_format_create(cmd, file, the_um))) {
|
||||
if (!(tf = text_format_create(cmd, file, cmd->um, cmd->cmd_line))) {
|
||||
log_error("Couldn't create text format object.");
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(vg = tf->ops->vg_read(tf, vg_name)))
|
||||
@@ -219,14 +240,15 @@ static struct volume_group *_read_vg(struct cmd_context *cmd,
|
||||
return vg;
|
||||
}
|
||||
|
||||
int backup_restore_from_file(const char *vg_name, const char *file)
|
||||
int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *file)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
|
||||
/*
|
||||
* Read in the volume group.
|
||||
*/
|
||||
if (!(vg = _read_vg(fid->cmd, vg_name, file))) {
|
||||
if (!(vg = _read_vg(cmd, vg_name, file))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -242,7 +264,7 @@ int backup_restore_from_file(const char *vg_name, const char *file)
|
||||
/*
|
||||
* Write the vg.
|
||||
*/
|
||||
if (!fid->ops->vg_write(fid, vg)) {
|
||||
if (!cmd->fid->ops->vg_write(cmd->fid, vg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -250,7 +272,7 @@ int backup_restore_from_file(const char *vg_name, const char *file)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int backup_restore(const char *vg_name)
|
||||
int backup_restore(struct cmd_context *cmd, const char *vg_name)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
|
||||
@@ -260,5 +282,5 @@ int backup_restore(const char *vg_name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return backup_restore_from_file(vg_name, path);
|
||||
return backup_restore_from_file(cmd, vg_name, path);
|
||||
}
|
||||
|
@@ -10,19 +10,21 @@
|
||||
#include "metadata.h"
|
||||
|
||||
/*
|
||||
* There are two operations that come under the
|
||||
* general area of backups. 'Archiving' occurs
|
||||
* just before a volume group configuration is
|
||||
* changed. The user may configure when archived
|
||||
* files are expired. Typically archives will be
|
||||
* stored in /etc/lvm/archive.
|
||||
* FIXME: This file is going to merge with the archiving code in
|
||||
* lib/format_text at some point.
|
||||
*/
|
||||
|
||||
/*
|
||||
* There are two operations that come under the general area of
|
||||
* backups. 'Archiving' occurs just before a volume group
|
||||
* configuration is changed. The user may configure when
|
||||
* archived files are expired. Typically archives will be stored
|
||||
* in /etc/lvm/archive.
|
||||
*
|
||||
* A 'backup' is a redundant copy of the *current*
|
||||
* volume group configuration. As such it should
|
||||
* be taken just after the volume group is
|
||||
* changed. Only 1 backup file will exist.
|
||||
* Typically backups will be stored in
|
||||
* /etc/lvm/backups.
|
||||
* A 'backup' is a redundant copy of the *current* volume group
|
||||
* configuration. As such it should be taken just after the
|
||||
* volume group is changed. Only 1 backup file will exist.
|
||||
* Typically backups will be stored in /etc/lvm/backups.
|
||||
*/
|
||||
|
||||
int archive_init(const char *dir,
|
||||
@@ -31,6 +33,7 @@ void archive_exit(void);
|
||||
|
||||
void archive_enable(int flag);
|
||||
int archive(struct volume_group *vg);
|
||||
int archive_display(struct cmd_context *cmd, const char *vg_name);
|
||||
|
||||
int backup_init(const char *dir);
|
||||
void backup_exit(void);
|
||||
@@ -39,7 +42,8 @@ void backup_enable(int flag);
|
||||
int backup(struct volume_group *vg);
|
||||
int backup_remove(const char *vg_name);
|
||||
|
||||
int backup_restore_from_file(const char *vg_name, const char *file);
|
||||
int backup_restore(const char *vg_name);
|
||||
int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
|
||||
const char *file);
|
||||
int backup_restore(struct cmd_context *cmd, const char *vg_name);
|
||||
|
||||
#endif
|
||||
|
@@ -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.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
arg(version_ARG, '\0', "version", NULL)
|
||||
arg(quiet_ARG, '\0', "quiet", NULL)
|
||||
arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", size_arg)
|
||||
|
||||
/* Allow some variations */
|
||||
arg(resizable_ARG, '\0', "resizable", yes_no_arg)
|
||||
@@ -44,6 +45,8 @@ arg(lvmpartition_ARG, 'l', "lvmpartition", NULL)
|
||||
arg(list_ARG, 'l', "list", NULL)
|
||||
arg(size_ARG, 'L', "size", size_arg)
|
||||
arg(logicalextent_ARG, 'L', "logicalextent", int_arg_with_sign)
|
||||
arg(persistent_ARG, 'M', "persistent", yes_no_arg)
|
||||
arg(minor_ARG, 'm', "minor", minor_arg)
|
||||
arg(maps_ARG, 'm', "maps", NULL)
|
||||
arg(name_ARG, 'n', "name", string_arg)
|
||||
arg(oldpath_ARG, 'n', "oldpath", NULL)
|
||||
@@ -69,7 +72,6 @@ arg(allocatable_ARG, 'x', "allocatable", yes_no_arg)
|
||||
arg(resizeable_ARG, 'x', "resizeable", yes_no_arg)
|
||||
arg(yes_ARG, 'y', "yes", NULL)
|
||||
arg(zero_ARG, 'Z', "zero", yes_no_arg)
|
||||
arg(suspend_ARG, 'z', "suspend", NULL)
|
||||
|
||||
/* this should always be last */
|
||||
arg(ARG_COUNT, '-', "", NULL)
|
||||
|
4
tools/cmdnames.h
Normal file
4
tools/cmdnames.h
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
#define xx(a, b, c...) a
|
||||
|
||||
#include "commands.h"
|
@@ -53,6 +53,7 @@ xx(lvchange,
|
||||
"\t[-C/--contiguous y/n]\n"
|
||||
"\t[-d/--debug]\n"
|
||||
"\t[-h/-?/--help]\n"
|
||||
"\t[-M/--persistent y/n] [--minor minor]\n"
|
||||
"\t[-P/--partial] " "\n"
|
||||
"\t[-p/--permission r/rw]\n"
|
||||
"\t[-r/--readahead ReadAheadSectors]\n"
|
||||
@@ -60,45 +61,36 @@ xx(lvchange,
|
||||
"\t[-v/--verbose]\n"
|
||||
"\tLogicalVolume[Path] [LogicalVolume[Path]...]\n",
|
||||
|
||||
autobackup_ARG, available_ARG, contiguous_ARG, partial_ARG,
|
||||
autobackup_ARG, available_ARG, contiguous_ARG,
|
||||
minor_ARG, persistent_ARG, partial_ARG,
|
||||
permission_ARG, readahead_ARG, test_ARG)
|
||||
|
||||
xx(lvcreate,
|
||||
"Create a logical volume",
|
||||
"lvcreate " "\n"
|
||||
"\t[-A|--autobackup {y|n}] " "\n"
|
||||
"\t[-C|--contiguous {y|n}] " "\n"
|
||||
"\t[-d|--debug]" "\n"
|
||||
"\t[-h|--help] " "\n"
|
||||
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]" "\n"
|
||||
"\t{-l|--extents LogicalExtentsNumber |" "\n"
|
||||
"\t -L|--size LogicalVolumeSize[kKmMgGtT]} " "\n"
|
||||
"\t[-n|--name LogicalVolumeName]" "\n"
|
||||
"\t[-p|--permission {r|rw}] " "\n"
|
||||
"\t[-r|--readahead ReadAheadSectors]" "\n"
|
||||
"\t[-t|--test] " "\n"
|
||||
"\t[-v|--verbose] " "\n"
|
||||
"\t[-Z|--zero {y|n}] " "\n"
|
||||
"\t[--version]" "\n"
|
||||
"\tVolumeGroupName [PhysicalVolumePath...]" "\n\n"
|
||||
"lvcreate " "\n"
|
||||
"\t[-A|--autobackup {y|n}]\n"
|
||||
"\t[-c|--chunksize]\n"
|
||||
"\t[-C|--contiguous {y|n}]\n"
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-h|--help]\n"
|
||||
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
|
||||
"\t{-l|--extents LogicalExtentsNumber |\n"
|
||||
"\t -L|--size LogicalVolumeSize[kKmMgGtT]}\n"
|
||||
"\t[-M|--persistent {y|n}] [--minor minor]\n"
|
||||
"\t[-n|--name LogicalVolumeName]\n"
|
||||
"\t[-p|--permission {r|rw}]\n"
|
||||
"\t[-r|--readahead ReadAheadSectors]\n"
|
||||
"\t[-s|--snapshot]\n"
|
||||
"\t[-t|--test]\n"
|
||||
"\t[-v|--verbose]\n"
|
||||
"\t[-Z|--zero {y|n}]\n"
|
||||
"\t[--version]\n"
|
||||
"\tVolumeGroupName [PhysicalVolumePath...]\n\n",
|
||||
|
||||
,
|
||||
/*
|
||||
"lvcreate "
|
||||
"\t-s|--snapshot "
|
||||
"\t[-c|--chunksize ChunkSize]" "\n"
|
||||
"\t{-l|--extents LogicalExtentsNumber |" "\n"
|
||||
"\t -L|--size LogicalVolumeSize[kKmMgGtT]}" "\n"
|
||||
"\t-n|--name SnapshotLogicalVolumeName" "\n"
|
||||
"\t[-t|--test]" "\n"
|
||||
"\tLogicalVolume[Path] [PhysicalVolumePath...]" "\n",
|
||||
chunksize_ARG,
|
||||
snapshot_ARG,
|
||||
*/
|
||||
|
||||
autobackup_ARG, contiguous_ARG, stripes_ARG, stripesize_ARG,
|
||||
extents_ARG, size_ARG, name_ARG, permission_ARG, readahead_ARG,
|
||||
test_ARG, zero_ARG)
|
||||
autobackup_ARG, chunksize_ARG,
|
||||
contiguous_ARG, extents_ARG, minor_ARG, name_ARG,
|
||||
permission_ARG, persistent_ARG, readahead_ARG, size_ARG,
|
||||
snapshot_ARG, stripes_ARG, stripesize_ARG, test_ARG, zero_ARG)
|
||||
|
||||
xx(lvdisplay,
|
||||
"Display information about a logical volume",
|
||||
@@ -132,7 +124,7 @@ xx(lvextend,
|
||||
|
||||
xx(lvmchange,
|
||||
"With the device mapper, this is obsolete and does nothing.",
|
||||
"lvmchange\n"
|
||||
"lvmchange\n"
|
||||
"\t[-d/--debug]\n"
|
||||
"\t[-h/-?/--help]\n"
|
||||
"\t[-R/--reset]\n"
|
||||
@@ -145,8 +137,7 @@ xx(lvmdiskscan,
|
||||
"lvmdiskscan\n"
|
||||
"\t[-d/--debug]\n"
|
||||
"\t[-h/-?/--help]\n"
|
||||
"\t[-l/--lvmpartition]\n"
|
||||
"\t[-v/--verbose]\n",
|
||||
"\t[-l/--lvmpartition]\n",
|
||||
|
||||
lvmpartition_ARG)
|
||||
|
||||
@@ -262,13 +253,14 @@ xx(pvcreate,
|
||||
"\t[-f[f]|--force [--force]] " "\n"
|
||||
"\t[-h|--help] " "\n"
|
||||
"\t[-y|--yes]" "\n"
|
||||
"\t[-s|--size PhysicalVolumeSize[kKmMgGtT]" "\n"
|
||||
"\t[-t|--test] " "\n"
|
||||
"\t[-u|--uuid uuid] " "\n"
|
||||
"\t[-v|--verbose] " "\n"
|
||||
"\t[--version] " "\n"
|
||||
"\tPhysicalVolume [PhysicalVolume...]\n",
|
||||
|
||||
force_ARG, test_ARG, uuidstr_ARG, yes_ARG)
|
||||
force_ARG, test_ARG, physicalvolumesize_ARG, uuidstr_ARG, yes_ARG)
|
||||
|
||||
xx(pvdata,
|
||||
"Display the on-disk metadata for physical volume(s)",
|
||||
@@ -317,6 +309,19 @@ xx(pvmove,
|
||||
|
||||
autobackup_ARG, force_ARG, name_ARG, test_ARG)
|
||||
|
||||
xx(pvresize,
|
||||
"Resize a physical volume in use by a volume group",
|
||||
"pvmove "
|
||||
"[-A|--autobackup {y|n}] "
|
||||
"[-d|--debug] "
|
||||
"[-h|--help]\n\t"
|
||||
"[-s|--size PhysicalVolumeSize[kKmMgGtT]" "\n"
|
||||
"[-v|--verbose] "
|
||||
"[--version]\n\t"
|
||||
"\tPhysicalVolumePath [PhysicalVolumePath...]\n",
|
||||
|
||||
autobackup_ARG, physicalvolumesize_ARG)
|
||||
|
||||
xx(pvscan,
|
||||
"List all physical volumes",
|
||||
"pvscan " "\n"
|
||||
@@ -372,7 +377,7 @@ xx(vgchange,
|
||||
"\t[VolumeGroupName...]\n",
|
||||
|
||||
autobackup_ARG, available_ARG, logicalvolume_ARG, partial_ARG,
|
||||
resizeable_ARG, resizable_ARG, allocation_ARG,
|
||||
resizeable_ARG, resizable_ARG, allocation_ARG,
|
||||
test_ARG)
|
||||
|
||||
xx(vgck,
|
||||
|
176
tools/dmsetup.c
176
tools/dmsetup.c
@@ -18,6 +18,7 @@
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <linux/kdev_t.h>
|
||||
|
||||
#define LINE_SIZE 1024
|
||||
|
||||
@@ -35,23 +36,22 @@ enum {
|
||||
static int _switches[NUM_SWITCHES];
|
||||
static int _values[NUM_SWITCHES];
|
||||
|
||||
|
||||
/*
|
||||
* Commands
|
||||
*/
|
||||
static int _parse_file(struct dm_task *dmt, const char *file)
|
||||
{
|
||||
char buffer[LINE_SIZE], *ttype, *ptr, *comment;
|
||||
FILE *fp = fopen(file, "r");
|
||||
unsigned long long start, size;
|
||||
int r = 0, n, line = 0;
|
||||
char buffer[LINE_SIZE], *ttype, *ptr, *comment;
|
||||
FILE *fp = fopen(file, "r");
|
||||
unsigned long long start, size;
|
||||
int r = 0, n, line = 0;
|
||||
|
||||
if (!fp) {
|
||||
err("Couldn't open '%s' for reading", file);
|
||||
return 0;
|
||||
}
|
||||
if (!fp) {
|
||||
err("Couldn't open '%s' for reading", file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), fp)) {
|
||||
while (fgets(buffer, sizeof(buffer), fp)) {
|
||||
line++;
|
||||
|
||||
/* trim trailing space */
|
||||
@@ -62,35 +62,34 @@ static int _parse_file(struct dm_task *dmt, const char *file)
|
||||
*ptr = '\0';
|
||||
|
||||
/* trim leading space */
|
||||
for (ptr = buffer; *ptr && isspace((int) *ptr); ptr++)
|
||||
;
|
||||
for (ptr = buffer; *ptr && isspace((int) *ptr); ptr++) ;
|
||||
|
||||
if (!*ptr || *ptr == '#')
|
||||
continue;
|
||||
if (!*ptr || *ptr == '#')
|
||||
continue;
|
||||
|
||||
if (sscanf(ptr, "%llu %llu %as %n",
|
||||
&start, &size, &ttype, &n) < 3) {
|
||||
err("%s:%d Invalid format", file, line);
|
||||
goto out;
|
||||
}
|
||||
if (sscanf(ptr, "%llu %llu %as %n",
|
||||
&start, &size, &ttype, &n) < 3) {
|
||||
err("%s:%d Invalid format", file, line);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ptr += n;
|
||||
if ((comment = strchr(ptr, (int) '#')))
|
||||
*comment = '\0';
|
||||
|
||||
if (!dm_task_add_target(dmt, start, size, ttype, ptr))
|
||||
goto out;
|
||||
if (!dm_task_add_target(dmt, start, size, ttype, ptr))
|
||||
goto out;
|
||||
|
||||
free(ttype);
|
||||
}
|
||||
r = 1;
|
||||
}
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
fclose(fp);
|
||||
return r;
|
||||
out:
|
||||
fclose(fp);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _load(int task, const char *name, const char *file)
|
||||
static int _load(int task, const char *name, const char *file, const char *uuid)
|
||||
{
|
||||
int r = 0;
|
||||
struct dm_task *dmt;
|
||||
@@ -101,6 +100,9 @@ static int _load(int task, const char *name, const char *file)
|
||||
if (!dm_task_set_name(dmt, name))
|
||||
goto out;
|
||||
|
||||
if (uuid && !dm_task_set_uuid(dmt, uuid))
|
||||
goto out;
|
||||
|
||||
if (!_parse_file(dmt, file))
|
||||
goto out;
|
||||
|
||||
@@ -115,7 +117,7 @@ static int _load(int task, const char *name, const char *file)
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
return r;
|
||||
@@ -123,12 +125,12 @@ out:
|
||||
|
||||
static int _create(int argc, char **argv)
|
||||
{
|
||||
return _load(DM_DEVICE_CREATE, argv[1], argv[2]);
|
||||
return _load(DM_DEVICE_CREATE, argv[1], argv[2], argv[3]);
|
||||
}
|
||||
|
||||
static int _reload(int argc, char **argv)
|
||||
{
|
||||
return _load(DM_DEVICE_RELOAD, argv[1], argv[2]);
|
||||
return _load(DM_DEVICE_RELOAD, argv[1], argv[2], NULL);
|
||||
}
|
||||
|
||||
static int _rename(int argc, char **argv)
|
||||
@@ -136,24 +138,24 @@ static int _rename(int argc, char **argv)
|
||||
int r = 0;
|
||||
struct dm_task *dmt;
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
|
||||
return 0;
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_RENAME)))
|
||||
return 0;
|
||||
|
||||
if (!dm_task_set_name(dmt, argv[1]))
|
||||
goto out;
|
||||
if (!dm_task_set_name(dmt, argv[1]))
|
||||
goto out;
|
||||
|
||||
if (!dm_task_set_newname(dmt, argv[2]))
|
||||
goto out;
|
||||
|
||||
if (!dm_task_run(dmt))
|
||||
goto out;
|
||||
if (!dm_task_run(dmt))
|
||||
goto out;
|
||||
|
||||
r = 1;
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
return r;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _version(int argc, char **argv)
|
||||
@@ -171,7 +173,7 @@ static int _version(int argc, char **argv)
|
||||
if (!dm_task_run(dmt))
|
||||
goto out;
|
||||
|
||||
if (!dm_task_get_driver_version(dmt, (char *)&version,
|
||||
if (!dm_task_get_driver_version(dmt, (char *) &version,
|
||||
sizeof(version)))
|
||||
goto out;
|
||||
|
||||
@@ -200,11 +202,16 @@ static int _simple(int task, const char *name)
|
||||
|
||||
r = dm_task_run(dmt);
|
||||
|
||||
out:
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _remove_all(int argc, char **argv)
|
||||
{
|
||||
return _simple(DM_DEVICE_REMOVE_ALL, "");
|
||||
}
|
||||
|
||||
static int _remove(int argc, char **argv)
|
||||
{
|
||||
return _simple(DM_DEVICE_REMOVE, argv[1]);
|
||||
@@ -223,6 +230,7 @@ static int _resume(int argc, char **argv)
|
||||
static int _info(int argc, char **argv)
|
||||
{
|
||||
int r = 0;
|
||||
const char *uuid;
|
||||
|
||||
/* remove <dev_name> */
|
||||
struct dm_task *dmt;
|
||||
@@ -246,6 +254,8 @@ static int _info(int argc, char **argv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
printf("Name: %s\n", argv[1]);
|
||||
|
||||
printf("State: %s\n",
|
||||
info.suspended ? "SUSPENDED" : "ACTIVE");
|
||||
|
||||
@@ -257,46 +267,95 @@ static int _info(int argc, char **argv)
|
||||
if (info.target_count != -1)
|
||||
printf("Number of targets: %d\n", info.target_count);
|
||||
|
||||
if ((uuid = dm_task_get_uuid(dmt)) && *uuid)
|
||||
printf("UUID: %s\n", uuid);
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _deps(int argc, char **argv)
|
||||
{
|
||||
int r = 0, i;
|
||||
struct dm_deps *deps;
|
||||
|
||||
/* remove <dev_name> */
|
||||
struct dm_task *dmt;
|
||||
struct dm_info info;
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
|
||||
return 0;
|
||||
|
||||
if (!dm_task_set_name(dmt, argv[1]))
|
||||
goto out;
|
||||
|
||||
if (!dm_task_run(dmt))
|
||||
goto out;
|
||||
|
||||
if (!dm_task_get_info(dmt, &info))
|
||||
goto out;
|
||||
|
||||
if (!(deps = dm_task_get_deps(dmt)))
|
||||
goto out;
|
||||
|
||||
if (!info.exists) {
|
||||
printf("Device does not exist.\n");
|
||||
r = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
printf("%d dependencies\t:", deps->count);
|
||||
|
||||
for (i = 0; i < deps->count; i++)
|
||||
printf(" (%d, %d)",
|
||||
(int) MAJOR(deps->device[i]),
|
||||
(int) MINOR(deps->device[i]));
|
||||
printf("\n");
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* dispatch table
|
||||
*/
|
||||
typedef int (*command_fn)(int argc, char **argv);
|
||||
typedef int (*command_fn) (int argc, char **argv);
|
||||
|
||||
struct command {
|
||||
char *name;
|
||||
char *help;
|
||||
int num_args;
|
||||
int min_args;
|
||||
int max_args;
|
||||
command_fn fn;
|
||||
};
|
||||
|
||||
static struct command _commands[] = {
|
||||
{"create", "<dev_name> <table_file>", 2, _create},
|
||||
{"remove", "<dev_name>", 1, _remove},
|
||||
{"suspend", "<dev_name>", 1, _suspend},
|
||||
{"resume", "<dev_name>", 1, _resume},
|
||||
{"reload", "<dev_name> <table_file>", 2, _reload},
|
||||
{"info", "<dev_name>", 1, _info},
|
||||
{"rename", "<dev_name> <new_name>", 2, _rename},
|
||||
{"version", "", 0, _version},
|
||||
{NULL, NULL, 0, NULL}
|
||||
{"create", "<dev_name> <table_file> [<uuid>]", 2, 3, _create},
|
||||
{"remove", "<dev_name>", 1, 1, _remove},
|
||||
{"remove_all", "", 0, 0, _remove_all},
|
||||
{"suspend", "<dev_name>", 1, 1, _suspend},
|
||||
{"resume", "<dev_name>", 1, 1, _resume},
|
||||
{"reload", "<dev_name> <table_file>", 2, 2, _reload},
|
||||
{"info", "<dev_name>", 1, 1, _info},
|
||||
{"deps", "<dev_name>", 1, 1, _deps},
|
||||
{"rename", "<dev_name> <new_name>", 2, 2, _rename},
|
||||
{"version", "", 0, 0, _version},
|
||||
{NULL, NULL, 0, 0, NULL}
|
||||
};
|
||||
|
||||
static void _usage(FILE *out)
|
||||
static void _usage(FILE * out)
|
||||
{
|
||||
int i;
|
||||
|
||||
fprintf(out, "usage:\n");
|
||||
for (i = 0; _commands[i].name; i++)
|
||||
fprintf(out, "\t%s %s\n",
|
||||
_commands[i].name, _commands[i].help);
|
||||
fprintf(out, "\t%s %s\n", _commands[i].name, _commands[i].help);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -363,7 +422,7 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (argc != c->num_args + 1) {
|
||||
if (argc < c->min_args + 1 || argc > c->max_args + 1) {
|
||||
fprintf(stderr, "Incorrect number of arguments\n");
|
||||
_usage(stderr);
|
||||
exit(1);
|
||||
@@ -376,4 +435,3 @@ int main(int argc, char **argv)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software
|
||||
*
|
||||
* LVM 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, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* LVM 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 LVM; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#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
|
||||
|
248
tools/lvchange.c
248
tools/lvchange.c
@@ -20,17 +20,24 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
static int lvchange_single(struct logical_volume *lv);
|
||||
static int lvchange_permission(struct logical_volume *lv);
|
||||
static int lvchange_availability(struct logical_volume *lv);
|
||||
static int lvchange_contiguous(struct logical_volume *lv);
|
||||
static int lvchange_readahead(struct logical_volume *lv);
|
||||
static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv);
|
||||
static int lvchange_permission(struct cmd_context *cmd,
|
||||
struct logical_volume *lv);
|
||||
static int lvchange_availability(struct cmd_context *cmd,
|
||||
struct logical_volume *lv);
|
||||
static int lvchange_contiguous(struct cmd_context *cmd,
|
||||
struct logical_volume *lv);
|
||||
static int lvchange_readahead(struct cmd_context *cmd,
|
||||
struct logical_volume *lv);
|
||||
static int lvchange_persistent(struct cmd_context *cmd,
|
||||
struct logical_volume *lv);
|
||||
|
||||
int lvchange(int argc, char **argv)
|
||||
int lvchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
if (!arg_count(available_ARG) && !arg_count(contiguous_ARG)
|
||||
&& !arg_count(permission_ARG) && !arg_count(readahead_ARG)) {
|
||||
log_error("One or more of -a, -C, -p or -r required");
|
||||
if (!arg_count(cmd, available_ARG) && !arg_count(cmd, contiguous_ARG)
|
||||
&& !arg_count(cmd, permission_ARG) && !arg_count(cmd, readahead_ARG)
|
||||
&& !arg_count(cmd, minor_ARG) && !arg_count(cmd, persistent_ARG)) {
|
||||
log_error("One or more of -a, -C, -m, -M, -p or -r required");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
@@ -39,154 +46,168 @@ int lvchange(int argc, char **argv)
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
return process_each_lv(argc, argv, &lvchange_single);
|
||||
if (arg_count(cmd, minor_ARG) && argc != 1) {
|
||||
log_error("Only give one logical volume when specifying minor");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
return process_each_lv(cmd, argc, argv, LCK_VG_WRITE, &lvchange_single);
|
||||
}
|
||||
|
||||
static int lvchange_single(struct logical_volume *lv)
|
||||
static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
int doit = 0;
|
||||
int archived = 0;
|
||||
|
||||
if (!(lv->vg->status & LVM_WRITE) &&
|
||||
(arg_count(contiguous_ARG) || arg_count(permission_ARG) ||
|
||||
arg_count(readahead_ARG))) {
|
||||
log_error("Only -a permitted with read-only volume group \"%s\"",
|
||||
lv->vg->name);
|
||||
if (!(lv->vg->status & LVM_WRITE) &&
|
||||
(arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
|
||||
arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) {
|
||||
log_error("Only -a permitted with read-only volume "
|
||||
"group \"%s\"", lv->vg->name);
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (lv->status & SNAPSHOT_ORG) {
|
||||
if (lv_is_origin(lv) &&
|
||||
(arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
|
||||
arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) {
|
||||
log_error("Can't change logical volume \"%s\" under snapshot",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (lv->status & SNAPSHOT) {
|
||||
log_error("Can't change snapshot logical volume \"%s\"", lv->name);
|
||||
if (lv_is_cow(lv)) {
|
||||
log_error("Can't change snapshot logical volume \"%s\"",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
/* access permission change */
|
||||
if (arg_count(permission_ARG)) {
|
||||
if (arg_count(cmd, permission_ARG)) {
|
||||
if (!archive(lv->vg))
|
||||
return ECMD_FAILED;
|
||||
archived = 1;
|
||||
doit += lvchange_permission(lv);
|
||||
doit += lvchange_permission(cmd, lv);
|
||||
}
|
||||
|
||||
/* allocation policy change */
|
||||
if (arg_count(contiguous_ARG)) {
|
||||
if (arg_count(cmd, contiguous_ARG)) {
|
||||
if (!archived && !archive(lv->vg))
|
||||
return ECMD_FAILED;
|
||||
archived = 1;
|
||||
doit += lvchange_contiguous(lv);
|
||||
doit += lvchange_contiguous(cmd, lv);
|
||||
}
|
||||
|
||||
/* read ahead sector change */
|
||||
if (arg_count(readahead_ARG)) {
|
||||
if (arg_count(cmd, readahead_ARG)) {
|
||||
if (!archived && !archive(lv->vg))
|
||||
return ECMD_FAILED;
|
||||
archived = 1;
|
||||
doit += lvchange_readahead(lv);
|
||||
doit += lvchange_readahead(cmd, lv);
|
||||
}
|
||||
|
||||
/* read ahead sector change */
|
||||
if (arg_count(cmd, persistent_ARG)) {
|
||||
if (!archived && !archive(lv->vg))
|
||||
return ECMD_FAILED;
|
||||
archived = 1;
|
||||
doit += lvchange_persistent(cmd, lv);
|
||||
}
|
||||
|
||||
if (doit)
|
||||
log_print("Logical volume \"%s\" changed", lv->name);
|
||||
|
||||
/* availability change */
|
||||
if (arg_count(available_ARG))
|
||||
if (!lvchange_availability(lv))
|
||||
if (arg_count(cmd, available_ARG))
|
||||
if (!lvchange_availability(cmd, lv))
|
||||
return ECMD_FAILED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lvchange_permission(struct logical_volume *lv)
|
||||
static int lvchange_permission(struct cmd_context *cmd,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
int lv_access;
|
||||
|
||||
lv_access = arg_int_value(permission_ARG, 0);
|
||||
lv_access = arg_int_value(cmd, permission_ARG, 0);
|
||||
|
||||
if ((lv_access & LVM_WRITE) && (lv->status & LVM_WRITE)) {
|
||||
log_error("Logical volume \"%s\" is already writable", lv->name);
|
||||
log_error("Logical volume \"%s\" is already writable",
|
||||
lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(lv_access & LVM_WRITE) && !(lv->status & LVM_WRITE)) {
|
||||
log_error("Logical volume \"%s\" is already read only", lv->name);
|
||||
log_error("Logical volume \"%s\" is already read only",
|
||||
lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_access & LVM_WRITE) {
|
||||
lv->status |= LVM_WRITE;
|
||||
log_verbose("Setting logical volume \"%s\" read/write", lv->name);
|
||||
log_verbose("Setting logical volume \"%s\" read/write",
|
||||
lv->name);
|
||||
} else {
|
||||
lv->status &= ~LVM_WRITE;
|
||||
log_verbose("Setting logical volume \"%s\" read-only", lv->name);
|
||||
log_verbose("Setting logical volume \"%s\" read-only",
|
||||
lv->name);
|
||||
}
|
||||
|
||||
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) {
|
||||
log_error("Failed to lock %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
|
||||
if (!fid->ops->vg_write(fid, lv->vg))
|
||||
if (!cmd->fid->ops->vg_write(cmd->fid, lv->vg)) {
|
||||
/* FIXME: Attempt reversion? */
|
||||
unlock_lv(cmd, lv->lvid.s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
backup(lv->vg);
|
||||
|
||||
log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name);
|
||||
if (!lv_update_write_access(lv))
|
||||
return 0;
|
||||
if (!unlock_lv(cmd, lv->lvid.s)) {
|
||||
log_error("Problem reactivating %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lvchange_availability(struct logical_volume *lv)
|
||||
static int lvchange_availability(struct cmd_context *cmd,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
int activate = 0;
|
||||
int active;
|
||||
|
||||
if (strcmp(arg_str_value(available_ARG, "n"), "n"))
|
||||
if (strcmp(arg_str_value(cmd, available_ARG, "n"), "n"))
|
||||
activate = 1;
|
||||
|
||||
if ((active = lv_active(lv)) < 0) {
|
||||
log_error("Unable to determine status of \"%s\"", lv->name);
|
||||
return 0;
|
||||
if (arg_count(cmd, minor_ARG)) {
|
||||
lv->minor = arg_int_value(cmd, minor_ARG, -1);
|
||||
}
|
||||
|
||||
if (activate && active) {
|
||||
log_verbose("Logical volume \"%s\" is already active", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!activate && !active) {
|
||||
log_verbose("Logical volume \"%s\" is already inactive", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (activate & lv_suspended(lv)) {
|
||||
log_verbose("Reactivating logical volume \"%s\"", lv->name);
|
||||
if (!lv_reactivate(lv))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (activate) {
|
||||
/* FIXME Tighter locking if lv_is_origin() */
|
||||
log_verbose("Activating logical volume \"%s\"", lv->name);
|
||||
if (!lv_activate(lv))
|
||||
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_ACTIVATE))
|
||||
return 0;
|
||||
} else {
|
||||
log_verbose("Deactivating logical volume \"%s\"", lv->name);
|
||||
if (!lv_deactivate(lv))
|
||||
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_DEACTIVATE))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lvchange_contiguous(struct logical_volume *lv)
|
||||
static int lvchange_contiguous(struct cmd_context *cmd,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
int lv_allocation = 0;
|
||||
|
||||
if (strcmp(arg_str_value(contiguous_ARG, "n"), "n"))
|
||||
if (strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n"))
|
||||
lv_allocation |= ALLOC_CONTIGUOUS;
|
||||
|
||||
if ((lv_allocation & ALLOC_CONTIGUOUS) &&
|
||||
@@ -198,8 +219,9 @@ static int lvchange_contiguous(struct logical_volume *lv)
|
||||
|
||||
if (!(lv_allocation & ALLOC_CONTIGUOUS) &&
|
||||
!(lv->status & ALLOC_CONTIGUOUS)) {
|
||||
log_error("Allocation policy of logical volume \"%s\" is already"
|
||||
" not contiguous", lv->name);
|
||||
log_error
|
||||
("Allocation policy of logical volume \"%s\" is already"
|
||||
" not contiguous", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -220,21 +242,35 @@ static int lvchange_contiguous(struct logical_volume *lv)
|
||||
lv->name);
|
||||
}
|
||||
|
||||
log_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
|
||||
|
||||
if (!fid->ops->vg_write(fid, lv->vg))
|
||||
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) {
|
||||
log_error("Failed to lock %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
|
||||
if (!cmd->fid->ops->vg_write(cmd->fid, lv->vg)) {
|
||||
/* FIXME: Attempt reversion? */
|
||||
unlock_lv(cmd, lv->lvid.s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
backup(lv->vg);
|
||||
|
||||
if (!unlock_lv(cmd, lv->lvid.s)) {
|
||||
log_error("Problem reactivating %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
static int lvchange_readahead(struct logical_volume *lv)
|
||||
static int lvchange_readahead(struct cmd_context *cmd,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
int read_ahead = 0;
|
||||
|
||||
read_ahead = arg_int_value(readahead_ARG, 0);
|
||||
read_ahead = arg_int_value(cmd, readahead_ARG, 0);
|
||||
|
||||
/******* FIXME Ranges?
|
||||
if (read_ahead < LVM_MIN_READ_AHEAD || read_ahead > LVM_MAX_READ_AHEAD) {
|
||||
@@ -250,14 +286,80 @@ static int lvchange_readahead(struct logical_volume *lv)
|
||||
}
|
||||
|
||||
lv->read_ahead = read_ahead;
|
||||
log_verbose("Setting read ahead to %u for \"%s\"", read_ahead, lv->name);
|
||||
|
||||
log_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
|
||||
log_verbose("Setting read ahead to %u for \"%s\"", read_ahead,
|
||||
lv->name);
|
||||
|
||||
if (!fid->ops->vg_write(fid, lv->vg))
|
||||
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) {
|
||||
log_error("Failed to lock %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
|
||||
if (!cmd->fid->ops->vg_write(cmd->fid, lv->vg)) {
|
||||
/* FIXME: Attempt reversion? */
|
||||
unlock_lv(cmd, lv->lvid.s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
backup(lv->vg);
|
||||
|
||||
if (!unlock_lv(cmd, lv->lvid.s)) {
|
||||
log_error("Problem reactivating %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lvchange_persistent(struct cmd_context *cmd,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
|
||||
if (!strcmp(arg_str_value(cmd, persistent_ARG, "n"), "n")) {
|
||||
if (!(lv->status & FIXED_MINOR)) {
|
||||
log_error("Minor number is already not persistent "
|
||||
"for \"%s\"", lv->name);
|
||||
return 0;
|
||||
}
|
||||
lv->status &= ~FIXED_MINOR;
|
||||
lv->minor = -1;
|
||||
log_verbose("Disabling persistent minor for \"%s\"", lv->name);
|
||||
} else {
|
||||
if (!arg_count(cmd, minor_ARG)) {
|
||||
log_error("Minor number must be specified with -My");
|
||||
return 0;
|
||||
}
|
||||
log_verbose("Ensuring %s is inactive. Reactivate with -ay.",
|
||||
lv->name);
|
||||
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_DEACTIVATE)) {
|
||||
log_error("%s: deactivation failed", lv->name);
|
||||
return 0;
|
||||
}
|
||||
lv->status |= FIXED_MINOR;
|
||||
lv->minor = arg_int_value(cmd, minor_ARG, -1);
|
||||
log_verbose("Setting persistent minor number to %d for \"%s\"",
|
||||
lv->minor, lv->name);
|
||||
}
|
||||
|
||||
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) {
|
||||
log_error("Failed to lock %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
|
||||
if (!cmd->fid->ops->vg_write(cmd->fid, lv->vg)) {
|
||||
/* FIXME: Attempt reversion? */
|
||||
unlock_lv(cmd, lv->lvid.s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
backup(lv->vg);
|
||||
|
||||
if (!unlock_lv(cmd, lv->lvid.s)) {
|
||||
log_error("Problem reactivating %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
606
tools/lvcreate.c
606
tools/lvcreate.c
@@ -9,250 +9,470 @@
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
int lvcreate(int argc, char **argv)
|
||||
{
|
||||
struct lvcreate_params {
|
||||
/* flags */
|
||||
int snapshot;
|
||||
int zero;
|
||||
uint32_t read_ahead = 0;
|
||||
int stripes = 1;
|
||||
int stripesize = 0;
|
||||
int contiguous;
|
||||
int minor;
|
||||
|
||||
int opt = 0;
|
||||
uint32_t status = 0;
|
||||
uint32_t size = 0;
|
||||
uint32_t size_rest;
|
||||
uint32_t extents = 0;
|
||||
struct volume_group *vg;
|
||||
struct logical_volume *lv;
|
||||
struct list *pvh;
|
||||
char *lv_name = NULL;
|
||||
char *origin;
|
||||
char *vg_name;
|
||||
char *st;
|
||||
char *lv_name;
|
||||
|
||||
if (arg_count(snapshot_ARG) || arg_count(chunksize_ARG)) {
|
||||
log_error("Snapshots are not yet supported in LVM2.");
|
||||
return EINVALID_CMD_LINE;
|
||||
uint32_t stripes;
|
||||
uint32_t stripe_size;
|
||||
uint32_t chunk_size;
|
||||
|
||||
/* size */
|
||||
uint32_t extents;
|
||||
uint64_t size;
|
||||
|
||||
uint32_t permission;
|
||||
uint32_t read_ahead;
|
||||
|
||||
int pv_count;
|
||||
char **pvs;
|
||||
};
|
||||
|
||||
static int _read_name_params(struct lvcreate_params *lp,
|
||||
struct cmd_context *cmd, int *pargc,
|
||||
char ***pargv)
|
||||
{
|
||||
int argc = *pargc;
|
||||
char **argv = *pargv, *ptr;
|
||||
|
||||
if (arg_count(cmd, name_ARG))
|
||||
lp->lv_name = arg_value(cmd, name_ARG);
|
||||
|
||||
if (arg_count(cmd, snapshot_ARG)) {
|
||||
lp->snapshot = 1;
|
||||
|
||||
if (!argc) {
|
||||
log_err("Please specify a logical volume to act as "
|
||||
"the snapshot origin.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lp->origin = argv[0];
|
||||
(*pargv)++, (*pargc)--;
|
||||
if (!(lp->vg_name = extract_vgname(cmd->fid, lp->origin))) {
|
||||
log_err("The origin name should include the "
|
||||
"volume group.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Strip the volume group from the origin */
|
||||
if ((ptr = strrchr(lp->origin, (int) '/')))
|
||||
lp->origin = ptr + 1;
|
||||
|
||||
} else {
|
||||
/*
|
||||
* If VG not on command line, try -n arg and then
|
||||
* environment.
|
||||
*/
|
||||
if (!argc) {
|
||||
if (!(lp->vg_name =
|
||||
extract_vgname(cmd->fid, lp->lv_name))) {
|
||||
log_err("Please provide a volume group name");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Ensure lv_name doesn't contain a
|
||||
* different VG.
|
||||
*/
|
||||
if (lp->lv_name && strchr(lp->lv_name, '/')) {
|
||||
if (!(lp->vg_name =
|
||||
extract_vgname(cmd->fid, lp->lv_name)))
|
||||
return 0;
|
||||
|
||||
if (strcmp(lp->vg_name, argv[0])) {
|
||||
log_error("Inconsistent volume group "
|
||||
"names "
|
||||
"given: \"%s\" and \"%s\"",
|
||||
lp->vg_name, argv[0]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
lp->vg_name = argv[0];
|
||||
(*pargv)++, (*pargc)--;
|
||||
}
|
||||
}
|
||||
|
||||
/* mutually exclusive */
|
||||
if ((arg_count(zero_ARG) && arg_count(snapshot_ARG)) ||
|
||||
(arg_count(extents_ARG) && arg_count(size_ARG))) {
|
||||
if (lp->lv_name && (ptr = strrchr(lp->lv_name, '/')))
|
||||
lp->lv_name = ptr + 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_size_params(struct lvcreate_params *lp,
|
||||
struct cmd_context *cmd, int *pargc,
|
||||
char ***pargv)
|
||||
{
|
||||
/*
|
||||
* There are two mutually exclusive ways of specifying
|
||||
* the size ...
|
||||
*/
|
||||
if (arg_count(cmd, extents_ARG) && arg_count(cmd, size_ARG)) {
|
||||
log_error("Invalid combination of arguments");
|
||||
return EINVALID_CMD_LINE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg_count(size_ARG) + arg_count(extents_ARG) == 0) {
|
||||
/*
|
||||
* ... you must use one of them.
|
||||
*/
|
||||
if (arg_count(cmd, size_ARG) + arg_count(cmd, extents_ARG) == 0) {
|
||||
log_error("Please indicate size using option -l or -L");
|
||||
return EINVALID_CMD_LINE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(arg_str_value(contiguous_ARG, "n"), "n"))
|
||||
if (arg_count(cmd, extents_ARG))
|
||||
lp->extents = arg_int_value(cmd, extents_ARG, 0);
|
||||
|
||||
/* Size returned in kilobyte units; held in sectors */
|
||||
if (arg_count(cmd, size_ARG))
|
||||
lp->size = arg_int64_value(cmd, size_ARG, 0) * 2ull;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_stripe_params(struct lvcreate_params *lp,
|
||||
struct cmd_context *cmd,
|
||||
int *pargc, char ***pargv)
|
||||
{
|
||||
int argc = *pargc;
|
||||
|
||||
lp->stripes = 1;
|
||||
|
||||
if (arg_count(cmd, stripes_ARG)) {
|
||||
lp->stripes = arg_int_value(cmd, stripes_ARG, 1);
|
||||
if (lp->stripes == 1)
|
||||
log_print("Redundant stripes argument: default is 1");
|
||||
}
|
||||
|
||||
if (arg_count(cmd, stripesize_ARG))
|
||||
lp->stripe_size = 2 * arg_int_value(cmd, stripesize_ARG, 0);
|
||||
|
||||
if (lp->stripes == 1 && lp->stripe_size) {
|
||||
log_print("Ignoring stripesize argument with single stripe");
|
||||
lp->stripe_size = 0;
|
||||
}
|
||||
|
||||
if (lp->stripes > 1 && !lp->stripe_size) {
|
||||
lp->stripe_size = 2 * STRIPE_SIZE_DEFAULT;
|
||||
log_print("Using default stripesize %dKB", lp->stripe_size / 2);
|
||||
}
|
||||
|
||||
if (argc && argc < lp->stripes) {
|
||||
log_error("Too few physical volumes on "
|
||||
"command line for %d-way striping", lp->stripes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lp->stripes < 1 || lp->stripes > MAX_STRIPES) {
|
||||
log_error("Number of stripes (%d) must be between %d and %d",
|
||||
lp->stripes, 1, MAX_STRIPES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lp->stripes > 1 && (lp->stripe_size < STRIPE_SIZE_MIN ||
|
||||
lp->stripe_size > STRIPE_SIZE_MAX ||
|
||||
lp->stripe_size & (lp->stripe_size - 1))) {
|
||||
log_error("Invalid stripe size %d", lp->stripe_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd,
|
||||
int argc, char **argv)
|
||||
{
|
||||
/*
|
||||
* Set the defaults.
|
||||
*/
|
||||
memset(lp, 0, sizeof(*lp));
|
||||
lp->chunk_size = 2 * arg_int_value(cmd, chunksize_ARG, 32);
|
||||
log_verbose("setting chunksize to %d sectors.", lp->chunk_size);
|
||||
|
||||
if (!_read_name_params(lp, cmd, &argc, &argv) ||
|
||||
!_read_size_params(lp, cmd, &argc, &argv) ||
|
||||
!_read_stripe_params(lp, cmd, &argc, &argv))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Should we zero the lv.
|
||||
*/
|
||||
lp->zero = strcmp(arg_str_value(cmd, zero_ARG, "y"), "n");
|
||||
|
||||
/*
|
||||
* Contiguous ?
|
||||
*/
|
||||
lp->contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n");
|
||||
|
||||
/*
|
||||
* Read ahead.
|
||||
*/
|
||||
if (arg_count(cmd, readahead_ARG))
|
||||
lp->read_ahead = arg_int_value(cmd, readahead_ARG, 0);
|
||||
|
||||
/*
|
||||
* Permissions.
|
||||
*/
|
||||
if (arg_count(cmd, permission_ARG))
|
||||
lp->permission = arg_int_value(cmd, permission_ARG, 0);
|
||||
else
|
||||
lp->permission = LVM_READ | LVM_WRITE;
|
||||
|
||||
lp->minor = arg_int_value(cmd, minor_ARG, -1);
|
||||
|
||||
/* Persistent minor */
|
||||
if (arg_count(cmd, persistent_ARG)) {
|
||||
if (!strcmp(arg_str_value(cmd, persistent_ARG, "n"), "y")) {
|
||||
if (lp->minor == -1) {
|
||||
log_error("Please specify minor number with "
|
||||
"--minor when using -My");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (lp->minor != -1) {
|
||||
log_error("--minor not possible with -Mn");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lp->pv_count = argc;
|
||||
lp->pvs = argv;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Volumes may be zeroed to remove old application data.
|
||||
*/
|
||||
static int _zero_lv(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
struct device *dev;
|
||||
char *name;
|
||||
|
||||
/*
|
||||
* FIXME:
|
||||
* <clausen> also, more than 4k
|
||||
* <clausen> say, reiserfs puts it's superblock 32k in, IIRC
|
||||
* <ejt_> k, I'll drop a fixme to that effect
|
||||
* (I know the device is at least 4k, but not 32k)
|
||||
*/
|
||||
if (!(name = pool_alloc(cmd->mem, PATH_MAX))) {
|
||||
log_error("Name allocation failed - device not zeroed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(name, PATH_MAX, "%s%s/%s", cmd->dev_dir,
|
||||
lv->vg->name, lv->name) < 0) {
|
||||
log_error("Name too long - device not zeroed (%s)", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_verbose("Zeroing start of logical volume \"%s\"", lv->name);
|
||||
|
||||
if (!(dev = dev_cache_get(name, NULL))) {
|
||||
log_error("%s: not found: device not zeroed", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(dev_open(dev, O_WRONLY)))
|
||||
return 0;
|
||||
|
||||
dev_zero(dev, 0, 4096);
|
||||
dev_close(dev);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
{
|
||||
uint32_t size_rest;
|
||||
uint32_t status = 0;
|
||||
struct volume_group *vg;
|
||||
struct logical_volume *lv, *org;
|
||||
struct list *pvh;
|
||||
|
||||
if (lp->contiguous)
|
||||
status |= ALLOC_CONTIGUOUS;
|
||||
else
|
||||
status |= ALLOC_SIMPLE;
|
||||
|
||||
zero = strcmp(arg_str_value(zero_ARG, "y"), "n");
|
||||
|
||||
if (arg_count(stripes_ARG)) {
|
||||
stripes = arg_int_value(stripes_ARG, 1);
|
||||
if (stripes == 1)
|
||||
log_print("Redundant stripes argument: default is 1");
|
||||
}
|
||||
|
||||
if (arg_count(stripesize_ARG))
|
||||
stripesize = 2 * arg_int_value(stripesize_ARG, 0);
|
||||
|
||||
if (stripes == 1 && stripesize) {
|
||||
log_print("Ignoring stripesize argument with single stripe");
|
||||
stripesize = 0;
|
||||
}
|
||||
|
||||
if (stripes > 1 && !stripesize) {
|
||||
stripesize = 2 * STRIPE_SIZE_DEFAULT;
|
||||
log_print("Using default stripesize %dKB", stripesize / 2);
|
||||
}
|
||||
|
||||
if (arg_count(permission_ARG))
|
||||
status |= arg_int_value(permission_ARG, 0);
|
||||
else
|
||||
status |= LVM_READ | LVM_WRITE;
|
||||
|
||||
if (arg_count(readahead_ARG))
|
||||
read_ahead = arg_int_value(readahead_ARG, 0);
|
||||
|
||||
if (arg_count(extents_ARG))
|
||||
extents = arg_int_value(extents_ARG, 0);
|
||||
|
||||
/* Size returned in kilobyte units; held in sectors */
|
||||
if (arg_count(size_ARG))
|
||||
size = arg_int_value(size_ARG, 0);
|
||||
|
||||
if (arg_count(name_ARG))
|
||||
lv_name = arg_value(name_ARG);
|
||||
|
||||
/* If VG not on command line, try -n arg and then environment */
|
||||
if (!argc) {
|
||||
if (!(vg_name = extract_vgname(fid, lv_name))) {
|
||||
log_error("Please provide a volume group name");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Ensure lv_name doesn't contain a different VG! */
|
||||
if (lv_name && strchr(lv_name, '/')) {
|
||||
if (!(vg_name = extract_vgname(fid, lv_name)))
|
||||
return EINVALID_CMD_LINE;
|
||||
if (strcmp(vg_name, argv[0])) {
|
||||
log_error("Inconsistent volume group names "
|
||||
"given: \"%s\" and \"%s\"",
|
||||
vg_name, argv[0]);
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
}
|
||||
vg_name = argv[0];
|
||||
argv++;
|
||||
argc--;
|
||||
}
|
||||
|
||||
if (lv_name && (st = strrchr(lv_name, '/')))
|
||||
lv_name = st + 1;
|
||||
status |= lp->permission;
|
||||
|
||||
/* does VG exist? */
|
||||
log_verbose("Finding volume group \"%s\"", vg_name);
|
||||
if (!(vg = fid->ops->vg_read(fid, vg_name))) {
|
||||
log_error("Volume group \"%s\" doesn't exist", vg_name);
|
||||
return ECMD_FAILED;
|
||||
log_verbose("Finding volume group \"%s\"", lp->vg_name);
|
||||
|
||||
if (!(vg = cmd->fid->ops->vg_read(cmd->fid, lp->vg_name))) {
|
||||
log_error("Volume group \"%s\" doesn't exist", lp->vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group \"%s\" is exported", vg_name);
|
||||
return ECMD_FAILED;
|
||||
log_error("Volume group \"%s\" is exported", lp->vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(vg->status & LVM_WRITE)) {
|
||||
log_error("Volume group \"%s\" is read-only", vg_name);
|
||||
return ECMD_FAILED;
|
||||
log_error("Volume group \"%s\" is read-only", lp->vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_name && find_lv_in_vg(vg, lv_name)) {
|
||||
if (lp->lv_name && find_lv_in_vg(vg, lp->lv_name)) {
|
||||
log_error("Logical volume \"%s\" already exists in "
|
||||
"volume group \"%s\"", lv_name, vg_name);
|
||||
return ECMD_FAILED;
|
||||
"volume group \"%s\"", lp->lv_name, lp->vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!argc)
|
||||
/* Use full list from VG */
|
||||
/*
|
||||
* Create the pv list.
|
||||
*/
|
||||
if (lp->pv_count) {
|
||||
if (!(pvh = create_pv_list(cmd->mem, vg,
|
||||
lp->pv_count, lp->pvs))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
pvh = &vg->pvs;
|
||||
|
||||
else {
|
||||
if (!(pvh = create_pv_list(fid->cmd->mem, vg,
|
||||
argc - opt, argv + opt))) {
|
||||
stack;
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc && argc < stripes ) {
|
||||
log_error("Too few physical volumes on "
|
||||
"command line for %d-way striping", stripes);
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (stripes < 1 || stripes > MAX_STRIPES) {
|
||||
log_error("Number of stripes (%d) must be between %d and %d",
|
||||
stripes, 1, MAX_STRIPES);
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (stripes > 1 && (stripesize < STRIPE_SIZE_MIN ||
|
||||
stripesize > STRIPE_SIZE_MAX ||
|
||||
stripesize & (stripesize - 1))) {
|
||||
log_error("Invalid stripe size %d", stripesize);
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (stripesize > vg->extent_size) {
|
||||
if (lp->stripe_size > vg->extent_size) {
|
||||
log_error("Setting stripe size %d KB to physical extent "
|
||||
"size %u KB",
|
||||
stripesize / 2, vg->extent_size / 2);
|
||||
stripesize = vg->extent_size;
|
||||
"size %u KB", lp->stripe_size / 2,
|
||||
vg->extent_size / 2);
|
||||
lp->stripe_size = vg->extent_size;
|
||||
}
|
||||
|
||||
if (size) {
|
||||
if (lp->size) {
|
||||
/* No of 512-byte sectors */
|
||||
extents = size * 2;
|
||||
lp->extents = lp->size;
|
||||
|
||||
if (extents % vg->extent_size) {
|
||||
if (lp->extents % vg->extent_size) {
|
||||
char *s1;
|
||||
|
||||
extents += vg->extent_size - extents % vg->extent_size;
|
||||
log_print("Rounding up size to full physical extent %s",
|
||||
(s1 = display_size(extents / 2, SIZE_SHORT)));
|
||||
lp->extents += vg->extent_size - lp->extents %
|
||||
vg->extent_size;
|
||||
log_print("Rounding up size to full physical "
|
||||
"extent %s",
|
||||
(s1 = display_size(lp->extents / 2,
|
||||
SIZE_SHORT)));
|
||||
dbg_free(s1);
|
||||
}
|
||||
|
||||
extents /= vg->extent_size;
|
||||
lp->extents /= vg->extent_size;
|
||||
}
|
||||
|
||||
if ((size_rest = extents % stripes)) {
|
||||
log_print("Rounding size (%d extents) up to stripe boundary "
|
||||
"size (%d extents)", extents,
|
||||
extents - size_rest + stripes);
|
||||
extents = extents - size_rest + stripes;
|
||||
}
|
||||
if ((size_rest = lp->extents % lp->stripes)) {
|
||||
log_print("Rounding size (%d extents) up to stripe boundary "
|
||||
"size (%d extents)", lp->extents,
|
||||
lp->extents - size_rest + lp->stripes);
|
||||
lp->extents = lp->extents - size_rest + lp->stripes;
|
||||
}
|
||||
|
||||
if (lp->snapshot && !(org = find_lv(vg, lp->origin))) {
|
||||
log_err("Couldn't find origin volume '%s'.", lp->origin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(lv = lv_create(cmd->fid, lp->lv_name, status,
|
||||
lp->stripes, lp->stripe_size, lp->extents,
|
||||
vg, pvh))) return 0;
|
||||
|
||||
if (lp->read_ahead) {
|
||||
log_verbose("Setting read ahead sectors");
|
||||
lv->read_ahead = lp->read_ahead;
|
||||
}
|
||||
|
||||
if (lp->minor >= 0) {
|
||||
lv->minor = lp->minor;
|
||||
lv->status |= FIXED_MINOR;
|
||||
log_verbose("Setting minor number to %d", lv->minor);
|
||||
}
|
||||
|
||||
if (!archive(vg))
|
||||
return ECMD_FAILED;
|
||||
|
||||
if (!(lv = lv_create(fid, lv_name, status,
|
||||
stripes, stripesize, extents,
|
||||
vg, pvh)))
|
||||
return ECMD_FAILED;
|
||||
|
||||
if (arg_count(readahead_ARG)) {
|
||||
log_verbose("Setting read ahead sectors");
|
||||
lv->read_ahead = read_ahead;
|
||||
}
|
||||
return 0;
|
||||
|
||||
/* store vg on disk(s) */
|
||||
if (!fid->ops->vg_write(fid, vg))
|
||||
return ECMD_FAILED;
|
||||
if (!cmd->fid->ops->vg_write(cmd->fid, vg))
|
||||
return 0;
|
||||
|
||||
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_ACTIVATE))
|
||||
return 0;
|
||||
|
||||
if (lp->zero || lp->snapshot)
|
||||
_zero_lv(cmd, lv);
|
||||
else
|
||||
log_print("WARNING: \"%s\" not zeroed", lv->name);
|
||||
|
||||
if (lp->snapshot) {
|
||||
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_DEACTIVATE)) {
|
||||
log_err("Couldn't unlock snapshot.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lock_vol(cmd, org->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) {
|
||||
log_error("Failed to lock origin %s", org->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vg_add_snapshot(org, lv, 1, lp->chunk_size)) {
|
||||
log_err("Couldn't create snapshot.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* store vg on disk(s) */
|
||||
if (!cmd->fid->ops->vg_write(cmd->fid, vg))
|
||||
return 0;
|
||||
|
||||
if (!unlock_lv(cmd, org->lvid.s)) {
|
||||
log_error("Problem reactivating origin %s", org->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
backup(vg);
|
||||
|
||||
log_print("Logical volume \"%s\" created", lv->name);
|
||||
|
||||
if (!lv_activate(lv))
|
||||
return ECMD_FAILED;
|
||||
/*
|
||||
* FIXME: as a sanity check we could try reading the
|
||||
* last block of the device ?
|
||||
*/
|
||||
|
||||
if (zero) {
|
||||
struct device *dev;
|
||||
char *name;
|
||||
|
||||
if (!(name = pool_alloc(fid->cmd->mem, PATH_MAX))) {
|
||||
log_error("Name allocation failed - device not zeroed");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(name, PATH_MAX, "%s%s/%s", fid->cmd->dev_dir,
|
||||
lv->vg->name, lv->name) < 0) {
|
||||
log_error("Name too long - device not zeroed (%s)",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
log_verbose("Zeroing start of logical volume \"%s\"", name);
|
||||
|
||||
if (!(dev = dev_cache_get(name, NULL))) {
|
||||
log_error("\"%s\" not found: device not zeroed", name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
if (!(dev_open(dev, O_WRONLY)))
|
||||
return ECMD_FAILED;
|
||||
dev_zero(dev, 0, 4096);
|
||||
dev_close(dev);
|
||||
|
||||
} else
|
||||
log_print("WARNING: \"%s\" not zeroed", lv->name);
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lvcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
int r = ECMD_FAILED;
|
||||
struct lvcreate_params lp;
|
||||
|
||||
memset(&lp, 0, sizeof(lp));
|
||||
|
||||
if (!_read_params(&lp, cmd, argc, argv))
|
||||
return -EINVALID_CMD_LINE;
|
||||
|
||||
if (!lock_vol(cmd, lp.vg_name, LCK_VG_WRITE)) {
|
||||
log_error("Can't get lock for %s", lp.vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_lvcreate(cmd, &lp)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
out:
|
||||
unlock_vg(cmd, lp.vg_name);
|
||||
return r;
|
||||
}
|
||||
|
@@ -20,27 +20,27 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
int lvdisplay(int argc, char **argv)
|
||||
int lvdisplay_single(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
/* FIXME Allow VG args via process_each */
|
||||
|
||||
if (arg_count(colon_ARG) && arg_count(verbose_ARG)) {
|
||||
log_error("Options -v and -c are incompatible");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
return process_each_lv(argc, argv, &lvdisplay_single);
|
||||
}
|
||||
|
||||
int lvdisplay_single(struct logical_volume *lv)
|
||||
{
|
||||
if (arg_count(colon_ARG))
|
||||
if (arg_count(cmd, colon_ARG))
|
||||
lvdisplay_colons(lv);
|
||||
else {
|
||||
lvdisplay_full(lv);
|
||||
if (arg_count(maps_ARG))
|
||||
lvdisplay_full(cmd, lv);
|
||||
if (arg_count(cmd, maps_ARG))
|
||||
lvdisplay_segments(lv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lvdisplay(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
/* FIXME Allow VG args via process_each */
|
||||
|
||||
if (arg_count(cmd, colon_ARG) && arg_count(cmd, verbose_ARG)) {
|
||||
log_error("Options -v and -c are incompatible");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
return process_each_lv(cmd, argc, argv, LCK_VG_READ, &lvdisplay_single);
|
||||
}
|
||||
|
@@ -20,7 +20,7 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
int lvextend(int argc, char **argv)
|
||||
int lvextend(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
return lvresize(argc, argv);
|
||||
return lvresize(cmd, argc, argv);
|
||||
}
|
||||
|
210
tools/lvm.c
210
tools/lvm.c
@@ -24,14 +24,16 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef READLINE_SUPPORT
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#ifndef HAVE_RL_COMPLETION_MATCHES
|
||||
#define rl_completion_matches(a, b) completion_matches((char *)a, b)
|
||||
#endif
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#ifndef HAVE_RL_COMPLETION_MATCHES
|
||||
#define rl_completion_matches(a, b) completion_matches((char *)a, b)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* define exported table of valid switches */
|
||||
/*
|
||||
* Exported table of valid switches
|
||||
*/
|
||||
struct arg the_args[ARG_COUNT + 1] = {
|
||||
|
||||
#define arg(a, b, c, d) {b, "--" c, d, 0, NULL},
|
||||
@@ -43,16 +45,6 @@ struct arg the_args[ARG_COUNT + 1] = {
|
||||
static int _array_size;
|
||||
static int _num_commands;
|
||||
static struct command *_commands;
|
||||
|
||||
/* Exported LVM1 disk format */
|
||||
struct format_instance *fid;
|
||||
|
||||
/* Map of uuid -> device */
|
||||
struct uuid_map *the_um;
|
||||
|
||||
/* Export command being processed */
|
||||
struct command *the_command;
|
||||
|
||||
struct cmd_context *cmd;
|
||||
|
||||
/* Whether or not to dump persistent filter state */
|
||||
@@ -64,7 +56,6 @@ static FILE *_log;
|
||||
/* lvm1 label handler */
|
||||
static struct labeller *_lvm1_label;
|
||||
|
||||
|
||||
/*
|
||||
* This structure only contains those options that
|
||||
* can have a default and per command setting.
|
||||
@@ -84,7 +75,6 @@ struct config_info {
|
||||
static struct config_info _default_settings;
|
||||
static struct config_info _current_settings;
|
||||
|
||||
|
||||
/*
|
||||
* The lvm_sys_dir contains:
|
||||
*
|
||||
@@ -269,9 +259,9 @@ int size_arg(struct arg *a)
|
||||
v *= 1024;
|
||||
}
|
||||
a->i_value = (uint32_t) v;
|
||||
a->i64_value = (uint64_t) v;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int int_arg(struct arg *a)
|
||||
@@ -294,6 +284,21 @@ int int_arg_with_sign(struct arg *a)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int minor_arg(struct arg *a)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
if (!_get_int_arg(a, &ptr) || (*ptr) || (a->sign == SIGN_MINUS))
|
||||
return 0;
|
||||
|
||||
if (a->i_value > 255) {
|
||||
log_error("Minor number outside range 0-255");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int string_arg(struct arg *a)
|
||||
{
|
||||
return 1;
|
||||
@@ -337,7 +342,7 @@ char yes_no_prompt(const char *prompt, ...)
|
||||
static void register_commands()
|
||||
{
|
||||
#define xx(a, b, c...) register_command(# a, a, b, ## c, \
|
||||
debug_ARG, help_ARG, suspend_ARG, \
|
||||
debug_ARG, help_ARG, \
|
||||
version_ARG, verbose_ARG, \
|
||||
quiet_ARG, -1);
|
||||
#include "commands.h"
|
||||
@@ -543,14 +548,13 @@ static int merge_synonym(int oldarg, int newarg)
|
||||
{
|
||||
struct arg *old, *new;
|
||||
|
||||
if (arg_count(oldarg) && arg_count(newarg)) {
|
||||
if (arg_count(cmd, oldarg) && arg_count(cmd, newarg)) {
|
||||
log_error("%s and %s are synonyms. Please only supply one.",
|
||||
the_args[oldarg].long_arg,
|
||||
the_args[newarg].long_arg);
|
||||
the_args[oldarg].long_arg, the_args[newarg].long_arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!arg_count(oldarg))
|
||||
if (!arg_count(cmd, oldarg))
|
||||
return 1;
|
||||
|
||||
old = the_args + oldarg;
|
||||
@@ -564,7 +568,7 @@ static int merge_synonym(int oldarg, int newarg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int version(int argc, char **argv)
|
||||
int version(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
char version[80];
|
||||
|
||||
@@ -581,44 +585,40 @@ static int process_common_commands(struct command *com)
|
||||
{
|
||||
_current_settings = _default_settings;
|
||||
|
||||
if (arg_count(suspend_ARG))
|
||||
kill(getpid(), SIGSTOP);
|
||||
|
||||
if (arg_count(debug_ARG))
|
||||
if (arg_count(cmd, debug_ARG))
|
||||
_current_settings.debug = _LOG_FATAL +
|
||||
(arg_count(debug_ARG) - 1);
|
||||
(arg_count(cmd, debug_ARG) - 1);
|
||||
|
||||
if (arg_count(verbose_ARG))
|
||||
_current_settings.verbose = arg_count(verbose_ARG);
|
||||
if (arg_count(cmd, verbose_ARG))
|
||||
_current_settings.verbose = arg_count(cmd, verbose_ARG);
|
||||
|
||||
if (arg_count(quiet_ARG)) {
|
||||
if (arg_count(cmd, quiet_ARG)) {
|
||||
_current_settings.debug = 0;
|
||||
_current_settings.verbose = 0;
|
||||
}
|
||||
|
||||
if (arg_count(test_ARG))
|
||||
_current_settings.test = arg_count(test_ARG);
|
||||
if (arg_count(cmd, test_ARG))
|
||||
_current_settings.test = arg_count(cmd, test_ARG);
|
||||
|
||||
if (arg_count(help_ARG)) {
|
||||
if (arg_count(cmd, help_ARG)) {
|
||||
usage(com->name);
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
if (arg_count(version_ARG)) {
|
||||
return version(0, (char **)NULL);
|
||||
if (arg_count(cmd, version_ARG)) {
|
||||
return version(cmd, 0, (char **) NULL);
|
||||
}
|
||||
|
||||
if (arg_count(autobackup_ARG)) {
|
||||
if (arg_count(cmd, autobackup_ARG)) {
|
||||
_current_settings.archive = 1;
|
||||
_current_settings.backup = 1;
|
||||
}
|
||||
|
||||
if (arg_count(partial_ARG)) {
|
||||
if (arg_count(cmd, partial_ARG)) {
|
||||
init_partial(1);
|
||||
log_print("Partial mode. Incomplete volume groups will "
|
||||
"be activated read-only.");
|
||||
}
|
||||
else
|
||||
} else
|
||||
init_partial(0);
|
||||
|
||||
/* Handle synonyms */
|
||||
@@ -631,7 +631,7 @@ static int process_common_commands(struct command *com)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int help(int argc, char **argv)
|
||||
int help(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
if (!argc)
|
||||
display_help();
|
||||
@@ -669,26 +669,73 @@ static void _use_settings(struct config_info *settings)
|
||||
backup_enable(settings->backup);
|
||||
}
|
||||
|
||||
static char *_copy_command_line(struct pool *mem, int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Build up the complete command line, used as a
|
||||
* description for backups.
|
||||
*/
|
||||
if (!pool_begin_object(cmd->mem, 128))
|
||||
goto bad;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (!pool_grow_object(cmd->mem, argv[i], strlen(argv[i])))
|
||||
goto bad;
|
||||
|
||||
if (i < (argc - 1))
|
||||
if (!pool_grow_object(cmd->mem, " ", 1)) ;
|
||||
}
|
||||
|
||||
/*
|
||||
* Terminate.
|
||||
*/
|
||||
if (!pool_grow_object(mem, "\0", 1))
|
||||
goto bad;
|
||||
|
||||
return pool_end_object(mem);
|
||||
|
||||
bad:
|
||||
log_err("Couldn't copy command line.");
|
||||
pool_abandon_object(mem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int run_command(int argc, char **argv)
|
||||
{
|
||||
int ret = 0;
|
||||
int locking_type;
|
||||
|
||||
if (!(the_command = find_command(argv[0])))
|
||||
if (!(cmd->cmd_line = _copy_command_line(cmd->mem, argc, argv)))
|
||||
return ECMD_FAILED;
|
||||
|
||||
if (!(cmd->command = find_command(argv[0])))
|
||||
return ENO_SUCH_CMD;
|
||||
|
||||
if (!process_command_line(the_command, &argc, &argv)) {
|
||||
if (!process_command_line(cmd->command, &argc, &argv)) {
|
||||
log_error("Error during parsing of command line.");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
set_cmd_name(the_command->name);
|
||||
set_cmd_name(cmd->command->name);
|
||||
|
||||
if ((ret = process_common_commands(the_command)))
|
||||
if ((ret = process_common_commands(cmd->command)))
|
||||
return ret;
|
||||
|
||||
_use_settings(&_current_settings);
|
||||
|
||||
ret = the_command->fn(argc, argv);
|
||||
locking_type = find_config_int(cmd->cf->root, "global/locking_type",
|
||||
'/', 1);
|
||||
if (!init_locking(locking_type, cmd->cf)) {
|
||||
log_error("Locking type %d initialisation failed.",
|
||||
locking_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = cmd->command->fn(cmd, argc, argv);
|
||||
|
||||
fin_locking();
|
||||
|
||||
/*
|
||||
* set the debug and verbose levels back
|
||||
@@ -704,8 +751,7 @@ static int run_command(int argc, char **argv)
|
||||
pool_empty(cmd->mem);
|
||||
|
||||
if (ret == EINVALID_CMD_LINE && !_interactive)
|
||||
usage(the_command->name);
|
||||
|
||||
usage(cmd->command->name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -749,9 +795,8 @@ static void __init_log(struct config_file *cf)
|
||||
|
||||
const char *log_file, *prefix;
|
||||
|
||||
|
||||
_default_settings.syslog =
|
||||
find_config_int(cf->root, "log/syslog", '/', 1);
|
||||
find_config_int(cf->root, "log/syslog", '/', 1);
|
||||
if (_default_settings.syslog != 1)
|
||||
fin_syslog();
|
||||
|
||||
@@ -759,11 +804,11 @@ static void __init_log(struct config_file *cf)
|
||||
init_syslog(_default_settings.syslog);
|
||||
|
||||
_default_settings.debug =
|
||||
find_config_int(cf->root, "log/level", '/', 0);
|
||||
find_config_int(cf->root, "log/level", '/', 0);
|
||||
init_debug(_default_settings.debug);
|
||||
|
||||
_default_settings.verbose =
|
||||
find_config_int(cf->root, "log/verbose", '/', 0);
|
||||
find_config_int(cf->root, "log/verbose", '/', 0);
|
||||
init_verbose(_default_settings.verbose);
|
||||
|
||||
init_indent(find_config_int(cf->root, "log/indent", '/', 1));
|
||||
@@ -772,7 +817,7 @@ static void __init_log(struct config_file *cf)
|
||||
|
||||
init_cmd_name(find_config_int(cf->root, "log/command_names", '/', 0));
|
||||
|
||||
_default_settings.test = find_config_int(cf->root, "global/test",
|
||||
_default_settings.test = find_config_int(cf->root, "global/test",
|
||||
'/', 0);
|
||||
if (find_config_int(cf->root, "log/overwrite", '/', 0))
|
||||
open_mode = "w";
|
||||
@@ -803,14 +848,14 @@ static int _init_backup(struct config_file *cf)
|
||||
|
||||
/* set up archiving */
|
||||
_default_settings.archive =
|
||||
find_config_bool(cmd->cf->root, "backup/archive", '/',
|
||||
DEFAULT_ARCHIVE_ENABLED);
|
||||
find_config_bool(cmd->cf->root, "backup/archive", '/',
|
||||
DEFAULT_ARCHIVE_ENABLED);
|
||||
|
||||
days = find_config_int(cmd->cf->root, "backup/retain_days", '/',
|
||||
DEFAULT_ARCHIVE_DAYS);
|
||||
|
||||
min = find_config_int(cmd->cf->root, "backup/retain_min", '/',
|
||||
DEFAULT_ARCHIVE_NUMBER);
|
||||
DEFAULT_ARCHIVE_NUMBER);
|
||||
|
||||
if (lvm_snprintf(default_dir, sizeof(default_dir), "%s/%s", _sys_dir,
|
||||
DEFAULT_ARCHIVE_SUBDIR) == -1) {
|
||||
@@ -829,8 +874,8 @@ static int _init_backup(struct config_file *cf)
|
||||
|
||||
/* set up the backup */
|
||||
_default_settings.backup =
|
||||
find_config_bool(cmd->cf->root, "backup/backup", '/',
|
||||
DEFAULT_BACKUP_ENABLED);
|
||||
find_config_bool(cmd->cf->root, "backup/backup", '/',
|
||||
DEFAULT_BACKUP_ENABLED);
|
||||
|
||||
if (lvm_snprintf(default_dir, sizeof(default_dir), "%s/%s", _sys_dir,
|
||||
DEFAULT_BACKUP_SUBDIR) == -1) {
|
||||
@@ -934,8 +979,7 @@ static struct dev_filter *filter_setup(struct config_file *cf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
lvm_cache = find_config_str(cf->root, "devices/cache", '/',
|
||||
cache_file);
|
||||
lvm_cache = find_config_str(cf->root, "devices/cache", '/', cache_file);
|
||||
|
||||
if (!(f4 = persistent_filter_create(f3, lvm_cache))) {
|
||||
log_error("Failed to create persistent device filter");
|
||||
@@ -956,7 +1000,7 @@ static struct dev_filter *filter_setup(struct config_file *cf)
|
||||
return f4;
|
||||
}
|
||||
|
||||
static int _init_uuid_map(struct dev_filter *filter)
|
||||
static struct uuid_map *_init_uuid_map(struct dev_filter *filter)
|
||||
{
|
||||
label_init();
|
||||
|
||||
@@ -971,12 +1015,12 @@ static int _init_uuid_map(struct dev_filter *filter)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (the_um = uuid_map_create(filter)) ? 1 : 0;
|
||||
return uuid_map_create(filter);
|
||||
}
|
||||
|
||||
static void _exit_uuid_map(void)
|
||||
{
|
||||
uuid_map_destroy(the_um);
|
||||
uuid_map_destroy(cmd->um);
|
||||
label_exit();
|
||||
_lvm1_label->ops->destroy(_lvm1_label);
|
||||
_lvm1_label = NULL;
|
||||
@@ -1016,6 +1060,8 @@ static int init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd->args = &the_args[0];
|
||||
|
||||
if (!(cmd->cf = create_config_file())) {
|
||||
stack;
|
||||
return 0;
|
||||
@@ -1035,8 +1081,7 @@ static int init(void)
|
||||
if (stat(config_file, &info) != -1) {
|
||||
/* we've found a config file */
|
||||
if (!read_config(cmd->cf, config_file)) {
|
||||
log_error("Failed to load config file %s",
|
||||
config_file);
|
||||
log_error("Failed to load config file %s", config_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1044,15 +1089,15 @@ static int init(void)
|
||||
}
|
||||
|
||||
_default_settings.umask = find_config_int(cmd->cf->root,
|
||||
"global/umask", '/',
|
||||
DEFAULT_UMASK);
|
||||
"global/umask", '/',
|
||||
DEFAULT_UMASK);
|
||||
|
||||
if ((old_umask = umask((mode_t)_default_settings.umask)) !=
|
||||
(mode_t)_default_settings.umask)
|
||||
log_verbose("Set umask to %04o", _default_settings.umask);
|
||||
if ((old_umask = umask((mode_t) _default_settings.umask)) !=
|
||||
(mode_t) _default_settings.umask)
|
||||
log_verbose("Set umask to %04o", _default_settings.umask);
|
||||
|
||||
if (lvm_snprintf(_dev_dir, sizeof(_dev_dir), "%s/",
|
||||
find_config_str(cmd->cf->root, "devices/dir",
|
||||
find_config_str(cmd->cf->root, "devices/dir",
|
||||
'/', DEFAULT_DEV_DIR)) < 0) {
|
||||
log_error("Device directory given in config file too long");
|
||||
return 0;
|
||||
@@ -1064,7 +1109,7 @@ static int init(void)
|
||||
dm_log_init(print_log);
|
||||
|
||||
if (lvm_snprintf(_proc_dir, sizeof(_proc_dir), "%s",
|
||||
find_config_str(cmd->cf->root, "global/proc",
|
||||
find_config_str(cmd->cf->root, "global/proc",
|
||||
'/', DEFAULT_PROC_DIR)) < 0) {
|
||||
log_error("Device directory given in config file too long");
|
||||
return 0;
|
||||
@@ -1082,7 +1127,7 @@ static int init(void)
|
||||
}
|
||||
|
||||
/* the uuid map uses the filter */
|
||||
if (!_init_uuid_map(cmd->filter)) {
|
||||
if (!(cmd->um = _init_uuid_map(cmd->filter))) {
|
||||
log_err("Failed to set up the uuid map.");
|
||||
return 0;
|
||||
}
|
||||
@@ -1092,7 +1137,7 @@ static int init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(fid = create_lvm1_format(cmd)))
|
||||
if (!(cmd->fid = create_lvm1_format(cmd)))
|
||||
return 0;
|
||||
|
||||
_use_settings(&_default_settings);
|
||||
@@ -1114,16 +1159,16 @@ static void fin(void)
|
||||
if (_dump_filter)
|
||||
persistent_filter_dump(cmd->filter);
|
||||
|
||||
fid->ops->destroy(fid);
|
||||
cmd->fid->ops->destroy(cmd->fid);
|
||||
cmd->filter->destroy(cmd->filter);
|
||||
pool_destroy(cmd->mem);
|
||||
vgcache_destroy();
|
||||
dev_cache_exit();
|
||||
destroy_config_file(cmd->cf);
|
||||
dbg_free(cmd);
|
||||
archive_exit();
|
||||
backup_exit();
|
||||
_exit_uuid_map();
|
||||
dbg_free(cmd);
|
||||
__fin_commands();
|
||||
|
||||
dump_memory();
|
||||
@@ -1168,7 +1213,7 @@ static int run_script(int argc, char **argv)
|
||||
}
|
||||
if (!argc)
|
||||
continue;
|
||||
if (!strcmp(argv[0], "quit"))
|
||||
if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit"))
|
||||
break;
|
||||
run_command(argc, argv);
|
||||
}
|
||||
@@ -1244,7 +1289,7 @@ static char *_list_args(const char *text, int state)
|
||||
char c;
|
||||
if (!(c = (the_args +
|
||||
com->valid_args[match_no++])->short_arg))
|
||||
continue;
|
||||
continue;
|
||||
|
||||
sprintf(s, "-%c", c);
|
||||
if (!strncmp(text, s, len))
|
||||
@@ -1301,7 +1346,6 @@ static int _hist_file(char *buffer, size_t size)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void _read_history(void)
|
||||
{
|
||||
char hist_file[PATH_MAX];
|
||||
@@ -1312,7 +1356,7 @@ static void _read_history(void)
|
||||
if (read_history(hist_file))
|
||||
log_very_verbose("Couldn't read history from %s.", hist_file);
|
||||
|
||||
stifle_history(find_config_int(cmd->cf->root, "shell/history_size",
|
||||
stifle_history(find_config_int(cmd->cf->root, "shell/history_size",
|
||||
'/', DEFAULT_MAX_HISTORY));
|
||||
|
||||
}
|
||||
@@ -1370,7 +1414,7 @@ static int shell(void)
|
||||
if (!argc)
|
||||
continue;
|
||||
|
||||
if (!strcmp(argv[0], "quit")) {
|
||||
if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) {
|
||||
remove_history(history_length - 1);
|
||||
log_error("Exiting.");
|
||||
break;
|
||||
|
@@ -20,7 +20,7 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
int lvmchange(int argc, char **argv)
|
||||
int lvmchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
log_print("With the device mapper, this program is obsolete.");
|
||||
return 0;
|
||||
|
151
tools/lvmdiskscan.c
Normal file
151
tools/lvmdiskscan.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Sistina Software
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changelog
|
||||
*
|
||||
* 05/02/2002 - First drop [HM]
|
||||
*/
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
int _get_max_dev_name_len(struct dev_filter *filter);
|
||||
void _count(struct device *, int *, int *);
|
||||
void _print(struct device *, uint64_t, char *);
|
||||
int _check_device(struct device *);
|
||||
|
||||
int disks_found = 0;
|
||||
int parts_found = 0;
|
||||
int pv_disks_found = 0;
|
||||
int pv_parts_found = 0;
|
||||
int max_len;
|
||||
|
||||
int lvmdiskscan(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
uint64_t size;
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
struct physical_volume *pv;
|
||||
|
||||
if (arg_count(cmd, lvmpartition_ARG))
|
||||
log_print("WARNING: only considering LVM devices");
|
||||
|
||||
max_len = _get_max_dev_name_len(cmd->filter);
|
||||
|
||||
if (!(iter = dev_iter_create(cmd->filter))) {
|
||||
log_error("dev_iter_create failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do scan */
|
||||
for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
|
||||
/* Try if it is a PV first */
|
||||
if ((pv = cmd->fid->ops->pv_read(cmd->fid, dev_name(dev)))) {
|
||||
if (!dev_get_size(dev, &size)) {
|
||||
log_error("Couldn't get size of \"%s\"",
|
||||
dev_name(dev));
|
||||
continue;
|
||||
}
|
||||
_print(dev, size, "LVM physical volume");
|
||||
_count(dev, &pv_disks_found, &pv_parts_found);
|
||||
continue;
|
||||
}
|
||||
/* If user just wants PVs we are done */
|
||||
if (arg_count(cmd, lvmpartition_ARG))
|
||||
continue;
|
||||
|
||||
/* What other device is it? */
|
||||
if (!_check_device(dev))
|
||||
continue;
|
||||
}
|
||||
dev_iter_destroy(iter);
|
||||
|
||||
/* Display totals */
|
||||
if (!arg_count(cmd, lvmpartition_ARG)) {
|
||||
log_print("%d disk%s",
|
||||
disks_found, disks_found == 1 ? "" : "s");
|
||||
log_print("%d partition%s",
|
||||
parts_found, parts_found == 1 ? "" : "s");
|
||||
}
|
||||
log_print("%d LVM physical volume whole disk%s",
|
||||
pv_disks_found, pv_disks_found == 1 ? "" : "s");
|
||||
log_print("%d LVM physical volume%s",
|
||||
pv_parts_found, pv_parts_found == 1 ? "" : "s");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _check_device(struct device *dev)
|
||||
{
|
||||
char buffer;
|
||||
uint64_t size;
|
||||
|
||||
if (!dev_open(dev, 0)) {
|
||||
return 0;
|
||||
}
|
||||
if (dev_read(dev, 0, 1, &buffer) != 1) {
|
||||
dev_close(dev);
|
||||
return 0;
|
||||
}
|
||||
if (!dev_get_size(dev, &size)) {
|
||||
log_error("Couldn't get size of \"%s\"", dev_name(dev));
|
||||
}
|
||||
_print(dev, size, NULL);
|
||||
_count(dev, &disks_found, &parts_found);
|
||||
if (!dev_close(dev)) {
|
||||
log_error("dev_close on \"%s\" failed", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _get_max_dev_name_len(struct dev_filter *filter)
|
||||
{
|
||||
int len = 0;
|
||||
int max_len = 0;
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
|
||||
if (!(iter = dev_iter_create(filter))) {
|
||||
log_error("dev_iter_create failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do scan */
|
||||
for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
|
||||
len = strlen(dev_name(dev));
|
||||
if (len > max_len)
|
||||
max_len = len;
|
||||
}
|
||||
dev_iter_destroy(iter);
|
||||
|
||||
return max_len;
|
||||
}
|
||||
|
||||
void _count(struct device *dev, int *disks, int *parts)
|
||||
{
|
||||
int c = dev_name(dev)[strlen(dev_name(dev)) - 1];
|
||||
|
||||
if (!isdigit(c))
|
||||
(*disks)++;
|
||||
else
|
||||
(*parts)++;
|
||||
}
|
||||
|
||||
void _print(struct device *dev, uint64_t size, char *what)
|
||||
{
|
||||
char *dummy = display_size(size / 2, SIZE_SHORT);
|
||||
const char *name = dev_name(dev);
|
||||
|
||||
if (!what) {
|
||||
|
||||
what = "";
|
||||
}
|
||||
|
||||
log_print("%-*s [%15s] %s", max_len, name, dummy, what);
|
||||
dbg_free(dummy);
|
||||
}
|
@@ -20,7 +20,7 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
int lvreduce(int argc, char **argv)
|
||||
int lvreduce(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
return lvresize(argc, argv);
|
||||
return lvresize(cmd, argc, argv);
|
||||
}
|
||||
|
@@ -20,22 +20,22 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
static int lvremove_single(struct logical_volume *lv);
|
||||
static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv);
|
||||
|
||||
int lvremove(int argc, char **argv)
|
||||
int lvremove(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
if (!argc) {
|
||||
log_error("Please enter one or more logical volume paths");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
return process_each_lv(argc, argv, &lvremove_single);
|
||||
return process_each_lv(cmd, argc, argv, LCK_VG_READ, &lvremove_single);
|
||||
}
|
||||
|
||||
static int lvremove_single(struct logical_volume *lv)
|
||||
static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
int active;
|
||||
struct dm_info info;
|
||||
|
||||
vg = lv->vg;
|
||||
|
||||
@@ -44,24 +44,28 @@ static int lvremove_single(struct logical_volume *lv)
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (lv->status & SNAPSHOT_ORG) {
|
||||
if (lv_is_origin(lv)) {
|
||||
log_error("Can't remove logical volume \"%s\" under snapshot",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (lv_open_count(lv) > 0) {
|
||||
if (!lv_info(lv, &info)) {
|
||||
stack;
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (info.open_count) {
|
||||
log_error("Can't remove open logical volume \"%s\"", lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
active = lv_active(lv);
|
||||
|
||||
if (active && !arg_count(force_ARG)) {
|
||||
if (yes_no_prompt
|
||||
("Do you really want to remove active logical volume \"%s\"? "
|
||||
"[y/n]: ", lv->name) == 'n') {
|
||||
log_print("Logical volume \"%s\" not removed", lv->name);
|
||||
if (info.exists && !arg_count(cmd, force_ARG)) {
|
||||
if (yes_no_prompt("Do you really want to remove active "
|
||||
"logical volume \"%s\"? [y/n]: ",
|
||||
lv->name) == 'n') {
|
||||
log_print("Logical volume \"%s\" not removed",
|
||||
lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -69,8 +73,18 @@ static int lvremove_single(struct logical_volume *lv)
|
||||
if (!archive(vg))
|
||||
return ECMD_FAILED;
|
||||
|
||||
if (active && !lv_deactivate(lv)) {
|
||||
log_error("Unable to deactivate logical volume \"%s\"", lv->name);
|
||||
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_DEACTIVATE)) {
|
||||
log_error("Unable to deactivate logical volume \"%s\"",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (lv_is_cow(lv)) {
|
||||
log_verbose("Removing snapshot %s", lv->name);
|
||||
if (!vg_remove_snapshot(lv->vg, lv)) {
|
||||
stack;
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
log_verbose("Releasing logical volume \"%s\"", lv->name);
|
||||
@@ -80,11 +94,11 @@ static int lvremove_single(struct logical_volume *lv)
|
||||
}
|
||||
|
||||
/* store it on disks */
|
||||
if (!fid->ops->vg_write(fid, vg))
|
||||
if (!cmd->fid->ops->vg_write(cmd->fid, vg))
|
||||
return ECMD_FAILED;
|
||||
|
||||
backup(vg);
|
||||
|
||||
log_print("logical volume \"%s\" successfully removed", lv->name);
|
||||
log_print("Logical volume \"%s\" successfully removed", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
@@ -20,10 +20,9 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
int lvrename(int argc, char **argv)
|
||||
int lvrename(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
int maxlen;
|
||||
int active;
|
||||
char *lv_name_old, *lv_name_new;
|
||||
char *vg_name, *vg_name_new;
|
||||
char *st;
|
||||
@@ -40,13 +39,13 @@ int lvrename(int argc, char **argv)
|
||||
lv_name_old = argv[0];
|
||||
lv_name_new = argv[1];
|
||||
|
||||
if (!(vg_name = extract_vgname(fid, lv_name_old))) {
|
||||
if (!(vg_name = extract_vgname(cmd->fid, lv_name_old))) {
|
||||
log_error("Please provide a volume group name");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (strchr(lv_name_new, '/') &&
|
||||
(vg_name_new = extract_vgname(fid, lv_name_new)) &&
|
||||
(vg_name_new = extract_vgname(cmd->fid, lv_name_new)) &&
|
||||
strcmp(vg_name, vg_name_new)) {
|
||||
log_error("Logical volume names must "
|
||||
"have the same volume group (\"%s\" or \"%s\")",
|
||||
@@ -61,7 +60,7 @@ int lvrename(int argc, char **argv)
|
||||
lv_name_new = st + 1;
|
||||
|
||||
/* Check sanity of new name */
|
||||
maxlen = NAME_LEN - strlen(vg_name) - strlen(fid->cmd->dev_dir) - 3;
|
||||
maxlen = NAME_LEN - strlen(vg_name) - strlen(cmd->dev_dir) - 3;
|
||||
if (strlen(lv_name_new) > maxlen) {
|
||||
log_error("New logical volume path exceeds maximum length "
|
||||
"of %d!", maxlen);
|
||||
@@ -74,8 +73,9 @@ int lvrename(int argc, char **argv)
|
||||
}
|
||||
|
||||
if (!is_valid_chars(lv_name_new)) {
|
||||
log_error("New logical volume name \"%s\" has invalid characters",
|
||||
lv_name_new);
|
||||
log_error
|
||||
("New logical volume name \"%s\" has invalid characters",
|
||||
lv_name_new);
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
@@ -85,68 +85,73 @@ int lvrename(int argc, char **argv)
|
||||
}
|
||||
|
||||
log_verbose("Checking for existing volume group \"%s\"", vg_name);
|
||||
if (!(vg = fid->ops->vg_read(fid, vg_name))) {
|
||||
log_error("Volume group \"%s\" doesn't exist", vg_name);
|
||||
|
||||
if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
|
||||
log_error("Can't get lock for %s", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group \"%s\" is exported", vg->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
if (!(vg = cmd->fid->ops->vg_read(cmd->fid, vg_name))) {
|
||||
log_error("Volume group \"%s\" doesn't exist", vg_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(vg->status & LVM_WRITE)) {
|
||||
log_error("Volume group \"%s\" is read-only", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group \"%s\" is exported", vg->name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(vg->status & LVM_WRITE)) {
|
||||
log_error("Volume group \"%s\" is read-only", vg_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (find_lv_in_vg(vg, lv_name_new)) {
|
||||
log_error("Logical volume \"%s\" already exists in "
|
||||
"volume group \"%s\"", lv_name_new, vg_name);
|
||||
return ECMD_FAILED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(lvl = find_lv_in_vg(vg, lv_name_old))) {
|
||||
log_error("Existing logical volume \"%s\" not found in "
|
||||
"volume group \"%s\"", lv_name_old, vg_name);
|
||||
return ECMD_FAILED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
lv = lvl->lv;
|
||||
|
||||
if (!archive(lv->vg))
|
||||
return ECMD_FAILED;
|
||||
goto error;
|
||||
|
||||
if ((active = lv_active(lv)) < 0) {
|
||||
log_error("Unable to determine status of \"%s\"", lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD |
|
||||
LCK_NONBLOCK))
|
||||
goto error;
|
||||
|
||||
if (active && !lv_suspend(lv)) {
|
||||
log_error("Failed to suspend \"%s\"", lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(lv->name = pool_strdup(fid->cmd->mem, lv_name_new))) {
|
||||
if (!(lv->name = pool_strdup(cmd->mem, lv_name_new))) {
|
||||
log_error("Failed to allocate space for new name");
|
||||
return ECMD_FAILED;
|
||||
goto lverror;
|
||||
}
|
||||
|
||||
/* store it on disks */
|
||||
log_verbose("Writing out updated volume group");
|
||||
if (!(fid->ops->vg_write(fid, vg))) {
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
if (!(cmd->fid->ops->vg_write(cmd->fid, vg)))
|
||||
goto lverror;
|
||||
|
||||
if (active) {
|
||||
lv_rename(lv_name_old, lv);
|
||||
lv_reactivate(lv);
|
||||
}
|
||||
unlock_lv(cmd, lv->lvid.s);
|
||||
|
||||
backup(lv->vg);
|
||||
|
||||
unlock_vg(cmd, vg_name);
|
||||
|
||||
log_print("Renamed \"%s\" to \"%s\" in volume group \"%s\"",
|
||||
lv_name_old, lv_name_new, vg_name);
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
lverror:
|
||||
unlock_lv(cmd, lv->lvid.s);
|
||||
|
||||
error:
|
||||
unlock_vg(cmd, vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
143
tools/lvresize.c
143
tools/lvresize.c
@@ -20,10 +20,11 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
int lvresize(int argc, char **argv)
|
||||
int lvresize(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
struct logical_volume *lv;
|
||||
struct dm_info info;
|
||||
uint32_t extents = 0;
|
||||
uint32_t size = 0;
|
||||
uint32_t stripes = 0, stripesize = 0;
|
||||
@@ -37,7 +38,6 @@ int lvresize(int argc, char **argv)
|
||||
struct list *pvh, *segh;
|
||||
struct lv_list *lvl;
|
||||
int opt = 0;
|
||||
int active;
|
||||
|
||||
enum {
|
||||
LV_ANY = 0,
|
||||
@@ -45,25 +45,25 @@ int lvresize(int argc, char **argv)
|
||||
LV_EXTEND = 2
|
||||
} resize = LV_ANY;
|
||||
|
||||
cmd_name = command_name();
|
||||
cmd_name = command_name(cmd);
|
||||
if (!strcmp(cmd_name, "lvreduce"))
|
||||
resize = LV_REDUCE;
|
||||
if (!strcmp(cmd_name, "lvextend"))
|
||||
resize = LV_EXTEND;
|
||||
|
||||
if (arg_count(extents_ARG) + arg_count(size_ARG) != 1) {
|
||||
if (arg_count(cmd, extents_ARG) + arg_count(cmd, size_ARG) != 1) {
|
||||
log_error("Please specify either size or extents (not both)");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(extents_ARG)) {
|
||||
extents = arg_int_value(extents_ARG, 0);
|
||||
sign = arg_sign_value(extents_ARG, SIGN_NONE);
|
||||
if (arg_count(cmd, extents_ARG)) {
|
||||
extents = arg_int_value(cmd, extents_ARG, 0);
|
||||
sign = arg_sign_value(cmd, extents_ARG, SIGN_NONE);
|
||||
}
|
||||
|
||||
if (arg_count(size_ARG)) {
|
||||
size = arg_int_value(size_ARG, 0);
|
||||
sign = arg_sign_value(size_ARG, SIGN_NONE);
|
||||
if (arg_count(cmd, size_ARG)) {
|
||||
size = arg_int_value(cmd, size_ARG, 0);
|
||||
sign = arg_sign_value(cmd, size_ARG, SIGN_NONE);
|
||||
}
|
||||
|
||||
if (resize == LV_EXTEND && sign == SIGN_MINUS) {
|
||||
@@ -76,14 +76,14 @@ int lvresize(int argc, char **argv)
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(stripes_ARG)) {
|
||||
if (arg_count(cmd, stripes_ARG)) {
|
||||
log_print("Varied striping not yet supported. Ignoring.");
|
||||
/* FUTURE stripes = arg_int_value(stripes_ARG, 1); */
|
||||
/* FUTURE stripes = arg_int_value(cmd,stripes_ARG, 1); */
|
||||
}
|
||||
|
||||
if (arg_count(stripesize_ARG)) {
|
||||
if (arg_count(cmd, stripesize_ARG)) {
|
||||
log_print("Varied stripesize not yet supported. Ignoring.");
|
||||
/* FUTURE stripesize = 2 * arg_int_value(stripesize_ARG, 0); */
|
||||
/* FUTURE stripesize = 2 * arg_int_value(cmd,stripesize_ARG, 0); */
|
||||
}
|
||||
|
||||
if (!argc) {
|
||||
@@ -95,7 +95,7 @@ int lvresize(int argc, char **argv)
|
||||
argv++;
|
||||
argc--;
|
||||
|
||||
if (!(vg_name = extract_vgname(fid, lv_name))) {
|
||||
if (!(vg_name = extract_vgname(cmd->fid, lv_name))) {
|
||||
log_error("Please provide a volume group name");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
@@ -105,26 +105,31 @@ int lvresize(int argc, char **argv)
|
||||
|
||||
/* does VG exist? */
|
||||
log_verbose("Finding volume group %s", vg_name);
|
||||
if (!(vg = fid->ops->vg_read(fid, vg_name))) {
|
||||
log_error("Volume group %s doesn't exist", vg_name);
|
||||
if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
|
||||
log_error("Can't get lock for %s", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group %s is exported", vg->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
if (!(vg = cmd->fid->ops->vg_read(cmd->fid, vg_name))) {
|
||||
log_error("Volume group %s doesn't exist", vg_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(vg->status & LVM_WRITE)) {
|
||||
log_error("Volume group %s is read-only", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group %s is exported", vg->name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(vg->status & LVM_WRITE)) {
|
||||
log_error("Volume group %s is read-only", vg_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* does LV exist? */
|
||||
if (!(lvl = find_lv_in_vg(vg, lv_name))) {
|
||||
log_error("Logical volume %s not found in volume group %s",
|
||||
lv_name, vg_name);
|
||||
return ECMD_FAILED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
lv = lvl->lv;
|
||||
@@ -157,7 +162,7 @@ int lvresize(int argc, char **argv)
|
||||
if (extents >= lv->le_count) {
|
||||
log_error("Unable to reduce %s below 1 extent",
|
||||
lv_name);
|
||||
return EINVALID_CMD_LINE;
|
||||
goto error_cmdline;
|
||||
}
|
||||
|
||||
extents = lv->le_count - extents;
|
||||
@@ -165,13 +170,13 @@ int lvresize(int argc, char **argv)
|
||||
|
||||
if (!extents) {
|
||||
log_error("New size of 0 not permitted");
|
||||
return EINVALID_CMD_LINE;
|
||||
goto error_cmdline;
|
||||
}
|
||||
|
||||
if (extents == lv->le_count) {
|
||||
log_error("New size (%d extents) matches existing size "
|
||||
"(%d extents)", extents, lv->le_count);
|
||||
return EINVALID_CMD_LINE;
|
||||
goto error_cmdline;
|
||||
}
|
||||
|
||||
/* If extending, find stripes, stripesize & size of last segment */
|
||||
@@ -181,7 +186,7 @@ int lvresize(int argc, char **argv)
|
||||
struct stripe_segment *seg;
|
||||
uint32_t sz, str;
|
||||
|
||||
seg = list_item(segh, struct stripe_segment);
|
||||
seg = list_item(segh, struct stripe_segment);
|
||||
sz = seg->stripe_size;
|
||||
str = seg->stripes;
|
||||
|
||||
@@ -190,7 +195,7 @@ int lvresize(int argc, char **argv)
|
||||
(seg_stripes && seg_stripes != str && !stripes)) {
|
||||
log_error("Please specify number of "
|
||||
"stripes (-i) and stripesize (-I)");
|
||||
return EINVALID_CMD_LINE;
|
||||
goto error_cmdline;
|
||||
}
|
||||
|
||||
seg_stripesize = sz;
|
||||
@@ -245,7 +250,7 @@ int lvresize(int argc, char **argv)
|
||||
if (extents == lv->le_count) {
|
||||
log_error("New size (%d extents) matches existing size "
|
||||
"(%d extents)", extents, lv->le_count);
|
||||
return EINVALID_CMD_LINE;
|
||||
goto error_cmdline;
|
||||
}
|
||||
|
||||
if (extents < lv->le_count) {
|
||||
@@ -253,7 +258,7 @@ int lvresize(int argc, char **argv)
|
||||
log_error("New size given (%d extents) not larger "
|
||||
"than existing size (%d extents)",
|
||||
extents, lv->le_count);
|
||||
return EINVALID_CMD_LINE;
|
||||
goto error_cmdline;
|
||||
} else
|
||||
resize = LV_REDUCE;
|
||||
}
|
||||
@@ -263,7 +268,7 @@ int lvresize(int argc, char **argv)
|
||||
log_error("New size given (%d extents) not less than "
|
||||
"existing size (%d extents)", extents,
|
||||
lv->le_count);
|
||||
return EINVALID_CMD_LINE;
|
||||
goto error_cmdline;
|
||||
} else
|
||||
resize = LV_EXTEND;
|
||||
}
|
||||
@@ -272,12 +277,18 @@ int lvresize(int argc, char **argv)
|
||||
if (argc)
|
||||
log_print("Ignoring PVs on command line when reducing");
|
||||
|
||||
if (lv_active(lv) > 0) {
|
||||
if (!lv_info(lv, &info)) {
|
||||
stack;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (info.exists) {
|
||||
dummy =
|
||||
display_size(extents * vg->extent_size / 2,
|
||||
display_size((uint64_t)
|
||||
extents * (vg->extent_size / 2),
|
||||
SIZE_SHORT);
|
||||
log_print("WARNING: Reducing active%s logical volume "
|
||||
"to %s", lv_open_count(lv) ? " and open" : "",
|
||||
"to %s", info.open_count ? " and open" : "",
|
||||
dummy);
|
||||
|
||||
log_print("THIS MAY DESTROY YOUR DATA "
|
||||
@@ -285,63 +296,77 @@ int lvresize(int argc, char **argv)
|
||||
dbg_free(dummy);
|
||||
}
|
||||
|
||||
if (!arg_count(force_ARG)) {
|
||||
if (!arg_count(cmd, force_ARG)) {
|
||||
if (yes_no_prompt("Do you really want to reduce %s?"
|
||||
" [y/n]: ", lv_name) == 'n') {
|
||||
log_print("Logical volume %s NOT reduced",
|
||||
lv_name);
|
||||
return ECMD_FAILED;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!archive(vg))
|
||||
return ECMD_FAILED;
|
||||
goto error;
|
||||
|
||||
if (!lv_reduce(fid, lv, lv->le_count - extents))
|
||||
return ECMD_FAILED;
|
||||
if (!lv_reduce(cmd->fid, lv, lv->le_count - extents))
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((resize == LV_EXTEND && argc) &&
|
||||
!(pvh = create_pv_list(fid->cmd->mem, vg,
|
||||
argc - opt, argv + opt))) {
|
||||
!(pvh = create_pv_list(cmd->mem, vg, argc - opt, argv + opt))) {
|
||||
stack;
|
||||
return ECMD_FAILED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (resize == LV_EXTEND) {
|
||||
if (!archive(vg))
|
||||
return ECMD_FAILED;
|
||||
goto error;
|
||||
|
||||
if (!argc) {
|
||||
/* Use full list from VG */
|
||||
pvh = &vg->pvs;
|
||||
}
|
||||
dummy = display_size(extents * vg->extent_size / 2, SIZE_SHORT);
|
||||
dummy = display_size((uint64_t)
|
||||
extents * (vg->extent_size / 2),
|
||||
SIZE_SHORT);
|
||||
log_print("Extending logical volume %s to %s", lv_name, dummy);
|
||||
dbg_free(dummy);
|
||||
|
||||
if (!lv_extend(fid, lv, stripes, stripesize,
|
||||
if (!lv_extend(cmd->fid, lv, stripes, stripesize,
|
||||
extents - lv->le_count, pvh))
|
||||
return ECMD_FAILED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
active = lv_active(lv);
|
||||
|
||||
/********* FIXME Suspend lv ***********/
|
||||
if (!lock_vol(cmd, lv->lvid.s, LCK_LV_SUSPEND | LCK_HOLD)) {
|
||||
log_error("Can't get lock for %s", lv_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* store vg on disk(s) */
|
||||
if (!fid->ops->vg_write(fid, vg))
|
||||
return ECMD_FAILED;
|
||||
if (!cmd->fid->ops->vg_write(cmd->fid, vg)) {
|
||||
/* FIXME: Attempt reversion? */
|
||||
unlock_lv(cmd, lv->lvid.s);
|
||||
goto error;
|
||||
}
|
||||
|
||||
backup(vg);
|
||||
backup(vg);
|
||||
|
||||
if (active && !lv_reactivate(lv))
|
||||
return ECMD_FAILED;
|
||||
if (!unlock_lv(cmd, lv->lvid.s)) {
|
||||
log_error("Problem reactivating %s", lv_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/********* FIXME Resume *********/
|
||||
unlock_vg(cmd, vg_name);
|
||||
|
||||
log_print("Logical volume %s successfully resized", lv_name);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
unlock_vg(cmd, vg_name);
|
||||
return ECMD_FAILED;
|
||||
|
||||
error_cmdline:
|
||||
unlock_vg(cmd, vg_name);
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
@@ -20,43 +20,43 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
static int lvscan_single(struct logical_volume *lv);
|
||||
static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv);
|
||||
|
||||
int lvscan(int argc, char **argv)
|
||||
int lvscan(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
if (argc) {
|
||||
log_error("No additional command line arguments allowed");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
return process_each_lv(argc, argv, &lvscan_single);
|
||||
return process_each_lv(cmd, argc, argv, LCK_VG_READ, &lvscan_single);
|
||||
|
||||
/*********** FIXME Count! Add private struct to process_each*
|
||||
if (!lv_total)
|
||||
log_print("no logical volumes found");
|
||||
else {
|
||||
log_print
|
||||
("%d logical volumes with %s total in %d volume group%s",
|
||||
lv_total, (dummy =
|
||||
display_size(lv_capacity_total / 2, SIZE_SHORT)),
|
||||
vg_total, vg_total == 1 ? "" : "s");
|
||||
dbg_free(dummy);
|
||||
dummy = NULL;
|
||||
if (lv_active > 0)
|
||||
printf("%d active", lv_active);
|
||||
if (lv_active > 0 && lv_total - lv_active > 0)
|
||||
printf(" / ");
|
||||
if (lv_total - lv_active > 0)
|
||||
printf("%d inactive", lv_total - lv_active);
|
||||
printf(" logical volumes\n");
|
||||
}
|
||||
* if (!lv_total)
|
||||
* log_print("no logical volumes found");
|
||||
* else {
|
||||
* log_print
|
||||
* ("%d logical volumes with %s total in %d volume group%s",
|
||||
* lv_total, (dummy =
|
||||
* display_size(lv_capacity_total / 2, SIZE_SHORT)),
|
||||
* vg_total, vg_total == 1 ? "" : "s");
|
||||
* dbg_free(dummy);
|
||||
* dummy = NULL;
|
||||
* if (lv_active > 0)
|
||||
* printf("%d active", lv_active);
|
||||
* if (lv_active > 0 && lv_total - lv_active > 0)
|
||||
* printf(" / ");
|
||||
* if (lv_total - lv_active > 0)
|
||||
* printf("%d inactive", lv_total - lv_active);
|
||||
* printf(" logical volumes\n");
|
||||
* }
|
||||
*************/
|
||||
|
||||
}
|
||||
|
||||
static int lvscan_single(struct logical_volume *lv)
|
||||
static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
int active = 0;
|
||||
struct dm_info info;
|
||||
int lv_total = 0;
|
||||
ulong lv_capacity_total = 0;
|
||||
|
||||
@@ -64,15 +64,14 @@ static int lvscan_single(struct logical_volume *lv)
|
||||
const char *active_str, *snapshot_str;
|
||||
|
||||
/* FIXME Add -D arg to skip this! */
|
||||
if (lv_active(lv) > 0) {
|
||||
if (lv_info(lv, &info) && info.exists)
|
||||
active_str = "ACTIVE ";
|
||||
active++;
|
||||
} else
|
||||
else
|
||||
active_str = "inactive ";
|
||||
|
||||
if (lv->status & SNAPSHOT_ORG)
|
||||
if (lv_is_origin(lv))
|
||||
snapshot_str = "Original";
|
||||
else if (lv->status & SNAPSHOT)
|
||||
else if (lv_is_cow(lv))
|
||||
snapshot_str = "Snapshot";
|
||||
else
|
||||
snapshot_str = " ";
|
||||
@@ -88,21 +87,21 @@ static int lvscan_single(struct logical_volume *lv)
|
||||
dummy = display_size(lv->size / 2, SIZE_SHORT);
|
||||
|
||||
log_print("%s%s '%s%s/%s' [%s]%s%s", active_str, snapshot_str,
|
||||
fid->cmd->dev_dir, lv->vg->name, lv->name, dummy,
|
||||
cmd->dev_dir, lv->vg->name, lv->name, dummy,
|
||||
(lv->status & ALLOC_STRICT) ? " strict" : "",
|
||||
(lv->status & ALLOC_CONTIGUOUS) ? " contiguous" : "");
|
||||
|
||||
dbg_free(dummy);
|
||||
|
||||
/* FIXME sprintf? */
|
||||
|
||||
|
||||
/*********** FIXME Handle segments?
|
||||
if (lv->segments[0]->stripes > 1 && !(lv->status & SNAPSHOT))
|
||||
log_print(" striped[%u]", lv->segments[0]->stripes);
|
||||
****************/
|
||||
|
||||
/******** FIXME Device number display & Snapshot
|
||||
if (arg_count(blockdevice_ARG))
|
||||
if (arg_count(cmd,blockdevice_ARG))
|
||||
printf(" %d:%d",
|
||||
MAJOR(lv->lv_dev),
|
||||
MINOR(lv->lv_dev));
|
||||
|
@@ -20,9 +20,9 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
int pvchange_single(struct physical_volume *pv);
|
||||
int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv);
|
||||
|
||||
int pvchange(int argc, char **argv)
|
||||
int pvchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
int opt = 0;
|
||||
int done = 0;
|
||||
@@ -33,17 +33,17 @@ int pvchange(int argc, char **argv)
|
||||
|
||||
struct list *pvh, *pvs;
|
||||
|
||||
if (arg_count(allocatable_ARG) == 0) {
|
||||
if (arg_count(cmd, allocatable_ARG) == 0) {
|
||||
log_error("Please give the x option");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!(arg_count(all_ARG)) && !argc) {
|
||||
if (!(arg_count(cmd, all_ARG)) && !argc) {
|
||||
log_error("Please give a physical volume path");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(all_ARG) && argc) {
|
||||
if (arg_count(cmd, all_ARG) && argc) {
|
||||
log_error("Option a and PhysicalVolumePath are exclusive");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
@@ -52,67 +52,81 @@ int pvchange(int argc, char **argv)
|
||||
log_verbose("Using physical volume(s) on command line");
|
||||
for (; opt < argc; opt++) {
|
||||
pv_name = argv[opt];
|
||||
if (!(pv = fid->ops->pv_read(fid, pv_name))) {
|
||||
log_error("Failed to read physical volume \"%s\"",
|
||||
pv_name);
|
||||
if (!(pv = cmd->fid->ops->pv_read(cmd->fid, pv_name))) {
|
||||
log_error
|
||||
("Failed to read physical volume \"%s\"",
|
||||
pv_name);
|
||||
continue;
|
||||
}
|
||||
total++;
|
||||
done += pvchange_single(pv);
|
||||
done += pvchange_single(cmd, pv);
|
||||
}
|
||||
} else {
|
||||
log_verbose("Scanning for physical volume names");
|
||||
if (!(pvs = fid->ops->get_pvs(fid))) {
|
||||
if (!(pvs = cmd->fid->ops->get_pvs(cmd->fid))) {
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
list_iterate(pvh, pvs) {
|
||||
total++;
|
||||
done += pvchange_single(
|
||||
list_item(pvh, struct pv_list)->pv);
|
||||
done += pvchange_single(cmd,
|
||||
list_item(pvh,
|
||||
struct pv_list)->pv);
|
||||
}
|
||||
}
|
||||
|
||||
log_print("%d physical volume%s changed / %d physical volume%s "
|
||||
"not changed",
|
||||
done, done > 1 ? "s" : "",
|
||||
total - done, total - done > 1 ? "s" : "");
|
||||
done, done > 1 ? "s" : "",
|
||||
total - done, total - done > 1 ? "s" : "");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pvchange_single(struct physical_volume *pv)
|
||||
int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv)
|
||||
{
|
||||
struct volume_group *vg = NULL;
|
||||
struct pv_list *pvl;
|
||||
|
||||
const char *pv_name = dev_name(pv->dev);
|
||||
|
||||
int allocatable = !strcmp(arg_str_value(allocatable_ARG, "n"), "y");
|
||||
int allocatable =
|
||||
!strcmp(arg_str_value(cmd, allocatable_ARG, "n"), "y");
|
||||
|
||||
/* If in a VG, must change using volume group. */
|
||||
if (*pv->vg_name) {
|
||||
log_verbose("Finding volume group of physical volume \"%s\"",
|
||||
log_verbose("Finding volume group of physical volume \"%s\"",
|
||||
pv_name);
|
||||
if (!(vg = fid->ops->vg_read(fid, pv->vg_name))) {
|
||||
|
||||
if (!lock_vol(cmd, pv->vg_name, LCK_VG_WRITE)) {
|
||||
log_error("Can't get lock for %s", pv->vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg = cmd->fid->ops->vg_read(cmd->fid, pv->vg_name))) {
|
||||
unlock_vg(cmd, pv->vg_name);
|
||||
log_error("Unable to find volume group of \"%s\"",
|
||||
pv_name);
|
||||
pv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group \"%s\" is exported", vg->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
unlock_vg(cmd, pv->vg_name);
|
||||
log_error("Volume group \"%s\" is exported", vg->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg->status & LVM_WRITE)) {
|
||||
if (!(vg->status & LVM_WRITE)) {
|
||||
unlock_vg(cmd, pv->vg_name);
|
||||
log_error("Volume group \"%s\" is read-only", vg->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(pvl = find_pv_in_vg(vg, pv_name))) {
|
||||
log_error("Unable to find \"%s\" in volume group \"%s\"",
|
||||
pv_name, vg->name);
|
||||
unlock_vg(cmd, pv->vg_name);
|
||||
log_error
|
||||
("Unable to find \"%s\" in volume group \"%s\"",
|
||||
pv_name, vg->name);
|
||||
return 0;
|
||||
}
|
||||
pv = pvl->pv;
|
||||
@@ -122,18 +136,24 @@ int pvchange_single(struct physical_volume *pv)
|
||||
|
||||
/* change allocatability for a PV */
|
||||
if (allocatable && (pv->status & ALLOCATABLE_PV)) {
|
||||
log_error("Physical volume \"%s\" is already allocatable", pv_name);
|
||||
log_error("Physical volume \"%s\" is already allocatable",
|
||||
pv_name);
|
||||
if (*pv->vg_name)
|
||||
unlock_vg(cmd, pv->vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!allocatable && !(pv->status & ALLOCATABLE_PV)) {
|
||||
log_error("Physical volume \"%s\" is already unallocatable",
|
||||
pv_name);
|
||||
if (*pv->vg_name)
|
||||
unlock_vg(cmd, pv->vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (allocatable) {
|
||||
log_verbose("Setting physical volume \"%s\" allocatable", pv_name);
|
||||
log_verbose("Setting physical volume \"%s\" allocatable",
|
||||
pv_name);
|
||||
pv->status |= ALLOCATABLE_PV;
|
||||
} else {
|
||||
log_verbose("Setting physical volume \"%s\" NOT allocatable",
|
||||
@@ -143,15 +163,17 @@ int pvchange_single(struct physical_volume *pv)
|
||||
|
||||
log_verbose("Updating physical volume \"%s\"", pv_name);
|
||||
if (*pv->vg_name) {
|
||||
if (!(fid->ops->vg_write(fid,vg))) {
|
||||
if (!(cmd->fid->ops->vg_write(cmd->fid, vg))) {
|
||||
unlock_vg(cmd, pv->vg_name);
|
||||
log_error("Failed to store physical volume \"%s\" in "
|
||||
"volume group \"%s\"", pv_name, vg->name);
|
||||
return 0;
|
||||
}
|
||||
backup(vg);
|
||||
unlock_vg(cmd, pv->vg_name);
|
||||
} else {
|
||||
if (!(fid->ops->pv_write(fid, pv))) {
|
||||
log_error("Failed to store physical volume \"%s\"",
|
||||
if (!(cmd->fid->ops->pv_write(cmd->fid, pv))) {
|
||||
log_error("Failed to store physical volume \"%s\"",
|
||||
pv_name);
|
||||
return 0;
|
||||
}
|
||||
|
@@ -27,16 +27,19 @@ const char _really_init[] =
|
||||
* See if we may pvcreate on this device.
|
||||
* 0 indicates we may not.
|
||||
*/
|
||||
static int pvcreate_check(const char *name)
|
||||
static int pvcreate_check(struct cmd_context *cmd, const char *name)
|
||||
{
|
||||
struct physical_volume *pv;
|
||||
|
||||
/* is the partition type set correctly ? */
|
||||
if ((arg_count(force_ARG) < 1) && !is_lvm_partition(name))
|
||||
if ((arg_count(cmd, force_ARG) < 1) && !is_lvm_partition(name)) {
|
||||
log_error("%s: Not LVM partition type: use -f to override",
|
||||
name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* is there a pv here already */
|
||||
if (!(pv = fid->ops->pv_read(fid, name)))
|
||||
if (!(pv = cmd->fid->ops->pv_read(cmd->fid, name)))
|
||||
return 1;
|
||||
|
||||
/* orphan ? */
|
||||
@@ -45,20 +48,20 @@ static int pvcreate_check(const char *name)
|
||||
|
||||
/* Allow partial & exported VGs to be destroyed. */
|
||||
/* we must have -ff to overwrite a non orphan */
|
||||
if (arg_count(force_ARG) < 2) {
|
||||
if (arg_count(cmd, force_ARG) < 2) {
|
||||
log_error("Can't initialize physical volume \"%s\" of "
|
||||
"volume group \"%s\" without -ff", name, pv->vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* prompt */
|
||||
if (!arg_count(yes_ARG) &&
|
||||
if (!arg_count(cmd, yes_ARG) &&
|
||||
yes_no_prompt(_really_init, name, pv->vg_name) == 'n') {
|
||||
log_print("Physical volume \"%s\" not initialized", name);
|
||||
log_print("%s: physical volume not initialized", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg_count(force_ARG)) {
|
||||
if (arg_count(cmd, force_ARG)) {
|
||||
log_print("WARNING: Forcing physical volume creation on "
|
||||
"%s%s%s%s", name,
|
||||
pv->vg_name[0] ? " of volume group \"" : "",
|
||||
@@ -69,18 +72,19 @@ static int pvcreate_check(const char *name)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void pvcreate_single(const char *pv_name)
|
||||
static void pvcreate_single(struct cmd_context *cmd, const char *pv_name)
|
||||
{
|
||||
struct physical_volume *pv;
|
||||
struct id id, *idp = NULL;
|
||||
char *uuid;
|
||||
uint64_t size = 0;
|
||||
struct device *dev;
|
||||
|
||||
if (arg_count(uuidstr_ARG)) {
|
||||
uuid = arg_str_value(uuidstr_ARG,"");
|
||||
if (arg_count(cmd, uuidstr_ARG)) {
|
||||
uuid = arg_str_value(cmd, uuidstr_ARG, "");
|
||||
if (!id_read_format(&id, uuid))
|
||||
return;
|
||||
if ((dev = uuid_map_lookup(the_um, &id))) {
|
||||
if ((dev = uuid_map_lookup(cmd->um, &id))) {
|
||||
log_error("uuid %s already in use on \"%s\"", uuid,
|
||||
dev_name(dev));
|
||||
return;
|
||||
@@ -88,20 +92,21 @@ static void pvcreate_single(const char *pv_name)
|
||||
idp = &id;
|
||||
}
|
||||
|
||||
if (!pvcreate_check(pv_name))
|
||||
if (!pvcreate_check(cmd, pv_name))
|
||||
return;
|
||||
|
||||
if (!(pv = pv_create(fid, pv_name, idp))) {
|
||||
log_err("Failed to setup physical volume \"%s\"", pv_name);
|
||||
size = arg_int64_value(cmd, physicalvolumesize_ARG, 0) * 2;
|
||||
if (!(pv = pv_create(cmd->fid, pv_name, idp, size))) {
|
||||
log_error("Failed to setup physical volume \"%s\"", pv_name);
|
||||
return;
|
||||
}
|
||||
|
||||
log_verbose("Set up physical volume for \"%s\" with %" PRIu64
|
||||
" sectors",
|
||||
pv_name, pv->size);
|
||||
" sectors", pv_name, pv->size);
|
||||
|
||||
log_verbose("Writing physical volume data to disk \"%s\"", pv_name);
|
||||
if (!(fid->ops->pv_write(fid, pv))) {
|
||||
log_very_verbose("Writing physical volume data to disk \"%s\"",
|
||||
pv_name);
|
||||
if (!(cmd->fid->ops->pv_write(cmd->fid, pv))) {
|
||||
log_error("Failed to write physical volume \"%s\"", pv_name);
|
||||
return;
|
||||
}
|
||||
@@ -109,7 +114,7 @@ static void pvcreate_single(const char *pv_name)
|
||||
log_print("Physical volume \"%s\" successfully created", pv_name);
|
||||
}
|
||||
|
||||
int pvcreate(int argc, char **argv)
|
||||
int pvcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -118,19 +123,19 @@ int pvcreate(int argc, char **argv)
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(uuidstr_ARG) && argc != 1) {
|
||||
if (arg_count(cmd, uuidstr_ARG) && argc != 1) {
|
||||
log_error("Can only set uuid on one volume at once");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (arg_count(yes_ARG) && !arg_count(force_ARG)) {
|
||||
if (arg_count(cmd, yes_ARG) && !arg_count(cmd, force_ARG)) {
|
||||
log_error("Option y can only be given with option f");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
pvcreate_single(argv[i]);
|
||||
pool_empty(fid->cmd->mem);
|
||||
pvcreate_single(cmd, argv[i]);
|
||||
pool_empty(cmd->mem);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@@ -20,48 +20,47 @@
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
void pvdisplay_single(struct physical_volume *pv);
|
||||
void pvdisplay_single(struct cmd_context *cmd, struct physical_volume *pv);
|
||||
|
||||
int pvdisplay(int argc, char **argv)
|
||||
int pvdisplay(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
int opt=0;
|
||||
int opt = 0;
|
||||
|
||||
struct list *pvh, *pvs;
|
||||
struct physical_volume *pv;
|
||||
|
||||
if (arg_count(colon_ARG) && arg_count(maps_ARG)) {
|
||||
if (arg_count(cmd, colon_ARG) && arg_count(cmd, maps_ARG)) {
|
||||
log_error("Option -v not allowed with option -c");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (argc) {
|
||||
log_very_verbose("Using physical volume(s) on command line");
|
||||
if (argc) {
|
||||
log_very_verbose("Using physical volume(s) on command line");
|
||||
|
||||
for (; opt < argc; opt++) {
|
||||
if (!(pv = fid->ops->pv_read(fid, argv[opt]))) {
|
||||
log_error("Failed to read physical "
|
||||
"volume \"%s\"",
|
||||
argv[opt]);
|
||||
if (!(pv = cmd->fid->ops->pv_read(cmd->fid, argv[opt]))) {
|
||||
log_error("Failed to read physical "
|
||||
"volume \"%s\"", argv[opt]);
|
||||
continue;
|
||||
}
|
||||
pvdisplay_single(pv);
|
||||
pvdisplay_single(cmd, pv);
|
||||
}
|
||||
} else {
|
||||
log_verbose("Scanning for physical volume names");
|
||||
if (!(pvs = fid->ops->get_pvs(fid)))
|
||||
return ECMD_FAILED;
|
||||
log_verbose("Scanning for physical volume names");
|
||||
if (!(pvs = cmd->fid->ops->get_pvs(cmd->fid)))
|
||||
return ECMD_FAILED;
|
||||
|
||||
list_iterate(pvh, pvs)
|
||||
pvdisplay_single(list_item(pvh, struct pv_list)->pv);
|
||||
list_iterate(pvh, pvs)
|
||||
pvdisplay_single(cmd, list_item(pvh, struct pv_list)->pv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pvdisplay_single(struct physical_volume *pv)
|
||||
void pvdisplay_single(struct cmd_context *cmd, struct physical_volume *pv)
|
||||
{
|
||||
char *sz;
|
||||
uint64_t size;
|
||||
uint64_t size;
|
||||
|
||||
const char *pv_name = dev_name(pv->dev);
|
||||
|
||||
@@ -70,7 +69,7 @@ void pvdisplay_single(struct physical_volume *pv)
|
||||
else
|
||||
size = (pv->pe_count - pv->pe_allocated) * pv->pe_size;
|
||||
|
||||
if (arg_count(short_ARG)) {
|
||||
if (arg_count(cmd, short_ARG)) {
|
||||
sz = display_size(size / 2, SIZE_SHORT);
|
||||
log_print("Device \"%s\" has a capacity of %s", pv_name, sz);
|
||||
dbg_free(sz);
|
||||
@@ -78,17 +77,16 @@ void pvdisplay_single(struct physical_volume *pv)
|
||||
}
|
||||
|
||||
if (pv->status & EXPORTED_VG)
|
||||
log_print("Physical volume \"%s\" of volume group \"%s\" "
|
||||
"is exported" , pv_name, pv->vg_name);
|
||||
log_print("Physical volume \"%s\" of volume group \"%s\" "
|
||||
"is exported", pv_name, pv->vg_name);
|
||||
|
||||
/********* FIXME
|
||||
log_error("no physical volume identifier on \"%s\"" , pv_name);
|
||||
*********/
|
||||
|
||||
if (!pv->vg_name) {
|
||||
log_print ( "\"%s\" is a new physical volume of \"%s\"",
|
||||
pv_name, ( sz = display_size ( size / 2,
|
||||
SIZE_SHORT)));
|
||||
log_print("\"%s\" is a new physical volume of \"%s\"",
|
||||
pv_name, (sz = display_size(size / 2, SIZE_SHORT)));
|
||||
dbg_free(sz);
|
||||
}
|
||||
|
||||
@@ -103,14 +101,14 @@ void pvdisplay_single(struct physical_volume *pv)
|
||||
ret = pv_check_consistency (pv)
|
||||
*/
|
||||
|
||||
if (arg_count(colon_ARG)) {
|
||||
if (arg_count(cmd, colon_ARG)) {
|
||||
pvdisplay_colons(pv);
|
||||
return;
|
||||
}
|
||||
|
||||
pvdisplay_full(pv);
|
||||
|
||||
if (!arg_count(maps_ARG))
|
||||
if (!arg_count(cmd, maps_ARG))
|
||||
return;
|
||||
|
||||
/******* FIXME
|
||||
@@ -129,4 +127,3 @@ void pvdisplay_single(struct physical_volume *pv)
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user