mirror of
git://sourceware.org/git/lvm2.git
synced 2025-10-23 23:33:15 +03:00
Compare commits
362 Commits
old-beta3
...
old-dm_v1_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e7a308528 | ||
|
|
7952177786 | ||
|
|
9afbe49c84 | ||
|
|
9f06ba2db3 | ||
|
|
fe55bfddcf | ||
|
|
c0842e6444 | ||
|
|
3fed20d06a | ||
|
|
5e8f2e2c04 | ||
|
|
e4df99ea84 | ||
|
|
b3276f5f11 | ||
|
|
32667ca256 | ||
|
|
bed122a170 | ||
|
|
14adc9b875 | ||
|
|
a8778bbc5a | ||
|
|
a54e641f44 | ||
|
|
5c99efe87a | ||
|
|
7da1d731ff | ||
|
|
af9828e819 | ||
|
|
7a27136142 | ||
|
|
012ad2d423 | ||
|
|
ef3bdbf4da | ||
|
|
b3bb698f7b | ||
|
|
1ed5d1e4c1 | ||
|
|
bdee01a03d | ||
|
|
458f7376d7 | ||
|
|
cb3a00e027 | ||
|
|
482eb1f3fb | ||
|
|
6e0f638f5e | ||
|
|
bab349047d | ||
|
|
28ea6b8de8 | ||
|
|
9d51bbdae8 | ||
|
|
d622f79533 | ||
|
|
04c8515ad1 | ||
|
|
53bc4251d1 | ||
|
|
a5a751f02f | ||
|
|
66ed5f82c4 | ||
|
|
c802a9e6aa | ||
|
|
880f210946 | ||
|
|
4f9f7eb6a6 | ||
|
|
f910c4a8e7 | ||
|
|
529686d965 | ||
|
|
84dfd1536f | ||
|
|
85dedc324c | ||
|
|
d639237411 | ||
|
|
449aaf75f1 | ||
|
|
b1fda66caa | ||
|
|
66a8e90fd9 | ||
|
|
37b487d191 | ||
|
|
6c59fe3577 | ||
|
|
1cbb70c992 | ||
|
|
e06b39f882 | ||
|
|
2602b1493e | ||
|
|
989d14502d | ||
|
|
f78a550282 | ||
|
|
54a1abb284 | ||
|
|
97b492a8e2 | ||
|
|
0873bd14a9 | ||
|
|
eff6ba429a | ||
|
|
8c18064be4 | ||
|
|
44a1ac0cf3 | ||
|
|
28dc8d88dd | ||
|
|
2c0c2b64ba | ||
|
|
bd3e0f5248 | ||
|
|
cd52d98938 | ||
|
|
894c70e7f8 | ||
|
|
51d70c2edd | ||
|
|
7d4b355240 | ||
|
|
3b56193b98 | ||
|
|
b16045b57d | ||
|
|
9e8b0fca5b | ||
|
|
35cf1b3b5b | ||
|
|
83f788af57 | ||
|
|
2ffe378d3f | ||
|
|
38b33a4a5e | ||
|
|
60bf9ed0a0 | ||
|
|
16adf4de1b | ||
|
|
80de983023 | ||
|
|
8703ca623f | ||
|
|
286253a73f | ||
|
|
bd806a41df | ||
|
|
b89c4e9002 | ||
|
|
6dbf31c0c3 | ||
|
|
060c45d8a1 | ||
|
|
33d3e82e4d | ||
|
|
4bb074514d | ||
|
|
e3f8892003 | ||
|
|
9d00ad5f18 | ||
|
|
dae4344850 | ||
|
|
aa7f3fabe2 | ||
|
|
f93434a8ce | ||
|
|
25dee56be9 | ||
|
|
ce9a3f3797 | ||
|
|
11e384920a | ||
|
|
a0a1f1e536 | ||
|
|
3b3d0ea9eb | ||
|
|
2f4d78286d | ||
|
|
677dc6f985 | ||
|
|
d52057e732 | ||
|
|
fa2a1cb1fb | ||
|
|
19a0fb04ad | ||
|
|
947352f2fe | ||
|
|
adcbedb686 | ||
|
|
7732f92acd | ||
|
|
ad8a001688 | ||
|
|
9121eada08 | ||
|
|
49bd4d25a2 | ||
|
|
d80b4129c6 | ||
|
|
7edb4172d5 | ||
|
|
c3a4677990 | ||
|
|
5cbb893a3b | ||
|
|
f28a2a432b | ||
|
|
03b75a2d27 | ||
|
|
859fe69083 | ||
|
|
f6f2205ddb | ||
|
|
0f9a03ef61 | ||
|
|
9aa417c084 | ||
|
|
7b70952f5d | ||
|
|
edd3d07b49 | ||
|
|
5293d0a4ec | ||
|
|
3c8c7beae1 | ||
|
|
9c3ba9fdcd | ||
|
|
fb1748fb0f | ||
|
|
0a109fbd03 | ||
|
|
5cf64db74e | ||
|
|
488cc94f36 | ||
|
|
e15846bf79 | ||
|
|
752bd00674 | ||
|
|
7fadfcbe32 | ||
|
|
41141e75bb | ||
|
|
50f641e627 | ||
|
|
c7883fd093 | ||
|
|
4fcb24b2b1 | ||
|
|
5003557935 | ||
|
|
bdf1ba84da | ||
|
|
b0b4def983 | ||
|
|
cc184bbe9e | ||
|
|
ad30c830aa | ||
|
|
1d791a8af4 | ||
|
|
e63c51cd97 | ||
|
|
f202e32908 | ||
|
|
26e1a08e82 | ||
|
|
4d5119d435 | ||
|
|
75e34ea62e | ||
|
|
0a183d6274 | ||
|
|
21d8060aea | ||
|
|
9cbe906f60 | ||
|
|
8ce4137399 | ||
|
|
5f8a139347 | ||
|
|
9bb009a3fe | ||
|
|
726d65923f | ||
|
|
8a6be4cb2d | ||
|
|
10b06beb8e | ||
|
|
81318c7968 | ||
|
|
47a2c1c6e5 | ||
|
|
39cee65c6b | ||
|
|
8582ec724e | ||
|
|
b0139682e8 | ||
|
|
d39c475a6d | ||
|
|
48f38354c6 | ||
|
|
cd5a920ed5 | ||
|
|
71bc1f378d | ||
|
|
0ee6c31cff | ||
|
|
af89a9971e | ||
|
|
c718a8ef72 | ||
|
|
8c8ad0faf0 | ||
|
|
314d5bbb7f | ||
|
|
102255757a | ||
|
|
914067a0d0 | ||
|
|
06e3ae2536 | ||
|
|
7f9b252556 | ||
|
|
3d700e243f | ||
|
|
bcfc78ce11 | ||
|
|
09241765d5 | ||
|
|
671c83c265 | ||
|
|
772d28b766 | ||
|
|
c26fcea58d | ||
|
|
1e5e26dbff | ||
|
|
742fc54864 | ||
|
|
49738f43c0 | ||
|
|
9f85f61010 | ||
|
|
239f422039 | ||
|
|
67af3c37be | ||
|
|
a9442385c4 | ||
|
|
8c9cd10b8b | ||
|
|
72542059dd | ||
|
|
a843fc6d40 | ||
|
|
4beed60c08 | ||
|
|
4049c1e480 | ||
|
|
8449314da2 | ||
|
|
63ad057028 | ||
|
|
e720464330 | ||
|
|
24036afef9 | ||
|
|
c78fa1a1bc | ||
|
|
faa8b9022c | ||
|
|
729bafef7a | ||
|
|
590b028632 | ||
|
|
8150d00f36 | ||
|
|
060065926f | ||
|
|
70babe8a28 | ||
|
|
c36e09664f | ||
|
|
a9672246f3 | ||
|
|
ff571884e9 | ||
|
|
475138bceb | ||
|
|
4a8af199c2 | ||
|
|
bdabf5db72 | ||
|
|
6a5f21b34e | ||
|
|
d608be103c | ||
|
|
374bb5d18a | ||
|
|
031d6c25ff | ||
|
|
223fb7b075 | ||
|
|
a746741971 | ||
|
|
120faf2a58 | ||
|
|
990bca0dc6 | ||
|
|
3406472db7 | ||
|
|
1bd733c9f6 | ||
|
|
238c7f982e | ||
|
|
fcb81147cb | ||
|
|
1915b73783 | ||
|
|
ee79e621fb | ||
|
|
d203275a3b | ||
|
|
9e8a996222 | ||
|
|
0126b0b3ed | ||
|
|
458928612c | ||
|
|
e33f88e28d | ||
|
|
be570bbf9e | ||
|
|
f59b4be110 | ||
|
|
37336e41be | ||
|
|
d24a1a3f0a | ||
|
|
f7258955bd | ||
|
|
2a1eae5d6f | ||
|
|
50ee0a4adb | ||
|
|
955a26584e | ||
|
|
1d3e407c8f | ||
|
|
cb809c4596 | ||
|
|
53bbe2888e | ||
|
|
7246f476a5 | ||
|
|
0785d1c390 | ||
|
|
85d2c49d14 | ||
|
|
8b77d62b7f | ||
|
|
373058a32a | ||
|
|
e6293c2c8c | ||
|
|
eff181c959 | ||
|
|
54752c2305 | ||
|
|
b4753c044f | ||
|
|
26493424ae | ||
|
|
0282fd1332 | ||
|
|
b9a019a08b | ||
|
|
66f6a0e687 | ||
|
|
2dd1b9f97d | ||
|
|
89615f3045 | ||
|
|
7e46192f67 | ||
|
|
e78d985cdf | ||
|
|
e8c4bf56fe | ||
|
|
e6aa7d323d | ||
|
|
fca8e25929 | ||
|
|
8e8ac286b4 | ||
|
|
7d9770b9a2 | ||
|
|
1996230460 | ||
|
|
de7897a864 | ||
|
|
e2884dcdb7 | ||
|
|
544a53a42b | ||
|
|
2e4787bfc8 | ||
|
|
1829eeb171 | ||
|
|
c7488e3c4a | ||
|
|
3bf9606383 | ||
|
|
4f43f18f0a | ||
|
|
5b7f197397 | ||
|
|
018141c97f | ||
|
|
4d7813e57c | ||
|
|
605c60208f | ||
|
|
884fafcc30 | ||
|
|
56baa90320 | ||
|
|
6bb20ee09e | ||
|
|
541356430c | ||
|
|
2f4d91fd69 | ||
|
|
f58c5e6b30 | ||
|
|
0311d0132c | ||
|
|
c946c97402 | ||
|
|
84a6f51318 | ||
|
|
24a1501b0d | ||
|
|
383b6f5fcc | ||
|
|
633dd7ff9b | ||
|
|
580624fad6 | ||
|
|
a8190f7efa | ||
|
|
dd2157534b | ||
|
|
38a90e7669 | ||
|
|
6bfc526dcd | ||
|
|
aadb8a7405 | ||
|
|
27082bf77e | ||
|
|
a2903c80cd | ||
|
|
9a77c5369c | ||
|
|
3c30741a19 | ||
|
|
7028ad4ec0 | ||
|
|
8de750c6aa | ||
|
|
04f98de9ee | ||
|
|
a1a019784b | ||
|
|
4aeeae77bd | ||
|
|
651cfc2b78 | ||
|
|
2ef8af25e2 | ||
|
|
0b13852a5b | ||
|
|
13427578c9 | ||
|
|
d89ca2087e | ||
|
|
8b0ea9fba6 | ||
|
|
9f0b653d5a | ||
|
|
659a339233 | ||
|
|
4c29f177a0 | ||
|
|
d664e63d55 | ||
|
|
2493509dbe | ||
|
|
1c8b27f554 | ||
|
|
68297b7186 | ||
|
|
34dd8d0a91 | ||
|
|
81c44790d5 | ||
|
|
d557b335cf | ||
|
|
e2adc28cff | ||
|
|
0fef6a6ecc | ||
|
|
f2fd4b8a1f | ||
|
|
95bd5605a8 | ||
|
|
497cca7eca | ||
|
|
54f78feedd | ||
|
|
76408e53ae | ||
|
|
be19e74d30 | ||
|
|
dac578a775 | ||
|
|
04732ce74b | ||
|
|
a6c95a2374 | ||
|
|
f68622abe9 | ||
|
|
83a9a7bdb2 | ||
|
|
6500afc0ca | ||
|
|
c69b7ecc96 | ||
|
|
615ef1e2d2 | ||
|
|
cf69a0cd7f | ||
|
|
06e892fb33 | ||
|
|
e6c5dd6865 | ||
|
|
247efdebdb | ||
|
|
76f3792287 | ||
|
|
64d8e2c727 | ||
|
|
ead0bd9cb0 | ||
|
|
66fc13b2ec | ||
|
|
f3af4128b0 | ||
|
|
0e43107c87 | ||
|
|
1ee3e7997e | ||
|
|
50fd61d91f | ||
|
|
e4cdc051a9 | ||
|
|
778e846e96 | ||
|
|
a27759b647 | ||
|
|
b75eceab41 | ||
|
|
e748a5d5f4 | ||
|
|
99c5a3ae46 | ||
|
|
51da710f5a | ||
|
|
569d69b3d2 | ||
|
|
059a6b1d90 | ||
|
|
990af7548a | ||
|
|
a38aefdfc8 | ||
|
|
3bcb12e7d1 | ||
|
|
7904ecb462 | ||
|
|
9ba4d45109 | ||
|
|
56b8afe19d | ||
|
|
f7aed9a94c | ||
|
|
e12a7e881d | ||
|
|
5afb65325d | ||
|
|
135f520f32 | ||
|
|
bc251f4ff6 | ||
|
|
b8769751f6 |
21
INSTALL
21
INSTALL
@@ -6,8 +6,8 @@ LVM2 installation
|
|||||||
Ensure the device-mapper has been installed on the machine.
|
Ensure the device-mapper has been installed on the machine.
|
||||||
|
|
||||||
The device-mapper should be in the kernel (look for 'device-mapper'
|
The device-mapper should be in the kernel (look for 'device-mapper'
|
||||||
messages in the kernel logs) and /usr/include/libdevmapper.h should
|
messages in the kernel logs) and /usr/include/libdevmapper.h
|
||||||
be present.
|
and libdevmapper.so should be present.
|
||||||
|
|
||||||
The device-mapper is available from:
|
The device-mapper is available from:
|
||||||
ftp://ftp.sistina.com/pub/LVM2/device-mapper/
|
ftp://ftp.sistina.com/pub/LVM2/device-mapper/
|
||||||
@@ -17,9 +17,15 @@ LVM2 installation
|
|||||||
|
|
||||||
Run the 'configure' script from the top directory.
|
Run the 'configure' script from the top directory.
|
||||||
|
|
||||||
If you do not have GNU readline (http://www.gnu.org/directory/readline.html)
|
If you wish to use the built-in LVM2 shell and have GNU readline
|
||||||
installed use
|
installed (http://www.gnu.org/directory/readline.html) use:
|
||||||
./configure --disable-readline
|
./configure --enable-readline
|
||||||
|
|
||||||
|
If you don't want to include the LVM1 backwards-compatibility code use:
|
||||||
|
./configure --with-lvm1=none
|
||||||
|
|
||||||
|
To separate the LVM1 support into a shared library loaded by lvm.conf use:
|
||||||
|
./configure --with-lvm1=shared
|
||||||
|
|
||||||
|
|
||||||
3) Build and install LVM2.
|
3) Build and install LVM2.
|
||||||
@@ -31,6 +37,9 @@ LVM2 installation
|
|||||||
|
|
||||||
The tools will work fine without a configuration file being
|
The tools will work fine without a configuration file being
|
||||||
present, but you ought to review the example file in doc/example.conf.
|
present, but you ought to review the example file in doc/example.conf.
|
||||||
For example, specifying the devices that LVM2 is to use should
|
For example, specifying the devices that LVM2 is to use can
|
||||||
make the tools run more efficiently - and avoid scanning /dev/cdrom!
|
make the tools run more efficiently - and avoid scanning /dev/cdrom!
|
||||||
|
|
||||||
|
Please also refer to the WHATS_NEW file and the manual pages for the
|
||||||
|
individual commands.
|
||||||
|
|
||||||
|
|||||||
18
INTRO
18
INTRO
@@ -1,18 +0,0 @@
|
|||||||
An introduction to LVM2
|
|
||||||
=======================
|
|
||||||
|
|
||||||
Background
|
|
||||||
|
|
||||||
|
|
||||||
Compatibility with LVM1
|
|
||||||
|
|
||||||
|
|
||||||
New features
|
|
||||||
|
|
||||||
|
|
||||||
Missing features
|
|
||||||
|
|
||||||
|
|
||||||
Future enhancements
|
|
||||||
|
|
||||||
|
|
||||||
43
Makefile.in
43
Makefile.in
@@ -1,34 +1,45 @@
|
|||||||
#
|
#
|
||||||
# Copyright (C) 2001 Sistina Software
|
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
#
|
#
|
||||||
# This LVM library is free software; you can redistribute it and/or
|
# This file is part of the LVM2.
|
||||||
# modify it under the terms of the GNU Library General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2 of the License, or (at your option) any later version.
|
|
||||||
#
|
#
|
||||||
# This LVM library is distributed in the hope that it will be useful,
|
# This copyrighted material is made available to anyone wishing to use,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# modify, copy, or redistribute it subject to the terms and conditions
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
# of the GNU General Public License v.2.
|
||||||
# Library General Public License for more details.
|
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Library General Public
|
# You should have received a copy of the GNU General Public License
|
||||||
# License along with this LVM library; if not, write to the Free
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
# MA 02111-1307, USA
|
|
||||||
|
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@
|
||||||
|
|
||||||
SUBDIRS = include man lib tools
|
SUBDIRS = doc include man
|
||||||
|
|
||||||
|
ifeq ("@INTL@", "yes")
|
||||||
|
SUBDIRS += po
|
||||||
|
endif
|
||||||
|
|
||||||
|
SUBDIRS += lib tools
|
||||||
|
|
||||||
ifeq ($(MAKECMDGOALS),distclean)
|
ifeq ($(MAKECMDGOALS),distclean)
|
||||||
SUBDIRS += test/mm test/device test/format1 test/regex test/filters
|
SUBDIRS += lib/format1 \
|
||||||
|
po \
|
||||||
|
test/mm test/device test/format1 test/regex test/filters
|
||||||
endif
|
endif
|
||||||
|
|
||||||
include make.tmpl
|
include make.tmpl
|
||||||
|
|
||||||
lib: include
|
lib: include
|
||||||
tools: include lib
|
tools: lib
|
||||||
|
po: lib tools
|
||||||
|
|
||||||
|
ifeq ("@INTL@", "yes")
|
||||||
|
lib.pofile: include.pofile
|
||||||
|
tools.pofile: lib.pofile
|
||||||
|
po.pofile: lib.pofile tools.pofile
|
||||||
|
pofile: po.pofile
|
||||||
|
endif
|
||||||
|
|
||||||
|
|||||||
18
README
18
README
@@ -1,13 +1,11 @@
|
|||||||
This directory contains a beta release of LMV2, the new version of
|
This directory contains LVM2, the new version of the userland LVM
|
||||||
the userland LVM tools designed for the new device-mapper for
|
tools designed for the new device-mapper for the Linux kernel.
|
||||||
the Linux kernel.
|
|
||||||
|
|
||||||
The device-mapper needs to be installed before compiling these LVM2 tools.
|
The device-mapper needs to be installed before compiling these LVM2 tools.
|
||||||
|
|
||||||
For more information about LVM2 read the INTRO file.
|
For more information about LVM2 read the WHATS_NEW file.
|
||||||
Installation instructions are in INSTALL.
|
Installation instructions are in INSTALL.
|
||||||
|
|
||||||
This is beta-quality software, released for testing purposes only.
|
|
||||||
There is no warranty - see COPYING and COPYING.LIB.
|
There is no warranty - see COPYING and COPYING.LIB.
|
||||||
|
|
||||||
Tarballs are available from:
|
Tarballs are available from:
|
||||||
@@ -15,11 +13,11 @@ Tarballs are available from:
|
|||||||
ftp://ftp.sistina.com/pub/LVM2/device-mapper/
|
ftp://ftp.sistina.com/pub/LVM2/device-mapper/
|
||||||
|
|
||||||
To access the CVS tree use:
|
To access the CVS tree use:
|
||||||
cvs -d :pserver:cvs@tech.sistina.com:/data/cvs login
|
cvs -d :pserver:cvs@sources.redhat.com:/cvs/lvm2 login
|
||||||
CVS password: cvs1
|
CVS password: cvs
|
||||||
cvs -d :pserver:cvs@tech.sistina.com:/data/cvs checkout LVM2
|
cvs -d :pserver:cvs@sources.redhat.com:/cvs/lvm2 co LVM2
|
||||||
|
|
||||||
Mailing list for discussion/bug reports etc.
|
Mailing list for discussion/bug reports etc.
|
||||||
lvm-devel@sistina.com
|
linux-lvm@redhat.com
|
||||||
Subscribe from http://lists.sistina.com/mailman/listinfo/lvm-devel
|
Subscribe from https://www.redhat.com/mailman/listinfo/linux-lvm
|
||||||
|
|
||||||
|
|||||||
28
TODO
28
TODO
@@ -1,28 +0,0 @@
|
|||||||
before 2.0
|
|
||||||
-----------
|
|
||||||
|
|
||||||
vgexport
|
|
||||||
vgimport
|
|
||||||
snapshots
|
|
||||||
pvmove
|
|
||||||
device-mapper support for 2.5 kernel series
|
|
||||||
review FIXMEs
|
|
||||||
extra validation & full consistency checks in format1 with LVM1
|
|
||||||
partial activation (aka VG quorum)
|
|
||||||
error message review
|
|
||||||
locking during metadata changes
|
|
||||||
format2 with atomic transactions
|
|
||||||
bidirectional format1/format2 migration tool
|
|
||||||
persistent minors
|
|
||||||
statistics target and tool support
|
|
||||||
review tool exit codes for LVM1 compatibility
|
|
||||||
|
|
||||||
before 2.1
|
|
||||||
----------
|
|
||||||
|
|
||||||
e2fsadm
|
|
||||||
lvmsadc
|
|
||||||
lvmsar
|
|
||||||
pvdata
|
|
||||||
vgsplit
|
|
||||||
vgmknodes
|
|
||||||
162
WHATS_NEW
Normal file
162
WHATS_NEW
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
Version 2.00.13 - 64 Apr 2004
|
||||||
|
=============================
|
||||||
|
Ignore error setting selinux file context if fs doesn't support it.
|
||||||
|
|
||||||
|
Version 2.00.12 - 14 Apr 2004
|
||||||
|
=============================
|
||||||
|
Install a default lvm.conf into /etc/lvm if there isn't one already.
|
||||||
|
Allow different installation dir for lvm.static (configure --staticdir=)
|
||||||
|
Fix inverted selinux error check.
|
||||||
|
Recognise power2 in /proc/devices.
|
||||||
|
Fix counting in lvs_in_vg_opened. [It ignored devices open more than once.]
|
||||||
|
|
||||||
|
Version 2.00.11 - 8 Apr 2004
|
||||||
|
============================
|
||||||
|
Set fallback_to_lvm1 in lvm.conf (or configure --enable-lvm1_fallback)
|
||||||
|
to run lvm1 binaries if running a 2.4 kernel without device-mapper.
|
||||||
|
|
||||||
|
Version 2.00.10 - 7 Apr 2004
|
||||||
|
============================
|
||||||
|
More fixes for static build.
|
||||||
|
Add basic selinux support.
|
||||||
|
Fix sysfs detection.
|
||||||
|
|
||||||
|
Version 2.00.09 - 31 Mar 2004
|
||||||
|
=============================
|
||||||
|
Update copyright notices for Red Hat.
|
||||||
|
Fix vgmknodes to remove dud /dev/mapper entries. (libdevmapper update reqd).
|
||||||
|
Add LVM1-style colon output to vgdisplay.
|
||||||
|
lvchange --refresh to reload active LVs.
|
||||||
|
Add string display to memory leak dump.
|
||||||
|
Add locking flags & memlock option.
|
||||||
|
Add list_versions to library.
|
||||||
|
Ignore open hidden LVs when checking if deactivation is OK.
|
||||||
|
Suppress move percentage when device inactive.
|
||||||
|
Add lv_info_by_lvid.
|
||||||
|
Various tidy-ups to the build process.
|
||||||
|
Rebaseline internal verbose level.
|
||||||
|
Add --nolocking option for read operations if locking is failing.
|
||||||
|
Add option to compile into a library.
|
||||||
|
When compiled without libdevmapper, only print warning message once.
|
||||||
|
Fix lvreduce PV extent calculations.
|
||||||
|
Fix DESTDIR to work with configure path overrides.
|
||||||
|
Always use / as config file separator & rename internal config file variables.
|
||||||
|
Add support for tagging PV/VG/LVs and hosts.
|
||||||
|
Fix rare bug in recognition of long cmdline argument forms.
|
||||||
|
Add basic internationalisation infrastructure.
|
||||||
|
Don't recurse symlinked dirs such as /dev/fd on 2.6 kernels.
|
||||||
|
Update autoconf files.
|
||||||
|
Add sysfs block device filtering for 2.6 kernels.
|
||||||
|
Update refs for move to sources.redhat.com.
|
||||||
|
|
||||||
|
Friday 14th November 2003
|
||||||
|
=========================
|
||||||
|
Some bug fixes & minor enhancements, including:
|
||||||
|
Backwards compatibility with LVM1 metadata improved.
|
||||||
|
Missing man pages written.
|
||||||
|
Tool error codes made more consistent.
|
||||||
|
vgmknodes written.
|
||||||
|
O_DIRECT can be turned off if it doesn't work in your kernel.
|
||||||
|
dumpconfig to display the active configuration file
|
||||||
|
|
||||||
|
You need to update libdevmapper before using 'vgmknodes' or 'vgscan --mknodes'.
|
||||||
|
If your root filesystem is on an LV, you should run one of those two
|
||||||
|
commands to fix up the special files in /dev in your real root filesystem
|
||||||
|
after finishing with your initrd. Also, remember you can use
|
||||||
|
'vgchange --ignorelockingfailure' on your initrd if the tool fails because
|
||||||
|
it can't write a lock file to a read-only filesystem.
|
||||||
|
|
||||||
|
Wednesday 30th April 2003
|
||||||
|
=========================
|
||||||
|
A pvmove implementation is now available for the new metadata format.
|
||||||
|
|
||||||
|
When running a command that allocates space (e.g. lvcreate), you can now
|
||||||
|
restrict not only which disk(s) may be used but also the Physical Extents
|
||||||
|
on those disks. e.g. lvcreate -L 10 vg1 /dev/hda6:1000-2000:3000-4000
|
||||||
|
|
||||||
|
|
||||||
|
Monday 18th November 2002
|
||||||
|
========================
|
||||||
|
|
||||||
|
The new format of LVM metadata is ready for you to test!
|
||||||
|
We expect it to be more efficient and more robust than the original format.
|
||||||
|
It's more compact and supports transactional changes and replication.
|
||||||
|
Should things go wrong on a system, it's human-readable (and editable).
|
||||||
|
|
||||||
|
Please report any problems you find to the mailing list,
|
||||||
|
linux-lvm@sistina.com. The software has NOT yet been thoroughly
|
||||||
|
tested and so quite possibly there'll still be some bugs in it.
|
||||||
|
Be aware of the disclaimer in the COPYING file.
|
||||||
|
|
||||||
|
While testing, we recommend turning logging on in the configuration file
|
||||||
|
to provide us with diagnostic information:
|
||||||
|
log {
|
||||||
|
file="/tmp/lvm2.log"
|
||||||
|
level=7
|
||||||
|
activation=1
|
||||||
|
}
|
||||||
|
|
||||||
|
You should schedule regular backups of your configuration file and
|
||||||
|
metadata backups and archives (normally kept under /etc/lvm).
|
||||||
|
|
||||||
|
Please read docs/example.conf and "man lvm.conf" to find out more about
|
||||||
|
the configuration file.
|
||||||
|
|
||||||
|
To convert an existing volume group called vg1 to the new format using
|
||||||
|
the default settings, use "vgconvert -M2 vg1". See "man vgconvert".
|
||||||
|
|
||||||
|
-M (or --metadatatype in its long form) is a new flag to indicate which
|
||||||
|
format of metadata the command should use for anything it creates.
|
||||||
|
Currently, the valid types are "lvm1" and "lvm2" and they can be
|
||||||
|
abbreviated to "1" and "2" respectively. The default value for this
|
||||||
|
flag can be changed in the global section in the config file.
|
||||||
|
|
||||||
|
Backwards-compatible support for the original LVM1 metadata format is
|
||||||
|
maintained, but it can be moved into a shared library or removed
|
||||||
|
completely with configure's --with-lvm1 option.
|
||||||
|
|
||||||
|
Under LVM2, the basic unit of metadata is the volume group. Different
|
||||||
|
volume groups can use different formats of metadata - vg1 could use
|
||||||
|
the original LVM1 format while vg2 used the new format - but you can't
|
||||||
|
mix formats within a volume group. So to add a PV to an LVM2-format
|
||||||
|
volume group you must run "pvcreate -M2" on it, followed by "vgextend".
|
||||||
|
|
||||||
|
With LVM2-format metadata, lvextend will let you specify striping
|
||||||
|
parameters. So an LV could consist of two or more "segments" - the
|
||||||
|
first segment could have 3 stripes while the second segment has just 2.
|
||||||
|
|
||||||
|
LVM2 maintains a backup of the current metadata for each volume group
|
||||||
|
in /etc/lvm/backup, and puts copies of previous versions in
|
||||||
|
/etc/lvm/archive. "vgcfgbackup" and "vgcfgrestore" can be used to
|
||||||
|
create and restore from these files. If you fully understand what
|
||||||
|
you're doing, metadata can be changed by editing a copy of a current
|
||||||
|
backup file and using vgcfgrestore to reload it.
|
||||||
|
|
||||||
|
Please read the pvcreate man page for more information on the new
|
||||||
|
format for metadata.
|
||||||
|
|
||||||
|
All tools that can change things have a --test flag which can be used
|
||||||
|
to check the effect of a set of cmdline args without really making the
|
||||||
|
changes.
|
||||||
|
|
||||||
|
|
||||||
|
What's not finished?
|
||||||
|
====================
|
||||||
|
The internal cache. If you turn on debugging output you'll see lots of
|
||||||
|
repeated messages, many of which will eventually get optimised out.
|
||||||
|
|
||||||
|
--test sometimes causes a command to fail (e.g. vgconvert --test) even
|
||||||
|
though the real command would work: again, fixing this is waiting for
|
||||||
|
the work on the cache.
|
||||||
|
|
||||||
|
Several of the tools do not yet contain the logic to handle full
|
||||||
|
recovery: combinations of pvcreate and vgcfgrestore may sometimes be
|
||||||
|
needed to restore metadata if a tool gets interrupted or crashes or
|
||||||
|
finds something unexpected. This applies particularly to tools that
|
||||||
|
work on more than one volume group at once (e.g. vgsplit).
|
||||||
|
|
||||||
|
Display output. Some metadata information cannot yet be displayed.
|
||||||
|
|
||||||
|
Recovery tools to salvage "lost" metadata directly from the disks:
|
||||||
|
but we hope the new format will mean such tools are hardly ever needed!
|
||||||
|
|
||||||
54
WHATS_NEW_DM
Normal file
54
WHATS_NEW_DM
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
Version 1.00.16 - 16 Apr 2004
|
||||||
|
=============================
|
||||||
|
Ignore error setting selinux file context if fs doesn't support it.
|
||||||
|
|
||||||
|
Version 1.00.15 - 7 Apr 2004
|
||||||
|
============================
|
||||||
|
Fix status overflow check in kernel patches.
|
||||||
|
|
||||||
|
Version 1.00.14 - 6 Apr 2004
|
||||||
|
============================
|
||||||
|
Fix static selinux build.
|
||||||
|
|
||||||
|
Version 1.00.13 - 6 Apr 2004
|
||||||
|
============================
|
||||||
|
Add some basic selinux support.
|
||||||
|
|
||||||
|
Version 1.00.12 - 6 Apr 2004
|
||||||
|
============================
|
||||||
|
Fix dmsetup.static install.
|
||||||
|
|
||||||
|
Version 1.00.11 - 5 Apr 2004
|
||||||
|
============================
|
||||||
|
configure --enable-static_link does static build in addition to dynamic.
|
||||||
|
Moved Makefile library targets definition into template.
|
||||||
|
|
||||||
|
Version 1.00.10 - 2 Apr 2004
|
||||||
|
============================
|
||||||
|
Fix DESTDIR handling.
|
||||||
|
Static build installs to dmsetup.static.
|
||||||
|
Basic support for internationalisation.
|
||||||
|
Minor Makefile tidy-ups/fixes.
|
||||||
|
|
||||||
|
Version 1.00.09 - 31 Mar 2004
|
||||||
|
=============================
|
||||||
|
Update copyright notices to Red Hat.
|
||||||
|
Move full mknodes functionality from dmsetup into libdevmapper.
|
||||||
|
Avoid sscanf %as for uClibc compatibility.
|
||||||
|
Cope if DM_LIST_VERSIONS is not defined.
|
||||||
|
Add DM_LIST_VERSIONS functionality to kernel patches.
|
||||||
|
Generate new kernel patches for 2.4.26-rc1.
|
||||||
|
|
||||||
|
Version 1.00.08 - 27 Feb 2004
|
||||||
|
=============================
|
||||||
|
Added 'dmsetup targets'.
|
||||||
|
Added event_nr support to 'dmsetup wait'.
|
||||||
|
Updated dmsetup man page.
|
||||||
|
Allow logging function to be reset to use internal one.
|
||||||
|
Bring log macros in line with LVM2 ones.
|
||||||
|
Added 'make install_static_lib' which installs libdevmapper.a.
|
||||||
|
Made configure/makefiles closer to LVM2 versions.
|
||||||
|
Fixed DESTDIR for make install/install_static_lib.
|
||||||
|
Updated README/INSTALL to reflect move to sources.redhat.com.
|
||||||
|
Updated autoconf files to 2003-06-17.
|
||||||
|
|
||||||
1082
autoconf/config.guess
vendored
1082
autoconf/config.guess
vendored
File diff suppressed because it is too large
Load Diff
560
autoconf/config.sub
vendored
560
autoconf/config.sub
vendored
@@ -1,6 +1,10 @@
|
|||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
# Configuration validation subroutine script, version 1.1.
|
# Configuration validation subroutine script.
|
||||||
# Copyright (C) 1991, 92-97, 1998, 1999 Free Software Foundation, Inc.
|
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
||||||
|
# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
timestamp='2003-06-17'
|
||||||
|
|
||||||
# This file is (in principle) common to ALL GNU software.
|
# This file is (in principle) common to ALL GNU software.
|
||||||
# The presence of a machine in this file suggests that SOME GNU software
|
# The presence of a machine in this file suggests that SOME GNU software
|
||||||
# can handle that machine. It does not imply ALL GNU software can.
|
# can handle that machine. It does not imply ALL GNU software can.
|
||||||
@@ -25,6 +29,9 @@
|
|||||||
# configuration script generated by Autoconf, you may include it under
|
# configuration script generated by Autoconf, you may include it under
|
||||||
# the same distribution terms that you use for the rest of that program.
|
# the same distribution terms that you use for the rest of that program.
|
||||||
|
|
||||||
|
# Please send patches to <config-patches@gnu.org>. Submit a context
|
||||||
|
# diff and a properly formatted ChangeLog entry.
|
||||||
|
#
|
||||||
# Configuration subroutine to validate and canonicalize a configuration type.
|
# Configuration subroutine to validate and canonicalize a configuration type.
|
||||||
# Supply the specified configuration type as an argument.
|
# Supply the specified configuration type as an argument.
|
||||||
# If it is invalid, we print an error message on stderr and exit with code 1.
|
# If it is invalid, we print an error message on stderr and exit with code 1.
|
||||||
@@ -45,30 +52,73 @@
|
|||||||
# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
|
# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
|
||||||
# It is wrong to echo any other type of specification.
|
# It is wrong to echo any other type of specification.
|
||||||
|
|
||||||
if [ x$1 = x ]
|
me=`echo "$0" | sed -e 's,.*/,,'`
|
||||||
then
|
|
||||||
echo Configuration name missing. 1>&2
|
|
||||||
echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
|
|
||||||
echo "or $0 ALIAS" 1>&2
|
|
||||||
echo where ALIAS is a recognized configuration type. 1>&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# First pass through any local machine types.
|
usage="\
|
||||||
case $1 in
|
Usage: $0 [OPTION] CPU-MFR-OPSYS
|
||||||
*local*)
|
$0 [OPTION] ALIAS
|
||||||
echo $1
|
|
||||||
exit 0
|
Canonicalize a configuration name.
|
||||||
;;
|
|
||||||
*)
|
Operation modes:
|
||||||
;;
|
-h, --help print this help, then exit
|
||||||
|
-t, --time-stamp print date of last modification, then exit
|
||||||
|
-v, --version print version number, then exit
|
||||||
|
|
||||||
|
Report bugs and patches to <config-patches@gnu.org>."
|
||||||
|
|
||||||
|
version="\
|
||||||
|
GNU config.sub ($timestamp)
|
||||||
|
|
||||||
|
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
|
||||||
|
Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This is free software; see the source for copying conditions. There is NO
|
||||||
|
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||||
|
|
||||||
|
help="
|
||||||
|
Try \`$me --help' for more information."
|
||||||
|
|
||||||
|
# Parse command line
|
||||||
|
while test $# -gt 0 ; do
|
||||||
|
case $1 in
|
||||||
|
--time-stamp | --time* | -t )
|
||||||
|
echo "$timestamp" ; exit 0 ;;
|
||||||
|
--version | -v )
|
||||||
|
echo "$version" ; exit 0 ;;
|
||||||
|
--help | --h* | -h )
|
||||||
|
echo "$usage"; exit 0 ;;
|
||||||
|
-- ) # Stop option processing
|
||||||
|
shift; break ;;
|
||||||
|
- ) # Use stdin as input.
|
||||||
|
break ;;
|
||||||
|
-* )
|
||||||
|
echo "$me: invalid option $1$help"
|
||||||
|
exit 1 ;;
|
||||||
|
|
||||||
|
*local*)
|
||||||
|
# First pass through any local machine types.
|
||||||
|
echo $1
|
||||||
|
exit 0;;
|
||||||
|
|
||||||
|
* )
|
||||||
|
break ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
case $# in
|
||||||
|
0) echo "$me: missing argument$help" >&2
|
||||||
|
exit 1;;
|
||||||
|
1) ;;
|
||||||
|
*) echo "$me: too many arguments$help" >&2
|
||||||
|
exit 1;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
|
# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
|
||||||
# Here we must recognize all the valid KERNEL-OS combinations.
|
# Here we must recognize all the valid KERNEL-OS combinations.
|
||||||
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
|
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
|
||||||
case $maybe_os in
|
case $maybe_os in
|
||||||
linux-gnu*)
|
nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
|
||||||
os=-$maybe_os
|
os=-$maybe_os
|
||||||
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
|
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
|
||||||
;;
|
;;
|
||||||
@@ -94,7 +144,7 @@ case $os in
|
|||||||
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
|
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
|
||||||
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
|
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
|
||||||
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
|
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
|
||||||
-apple)
|
-apple | -axis)
|
||||||
os=
|
os=
|
||||||
basic_machine=$1
|
basic_machine=$1
|
||||||
;;
|
;;
|
||||||
@@ -105,9 +155,17 @@ case $os in
|
|||||||
-scout)
|
-scout)
|
||||||
;;
|
;;
|
||||||
-wrs)
|
-wrs)
|
||||||
os=vxworks
|
os=-vxworks
|
||||||
basic_machine=$1
|
basic_machine=$1
|
||||||
;;
|
;;
|
||||||
|
-chorusos*)
|
||||||
|
os=-chorusos
|
||||||
|
basic_machine=$1
|
||||||
|
;;
|
||||||
|
-chorusrdb)
|
||||||
|
os=-chorusrdb
|
||||||
|
basic_machine=$1
|
||||||
|
;;
|
||||||
-hiux*)
|
-hiux*)
|
||||||
os=-hiuxwe2
|
os=-hiuxwe2
|
||||||
;;
|
;;
|
||||||
@@ -156,33 +214,72 @@ case $os in
|
|||||||
-psos*)
|
-psos*)
|
||||||
os=-psos
|
os=-psos
|
||||||
;;
|
;;
|
||||||
|
-mint | -mint[0-9]*)
|
||||||
|
basic_machine=m68k-atari
|
||||||
|
os=-mint
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Decode aliases for certain CPU-COMPANY combinations.
|
# Decode aliases for certain CPU-COMPANY combinations.
|
||||||
case $basic_machine in
|
case $basic_machine in
|
||||||
# Recognize the basic CPU types without company name.
|
# Recognize the basic CPU types without company name.
|
||||||
# Some are omitted here because they have special meanings below.
|
# Some are omitted here because they have special meanings below.
|
||||||
tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
|
1750a | 580 \
|
||||||
| arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \
|
| a29k \
|
||||||
| 580 | i960 | h8300 \
|
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
|
||||||
| hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
|
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
|
||||||
| alpha | alphaev[4-7] | alphaev56 | alphapca5[67] \
|
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
|
||||||
| we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \
|
| c4x | clipper \
|
||||||
| 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \
|
| d10v | d30v | dlx | dsp16xx \
|
||||||
| mips64orion | mips64orionel | mipstx39 | mipstx39el \
|
| fr30 | frv \
|
||||||
| mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
|
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
|
||||||
| mips64vr5000 | miprs64vr5000el | mcore \
|
| i370 | i860 | i960 | ia64 \
|
||||||
| sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \
|
| ip2k \
|
||||||
| thumb | d10v)
|
| m32r | m68000 | m68k | m88k | mcore \
|
||||||
|
| mips | mipsbe | mipseb | mipsel | mipsle \
|
||||||
|
| mips16 \
|
||||||
|
| mips64 | mips64el \
|
||||||
|
| mips64vr | mips64vrel \
|
||||||
|
| mips64orion | mips64orionel \
|
||||||
|
| mips64vr4100 | mips64vr4100el \
|
||||||
|
| mips64vr4300 | mips64vr4300el \
|
||||||
|
| mips64vr5000 | mips64vr5000el \
|
||||||
|
| mipsisa32 | mipsisa32el \
|
||||||
|
| mipsisa32r2 | mipsisa32r2el \
|
||||||
|
| mipsisa64 | mipsisa64el \
|
||||||
|
| mipsisa64sb1 | mipsisa64sb1el \
|
||||||
|
| mipsisa64sr71k | mipsisa64sr71kel \
|
||||||
|
| mipstx39 | mipstx39el \
|
||||||
|
| mn10200 | mn10300 \
|
||||||
|
| msp430 \
|
||||||
|
| ns16k | ns32k \
|
||||||
|
| openrisc | or32 \
|
||||||
|
| pdp10 | pdp11 | pj | pjl \
|
||||||
|
| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
|
||||||
|
| pyramid \
|
||||||
|
| sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
|
||||||
|
| sh64 | sh64le \
|
||||||
|
| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
|
||||||
|
| strongarm \
|
||||||
|
| tahoe | thumb | tic4x | tic80 | tron \
|
||||||
|
| v850 | v850e \
|
||||||
|
| we32k \
|
||||||
|
| x86 | xscale | xstormy16 | xtensa \
|
||||||
|
| z8k)
|
||||||
basic_machine=$basic_machine-unknown
|
basic_machine=$basic_machine-unknown
|
||||||
;;
|
;;
|
||||||
m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65)
|
m6811 | m68hc11 | m6812 | m68hc12)
|
||||||
|
# Motorola 68HC11/12.
|
||||||
|
basic_machine=$basic_machine-unknown
|
||||||
|
os=-none
|
||||||
|
;;
|
||||||
|
m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
|
||||||
;;
|
;;
|
||||||
|
|
||||||
# We use `pc' rather than `unknown'
|
# We use `pc' rather than `unknown'
|
||||||
# because (1) that's what they normally are, and
|
# because (1) that's what they normally are, and
|
||||||
# (2) the word "unknown" tends to confuse beginning users.
|
# (2) the word "unknown" tends to confuse beginning users.
|
||||||
i[34567]86)
|
i*86 | x86_64)
|
||||||
basic_machine=$basic_machine-pc
|
basic_machine=$basic_machine-pc
|
||||||
;;
|
;;
|
||||||
# Object if more than one company name word.
|
# Object if more than one company name word.
|
||||||
@@ -191,24 +288,60 @@ case $basic_machine in
|
|||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
# Recognize the basic CPU types with company name.
|
# Recognize the basic CPU types with company name.
|
||||||
# FIXME: clean up the formatting here.
|
580-* \
|
||||||
vax-* | tahoe-* | i[34567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \
|
| a29k-* \
|
||||||
| m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
|
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
|
||||||
| mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
|
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
|
||||||
| power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
|
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
|
||||||
| xmp-* | ymp-* \
|
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
|
||||||
| hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* | hppa2.0n-* \
|
| avr-* \
|
||||||
| alpha-* | alphaev[4-7]-* | alphaev56-* | alphapca5[67]-* \
|
| bs2000-* \
|
||||||
| we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
|
| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
|
||||||
| clipper-* | orion-* \
|
| clipper-* | cydra-* \
|
||||||
| sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
|
| d10v-* | d30v-* | dlx-* \
|
||||||
| sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \
|
| elxsi-* \
|
||||||
| mips64el-* | mips64orion-* | mips64orionel-* \
|
| f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
|
||||||
| mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
|
| h8300-* | h8500-* \
|
||||||
| mipstx39-* | mipstx39el-* | mcore-* \
|
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
|
||||||
| f301-* | armv*-* | t3e-* \
|
| i*86-* | i860-* | i960-* | ia64-* \
|
||||||
| m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
|
| ip2k-* \
|
||||||
| thumb-* | v850-* | d30v-* | tic30-* | c30-* )
|
| m32r-* \
|
||||||
|
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
|
||||||
|
| m88110-* | m88k-* | mcore-* \
|
||||||
|
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
|
||||||
|
| mips16-* \
|
||||||
|
| mips64-* | mips64el-* \
|
||||||
|
| mips64vr-* | mips64vrel-* \
|
||||||
|
| mips64orion-* | mips64orionel-* \
|
||||||
|
| mips64vr4100-* | mips64vr4100el-* \
|
||||||
|
| mips64vr4300-* | mips64vr4300el-* \
|
||||||
|
| mips64vr5000-* | mips64vr5000el-* \
|
||||||
|
| mipsisa32-* | mipsisa32el-* \
|
||||||
|
| mipsisa32r2-* | mipsisa32r2el-* \
|
||||||
|
| mipsisa64-* | mipsisa64el-* \
|
||||||
|
| mipsisa64sb1-* | mipsisa64sb1el-* \
|
||||||
|
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
|
||||||
|
| mipstx39-* | mipstx39el-* \
|
||||||
|
| msp430-* \
|
||||||
|
| none-* | np1-* | nv1-* | ns16k-* | ns32k-* \
|
||||||
|
| orion-* \
|
||||||
|
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
|
||||||
|
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
|
||||||
|
| pyramid-* \
|
||||||
|
| romp-* | rs6000-* \
|
||||||
|
| sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
|
||||||
|
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
|
||||||
|
| sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
|
||||||
|
| sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
|
||||||
|
| tahoe-* | thumb-* \
|
||||||
|
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
|
||||||
|
| tron-* \
|
||||||
|
| v850-* | v850e-* | vax-* \
|
||||||
|
| we32k-* \
|
||||||
|
| x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
|
||||||
|
| xtensa-* \
|
||||||
|
| ymp-* \
|
||||||
|
| z8k-*)
|
||||||
;;
|
;;
|
||||||
# Recognize the various machine names and aliases which stand
|
# Recognize the various machine names and aliases which stand
|
||||||
# for a CPU type and a company and sometimes even an OS.
|
# for a CPU type and a company and sometimes even an OS.
|
||||||
@@ -240,19 +373,22 @@ case $basic_machine in
|
|||||||
basic_machine=a29k-none
|
basic_machine=a29k-none
|
||||||
os=-bsd
|
os=-bsd
|
||||||
;;
|
;;
|
||||||
|
amd64)
|
||||||
|
basic_machine=x86_64-pc
|
||||||
|
;;
|
||||||
amdahl)
|
amdahl)
|
||||||
basic_machine=580-amdahl
|
basic_machine=580-amdahl
|
||||||
os=-sysv
|
os=-sysv
|
||||||
;;
|
;;
|
||||||
amiga | amiga-*)
|
amiga | amiga-*)
|
||||||
basic_machine=m68k-cbm
|
basic_machine=m68k-unknown
|
||||||
;;
|
;;
|
||||||
amigaos | amigados)
|
amigaos | amigados)
|
||||||
basic_machine=m68k-cbm
|
basic_machine=m68k-unknown
|
||||||
os=-amigaos
|
os=-amigaos
|
||||||
;;
|
;;
|
||||||
amigaunix | amix)
|
amigaunix | amix)
|
||||||
basic_machine=m68k-cbm
|
basic_machine=m68k-unknown
|
||||||
os=-sysv4
|
os=-sysv4
|
||||||
;;
|
;;
|
||||||
apollo68)
|
apollo68)
|
||||||
@@ -271,6 +407,10 @@ case $basic_machine in
|
|||||||
basic_machine=ns32k-sequent
|
basic_machine=ns32k-sequent
|
||||||
os=-dynix
|
os=-dynix
|
||||||
;;
|
;;
|
||||||
|
c90)
|
||||||
|
basic_machine=c90-cray
|
||||||
|
os=-unicos
|
||||||
|
;;
|
||||||
convex-c1)
|
convex-c1)
|
||||||
basic_machine=c1-convex
|
basic_machine=c1-convex
|
||||||
os=-bsd
|
os=-bsd
|
||||||
@@ -291,27 +431,30 @@ case $basic_machine in
|
|||||||
basic_machine=c38-convex
|
basic_machine=c38-convex
|
||||||
os=-bsd
|
os=-bsd
|
||||||
;;
|
;;
|
||||||
cray | ymp)
|
cray | j90)
|
||||||
basic_machine=ymp-cray
|
basic_machine=j90-cray
|
||||||
os=-unicos
|
|
||||||
;;
|
|
||||||
cray2)
|
|
||||||
basic_machine=cray2-cray
|
|
||||||
os=-unicos
|
|
||||||
;;
|
|
||||||
[ctj]90-cray)
|
|
||||||
basic_machine=c90-cray
|
|
||||||
os=-unicos
|
os=-unicos
|
||||||
;;
|
;;
|
||||||
crds | unos)
|
crds | unos)
|
||||||
basic_machine=m68k-crds
|
basic_machine=m68k-crds
|
||||||
;;
|
;;
|
||||||
|
cris | cris-* | etrax*)
|
||||||
|
basic_machine=cris-axis
|
||||||
|
;;
|
||||||
da30 | da30-*)
|
da30 | da30-*)
|
||||||
basic_machine=m68k-da30
|
basic_machine=m68k-da30
|
||||||
;;
|
;;
|
||||||
decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
|
decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
|
||||||
basic_machine=mips-dec
|
basic_machine=mips-dec
|
||||||
;;
|
;;
|
||||||
|
decsystem10* | dec10*)
|
||||||
|
basic_machine=pdp10-dec
|
||||||
|
os=-tops10
|
||||||
|
;;
|
||||||
|
decsystem20* | dec20*)
|
||||||
|
basic_machine=pdp10-dec
|
||||||
|
os=-tops20
|
||||||
|
;;
|
||||||
delta | 3300 | motorola-3300 | motorola-delta \
|
delta | 3300 | motorola-3300 | motorola-delta \
|
||||||
| 3300-motorola | delta-motorola)
|
| 3300-motorola | delta-motorola)
|
||||||
basic_machine=m68k-motorola
|
basic_machine=m68k-motorola
|
||||||
@@ -353,6 +496,10 @@ case $basic_machine in
|
|||||||
basic_machine=tron-gmicro
|
basic_machine=tron-gmicro
|
||||||
os=-sysv
|
os=-sysv
|
||||||
;;
|
;;
|
||||||
|
go32)
|
||||||
|
basic_machine=i386-pc
|
||||||
|
os=-go32
|
||||||
|
;;
|
||||||
h3050r* | hiux*)
|
h3050r* | hiux*)
|
||||||
basic_machine=hppa1.1-hitachi
|
basic_machine=hppa1.1-hitachi
|
||||||
os=-hiuxwe2
|
os=-hiuxwe2
|
||||||
@@ -426,22 +573,21 @@ case $basic_machine in
|
|||||||
;;
|
;;
|
||||||
i370-ibm* | ibm*)
|
i370-ibm* | ibm*)
|
||||||
basic_machine=i370-ibm
|
basic_machine=i370-ibm
|
||||||
os=-mvs
|
|
||||||
;;
|
;;
|
||||||
# I'm not sure what "Sysv32" means. Should this be sysv3.2?
|
# I'm not sure what "Sysv32" means. Should this be sysv3.2?
|
||||||
i[34567]86v32)
|
i*86v32)
|
||||||
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
|
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
|
||||||
os=-sysv32
|
os=-sysv32
|
||||||
;;
|
;;
|
||||||
i[34567]86v4*)
|
i*86v4*)
|
||||||
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
|
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
|
||||||
os=-sysv4
|
os=-sysv4
|
||||||
;;
|
;;
|
||||||
i[34567]86v)
|
i*86v)
|
||||||
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
|
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
|
||||||
os=-sysv
|
os=-sysv
|
||||||
;;
|
;;
|
||||||
i[34567]86sol2)
|
i*86sol2)
|
||||||
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
|
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
|
||||||
os=-solaris2
|
os=-solaris2
|
||||||
;;
|
;;
|
||||||
@@ -453,14 +599,6 @@ case $basic_machine in
|
|||||||
basic_machine=i386-unknown
|
basic_machine=i386-unknown
|
||||||
os=-vsta
|
os=-vsta
|
||||||
;;
|
;;
|
||||||
i386-go32 | go32)
|
|
||||||
basic_machine=i386-unknown
|
|
||||||
os=-go32
|
|
||||||
;;
|
|
||||||
i386-mingw32 | mingw32)
|
|
||||||
basic_machine=i386-unknown
|
|
||||||
os=-mingw32
|
|
||||||
;;
|
|
||||||
iris | iris4d)
|
iris | iris4d)
|
||||||
basic_machine=mips-sgi
|
basic_machine=mips-sgi
|
||||||
case $os in
|
case $os in
|
||||||
@@ -486,35 +624,43 @@ case $basic_machine in
|
|||||||
basic_machine=ns32k-utek
|
basic_machine=ns32k-utek
|
||||||
os=-sysv
|
os=-sysv
|
||||||
;;
|
;;
|
||||||
|
mingw32)
|
||||||
|
basic_machine=i386-pc
|
||||||
|
os=-mingw32
|
||||||
|
;;
|
||||||
miniframe)
|
miniframe)
|
||||||
basic_machine=m68000-convergent
|
basic_machine=m68000-convergent
|
||||||
;;
|
;;
|
||||||
*mint | *MiNT)
|
*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
|
||||||
basic_machine=m68k-atari
|
basic_machine=m68k-atari
|
||||||
os=-mint
|
os=-mint
|
||||||
;;
|
;;
|
||||||
mipsel*-linux*)
|
|
||||||
basic_machine=mipsel-unknown
|
|
||||||
os=-linux-gnu
|
|
||||||
;;
|
|
||||||
mips*-linux*)
|
|
||||||
basic_machine=mips-unknown
|
|
||||||
os=-linux-gnu
|
|
||||||
;;
|
|
||||||
mips3*-*)
|
mips3*-*)
|
||||||
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
|
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
|
||||||
;;
|
;;
|
||||||
mips3*)
|
mips3*)
|
||||||
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
|
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
|
||||||
;;
|
;;
|
||||||
|
mmix*)
|
||||||
|
basic_machine=mmix-knuth
|
||||||
|
os=-mmixware
|
||||||
|
;;
|
||||||
monitor)
|
monitor)
|
||||||
basic_machine=m68k-rom68k
|
basic_machine=m68k-rom68k
|
||||||
os=-coff
|
os=-coff
|
||||||
;;
|
;;
|
||||||
|
morphos)
|
||||||
|
basic_machine=powerpc-unknown
|
||||||
|
os=-morphos
|
||||||
|
;;
|
||||||
msdos)
|
msdos)
|
||||||
basic_machine=i386-unknown
|
basic_machine=i386-pc
|
||||||
os=-msdos
|
os=-msdos
|
||||||
;;
|
;;
|
||||||
|
mvs)
|
||||||
|
basic_machine=i370-ibm
|
||||||
|
os=-mvs
|
||||||
|
;;
|
||||||
ncr3000)
|
ncr3000)
|
||||||
basic_machine=i486-ncr
|
basic_machine=i486-ncr
|
||||||
os=-sysv4
|
os=-sysv4
|
||||||
@@ -524,7 +670,7 @@ case $basic_machine in
|
|||||||
os=-netbsd
|
os=-netbsd
|
||||||
;;
|
;;
|
||||||
netwinder)
|
netwinder)
|
||||||
basic_machine=armv4l-corel
|
basic_machine=armv4l-rebel
|
||||||
os=-linux
|
os=-linux
|
||||||
;;
|
;;
|
||||||
news | news700 | news800 | news900)
|
news | news700 | news800 | news900)
|
||||||
@@ -572,13 +718,28 @@ case $basic_machine in
|
|||||||
basic_machine=i960-intel
|
basic_machine=i960-intel
|
||||||
os=-mon960
|
os=-mon960
|
||||||
;;
|
;;
|
||||||
|
nonstopux)
|
||||||
|
basic_machine=mips-compaq
|
||||||
|
os=-nonstopux
|
||||||
|
;;
|
||||||
np1)
|
np1)
|
||||||
basic_machine=np1-gould
|
basic_machine=np1-gould
|
||||||
;;
|
;;
|
||||||
|
nv1)
|
||||||
|
basic_machine=nv1-cray
|
||||||
|
os=-unicosmp
|
||||||
|
;;
|
||||||
|
nsr-tandem)
|
||||||
|
basic_machine=nsr-tandem
|
||||||
|
;;
|
||||||
op50n-* | op60c-*)
|
op50n-* | op60c-*)
|
||||||
basic_machine=hppa1.1-oki
|
basic_machine=hppa1.1-oki
|
||||||
os=-proelf
|
os=-proelf
|
||||||
;;
|
;;
|
||||||
|
or32 | or32-*)
|
||||||
|
basic_machine=or32-unknown
|
||||||
|
os=-coff
|
||||||
|
;;
|
||||||
OSE68000 | ose68000)
|
OSE68000 | ose68000)
|
||||||
basic_machine=m68000-ericsson
|
basic_machine=m68000-ericsson
|
||||||
os=-ose
|
os=-ose
|
||||||
@@ -601,45 +762,65 @@ case $basic_machine in
|
|||||||
pbb)
|
pbb)
|
||||||
basic_machine=m68k-tti
|
basic_machine=m68k-tti
|
||||||
;;
|
;;
|
||||||
pc532 | pc532-*)
|
pc532 | pc532-*)
|
||||||
basic_machine=ns32k-pc532
|
basic_machine=ns32k-pc532
|
||||||
;;
|
;;
|
||||||
pentium | p5 | k5 | k6 | nexen)
|
pentium | p5 | k5 | k6 | nexgen | viac3)
|
||||||
basic_machine=i586-pc
|
basic_machine=i586-pc
|
||||||
;;
|
;;
|
||||||
pentiumpro | p6 | 6x86)
|
pentiumpro | p6 | 6x86 | athlon | athlon_*)
|
||||||
basic_machine=i686-pc
|
basic_machine=i686-pc
|
||||||
;;
|
;;
|
||||||
pentiumii | pentium2)
|
pentiumii | pentium2 | pentiumiii | pentium3)
|
||||||
|
basic_machine=i686-pc
|
||||||
|
;;
|
||||||
|
pentium4)
|
||||||
basic_machine=i786-pc
|
basic_machine=i786-pc
|
||||||
;;
|
;;
|
||||||
pentium-* | p5-* | k5-* | k6-* | nexen-*)
|
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
|
||||||
basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
|
basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||||
;;
|
;;
|
||||||
pentiumpro-* | p6-* | 6x86-*)
|
pentiumpro-* | p6-* | 6x86-* | athlon-*)
|
||||||
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
|
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||||
;;
|
;;
|
||||||
pentiumii-* | pentium2-*)
|
pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
|
||||||
|
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||||
|
;;
|
||||||
|
pentium4-*)
|
||||||
basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
|
basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||||
;;
|
;;
|
||||||
pn)
|
pn)
|
||||||
basic_machine=pn-gould
|
basic_machine=pn-gould
|
||||||
;;
|
;;
|
||||||
power) basic_machine=rs6000-ibm
|
power) basic_machine=power-ibm
|
||||||
;;
|
;;
|
||||||
ppc) basic_machine=powerpc-unknown
|
ppc) basic_machine=powerpc-unknown
|
||||||
;;
|
;;
|
||||||
ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
|
ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||||
;;
|
;;
|
||||||
ppcle | powerpclittle | ppc-le | powerpc-little)
|
ppcle | powerpclittle | ppc-le | powerpc-little)
|
||||||
basic_machine=powerpcle-unknown
|
basic_machine=powerpcle-unknown
|
||||||
;;
|
;;
|
||||||
ppcle-* | powerpclittle-*)
|
ppcle-* | powerpclittle-*)
|
||||||
basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
|
basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||||
;;
|
;;
|
||||||
|
ppc64) basic_machine=powerpc64-unknown
|
||||||
|
;;
|
||||||
|
ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||||
|
;;
|
||||||
|
ppc64le | powerpc64little | ppc64-le | powerpc64-little)
|
||||||
|
basic_machine=powerpc64le-unknown
|
||||||
|
;;
|
||||||
|
ppc64le-* | powerpc64little-*)
|
||||||
|
basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||||
|
;;
|
||||||
ps2)
|
ps2)
|
||||||
basic_machine=i386-ibm
|
basic_machine=i386-ibm
|
||||||
;;
|
;;
|
||||||
|
pw32)
|
||||||
|
basic_machine=i586-unknown
|
||||||
|
os=-pw32
|
||||||
|
;;
|
||||||
rom68k)
|
rom68k)
|
||||||
basic_machine=m68k-rom68k
|
basic_machine=m68k-rom68k
|
||||||
os=-coff
|
os=-coff
|
||||||
@@ -650,10 +831,26 @@ case $basic_machine in
|
|||||||
rtpc | rtpc-*)
|
rtpc | rtpc-*)
|
||||||
basic_machine=romp-ibm
|
basic_machine=romp-ibm
|
||||||
;;
|
;;
|
||||||
|
s390 | s390-*)
|
||||||
|
basic_machine=s390-ibm
|
||||||
|
;;
|
||||||
|
s390x | s390x-*)
|
||||||
|
basic_machine=s390x-ibm
|
||||||
|
;;
|
||||||
sa29200)
|
sa29200)
|
||||||
basic_machine=a29k-amd
|
basic_machine=a29k-amd
|
||||||
os=-udi
|
os=-udi
|
||||||
;;
|
;;
|
||||||
|
sb1)
|
||||||
|
basic_machine=mipsisa64sb1-unknown
|
||||||
|
;;
|
||||||
|
sb1el)
|
||||||
|
basic_machine=mipsisa64sb1el-unknown
|
||||||
|
;;
|
||||||
|
sei)
|
||||||
|
basic_machine=mips-sei
|
||||||
|
os=-seiux
|
||||||
|
;;
|
||||||
sequent)
|
sequent)
|
||||||
basic_machine=i386-sequent
|
basic_machine=i386-sequent
|
||||||
;;
|
;;
|
||||||
@@ -661,7 +858,10 @@ case $basic_machine in
|
|||||||
basic_machine=sh-hitachi
|
basic_machine=sh-hitachi
|
||||||
os=-hms
|
os=-hms
|
||||||
;;
|
;;
|
||||||
sparclite-wrs)
|
sh64)
|
||||||
|
basic_machine=sh64-unknown
|
||||||
|
;;
|
||||||
|
sparclite-wrs | simso-wrs)
|
||||||
basic_machine=sparclite-wrs
|
basic_machine=sparclite-wrs
|
||||||
os=-vxworks
|
os=-vxworks
|
||||||
;;
|
;;
|
||||||
@@ -719,20 +919,44 @@ case $basic_machine in
|
|||||||
sun386 | sun386i | roadrunner)
|
sun386 | sun386i | roadrunner)
|
||||||
basic_machine=i386-sun
|
basic_machine=i386-sun
|
||||||
;;
|
;;
|
||||||
|
sv1)
|
||||||
|
basic_machine=sv1-cray
|
||||||
|
os=-unicos
|
||||||
|
;;
|
||||||
symmetry)
|
symmetry)
|
||||||
basic_machine=i386-sequent
|
basic_machine=i386-sequent
|
||||||
os=-dynix
|
os=-dynix
|
||||||
;;
|
;;
|
||||||
t3e)
|
t3e)
|
||||||
basic_machine=t3e-cray
|
basic_machine=alphaev5-cray
|
||||||
os=-unicos
|
os=-unicos
|
||||||
;;
|
;;
|
||||||
|
t90)
|
||||||
|
basic_machine=t90-cray
|
||||||
|
os=-unicos
|
||||||
|
;;
|
||||||
|
tic54x | c54x*)
|
||||||
|
basic_machine=tic54x-unknown
|
||||||
|
os=-coff
|
||||||
|
;;
|
||||||
|
tic55x | c55x*)
|
||||||
|
basic_machine=tic55x-unknown
|
||||||
|
os=-coff
|
||||||
|
;;
|
||||||
|
tic6x | c6x*)
|
||||||
|
basic_machine=tic6x-unknown
|
||||||
|
os=-coff
|
||||||
|
;;
|
||||||
tx39)
|
tx39)
|
||||||
basic_machine=mipstx39-unknown
|
basic_machine=mipstx39-unknown
|
||||||
;;
|
;;
|
||||||
tx39el)
|
tx39el)
|
||||||
basic_machine=mipstx39el-unknown
|
basic_machine=mipstx39el-unknown
|
||||||
;;
|
;;
|
||||||
|
toad1)
|
||||||
|
basic_machine=pdp10-xkl
|
||||||
|
os=-tops20
|
||||||
|
;;
|
||||||
tower | tower-32)
|
tower | tower-32)
|
||||||
basic_machine=m68k-ncr
|
basic_machine=m68k-ncr
|
||||||
;;
|
;;
|
||||||
@@ -757,8 +981,8 @@ case $basic_machine in
|
|||||||
os=-vms
|
os=-vms
|
||||||
;;
|
;;
|
||||||
vpp*|vx|vx-*)
|
vpp*|vx|vx-*)
|
||||||
basic_machine=f301-fujitsu
|
basic_machine=f301-fujitsu
|
||||||
;;
|
;;
|
||||||
vxworks960)
|
vxworks960)
|
||||||
basic_machine=i960-wrs
|
basic_machine=i960-wrs
|
||||||
os=-vxworks
|
os=-vxworks
|
||||||
@@ -779,13 +1003,13 @@ case $basic_machine in
|
|||||||
basic_machine=hppa1.1-winbond
|
basic_machine=hppa1.1-winbond
|
||||||
os=-proelf
|
os=-proelf
|
||||||
;;
|
;;
|
||||||
xmp)
|
xps | xps100)
|
||||||
basic_machine=xmp-cray
|
|
||||||
os=-unicos
|
|
||||||
;;
|
|
||||||
xps | xps100)
|
|
||||||
basic_machine=xps100-honeywell
|
basic_machine=xps100-honeywell
|
||||||
;;
|
;;
|
||||||
|
ymp)
|
||||||
|
basic_machine=ymp-cray
|
||||||
|
os=-unicos
|
||||||
|
;;
|
||||||
z8k-*-coff)
|
z8k-*-coff)
|
||||||
basic_machine=z8k-unknown
|
basic_machine=z8k-unknown
|
||||||
os=-sim
|
os=-sim
|
||||||
@@ -806,13 +1030,6 @@ case $basic_machine in
|
|||||||
op60c)
|
op60c)
|
||||||
basic_machine=hppa1.1-oki
|
basic_machine=hppa1.1-oki
|
||||||
;;
|
;;
|
||||||
mips)
|
|
||||||
if [ x$os = x-linux-gnu ]; then
|
|
||||||
basic_machine=mips-unknown
|
|
||||||
else
|
|
||||||
basic_machine=mips-mips
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
romp)
|
romp)
|
||||||
basic_machine=romp-ibm
|
basic_machine=romp-ibm
|
||||||
;;
|
;;
|
||||||
@@ -822,16 +1039,26 @@ case $basic_machine in
|
|||||||
vax)
|
vax)
|
||||||
basic_machine=vax-dec
|
basic_machine=vax-dec
|
||||||
;;
|
;;
|
||||||
|
pdp10)
|
||||||
|
# there are many clones, so DEC is not a safe bet
|
||||||
|
basic_machine=pdp10-unknown
|
||||||
|
;;
|
||||||
pdp11)
|
pdp11)
|
||||||
basic_machine=pdp11-dec
|
basic_machine=pdp11-dec
|
||||||
;;
|
;;
|
||||||
we32k)
|
we32k)
|
||||||
basic_machine=we32k-att
|
basic_machine=we32k-att
|
||||||
;;
|
;;
|
||||||
sparc | sparcv9)
|
sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele)
|
||||||
|
basic_machine=sh-unknown
|
||||||
|
;;
|
||||||
|
sh64)
|
||||||
|
basic_machine=sh64-unknown
|
||||||
|
;;
|
||||||
|
sparc | sparcv9 | sparcv9b)
|
||||||
basic_machine=sparc-sun
|
basic_machine=sparc-sun
|
||||||
;;
|
;;
|
||||||
cydra)
|
cydra)
|
||||||
basic_machine=cydra-cydrome
|
basic_machine=cydra-cydrome
|
||||||
;;
|
;;
|
||||||
orion)
|
orion)
|
||||||
@@ -846,9 +1073,8 @@ case $basic_machine in
|
|||||||
pmac | pmac-mpw)
|
pmac | pmac-mpw)
|
||||||
basic_machine=powerpc-apple
|
basic_machine=powerpc-apple
|
||||||
;;
|
;;
|
||||||
c4x*)
|
*-unknown)
|
||||||
basic_machine=c4x-none
|
# Make sure to match an already-canonicalized machine name.
|
||||||
os=-coff
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
|
echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
|
||||||
@@ -906,14 +1132,34 @@ case $os in
|
|||||||
| -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
|
| -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
|
||||||
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
|
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
|
||||||
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
|
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
|
||||||
|
| -chorusos* | -chorusrdb* \
|
||||||
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
|
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
|
||||||
| -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
|
| -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
|
||||||
| -interix* | -uwin* | -rhapsody* | -openstep* | -oskit*)
|
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
|
||||||
|
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
|
||||||
|
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
|
||||||
|
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
|
||||||
|
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
|
||||||
|
| -powermax* | -dnix* | -nx6 | -nx7 | -sei*)
|
||||||
# Remember, each alternative MUST END IN *, to match a version number.
|
# Remember, each alternative MUST END IN *, to match a version number.
|
||||||
;;
|
;;
|
||||||
|
-qnx*)
|
||||||
|
case $basic_machine in
|
||||||
|
x86-* | i*86-*)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
os=-nto$os
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
-nto-qnx*)
|
||||||
|
;;
|
||||||
|
-nto*)
|
||||||
|
os=`echo $os | sed -e 's|nto|nto-qnx|'`
|
||||||
|
;;
|
||||||
-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
|
-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
|
||||||
| -windows* | -osx | -abug | -netware* | -os9* | -beos* \
|
| -windows* | -osx | -abug | -netware* | -os9* | -beos* \
|
||||||
| -macos* | -mpw* | -magic* | -mon960* | -lnews*)
|
| -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
|
||||||
;;
|
;;
|
||||||
-mac*)
|
-mac*)
|
||||||
os=`echo $os | sed -e 's|mac|macos|'`
|
os=`echo $os | sed -e 's|mac|macos|'`
|
||||||
@@ -927,6 +1173,12 @@ case $os in
|
|||||||
-sunos6*)
|
-sunos6*)
|
||||||
os=`echo $os | sed -e 's|sunos6|solaris3|'`
|
os=`echo $os | sed -e 's|sunos6|solaris3|'`
|
||||||
;;
|
;;
|
||||||
|
-opened*)
|
||||||
|
os=-openedition
|
||||||
|
;;
|
||||||
|
-wince*)
|
||||||
|
os=-wince
|
||||||
|
;;
|
||||||
-osfrose*)
|
-osfrose*)
|
||||||
os=-osfrose
|
os=-osfrose
|
||||||
;;
|
;;
|
||||||
@@ -942,14 +1194,23 @@ case $os in
|
|||||||
-acis*)
|
-acis*)
|
||||||
os=-aos
|
os=-aos
|
||||||
;;
|
;;
|
||||||
|
-atheos*)
|
||||||
|
os=-atheos
|
||||||
|
;;
|
||||||
-386bsd)
|
-386bsd)
|
||||||
os=-bsd
|
os=-bsd
|
||||||
;;
|
;;
|
||||||
-ctix* | -uts*)
|
-ctix* | -uts*)
|
||||||
os=-sysv
|
os=-sysv
|
||||||
;;
|
;;
|
||||||
|
-nova*)
|
||||||
|
os=-rtmk-nova
|
||||||
|
;;
|
||||||
-ns2 )
|
-ns2 )
|
||||||
os=-nextstep2
|
os=-nextstep2
|
||||||
|
;;
|
||||||
|
-nsk*)
|
||||||
|
os=-nsk
|
||||||
;;
|
;;
|
||||||
# Preserve the version number of sinix5.
|
# Preserve the version number of sinix5.
|
||||||
-sinix5.*)
|
-sinix5.*)
|
||||||
@@ -985,8 +1246,14 @@ case $os in
|
|||||||
-xenix)
|
-xenix)
|
||||||
os=-xenix
|
os=-xenix
|
||||||
;;
|
;;
|
||||||
-*mint | -*MiNT)
|
-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
|
||||||
os=-mint
|
os=-mint
|
||||||
|
;;
|
||||||
|
-aros*)
|
||||||
|
os=-aros
|
||||||
|
;;
|
||||||
|
-kaos*)
|
||||||
|
os=-kaos
|
||||||
;;
|
;;
|
||||||
-none)
|
-none)
|
||||||
;;
|
;;
|
||||||
@@ -1013,13 +1280,20 @@ case $basic_machine in
|
|||||||
*-acorn)
|
*-acorn)
|
||||||
os=-riscix1.2
|
os=-riscix1.2
|
||||||
;;
|
;;
|
||||||
arm*-corel)
|
arm*-rebel)
|
||||||
os=-linux
|
os=-linux
|
||||||
;;
|
;;
|
||||||
arm*-semi)
|
arm*-semi)
|
||||||
os=-aout
|
os=-aout
|
||||||
;;
|
;;
|
||||||
pdp11-*)
|
c4x-* | tic4x-*)
|
||||||
|
os=-coff
|
||||||
|
;;
|
||||||
|
# This must come before the *-dec entry.
|
||||||
|
pdp10-*)
|
||||||
|
os=-tops20
|
||||||
|
;;
|
||||||
|
pdp11-*)
|
||||||
os=-none
|
os=-none
|
||||||
;;
|
;;
|
||||||
*-dec | vax-*)
|
*-dec | vax-*)
|
||||||
@@ -1046,6 +1320,9 @@ case $basic_machine in
|
|||||||
mips*-*)
|
mips*-*)
|
||||||
os=-elf
|
os=-elf
|
||||||
;;
|
;;
|
||||||
|
or32-*)
|
||||||
|
os=-coff
|
||||||
|
;;
|
||||||
*-tti) # must be before sparc entry or we get the wrong os.
|
*-tti) # must be before sparc entry or we get the wrong os.
|
||||||
os=-sysv3
|
os=-sysv3
|
||||||
;;
|
;;
|
||||||
@@ -1109,25 +1386,25 @@ case $basic_machine in
|
|||||||
*-next)
|
*-next)
|
||||||
os=-nextstep3
|
os=-nextstep3
|
||||||
;;
|
;;
|
||||||
*-gould)
|
*-gould)
|
||||||
os=-sysv
|
os=-sysv
|
||||||
;;
|
;;
|
||||||
*-highlevel)
|
*-highlevel)
|
||||||
os=-bsd
|
os=-bsd
|
||||||
;;
|
;;
|
||||||
*-encore)
|
*-encore)
|
||||||
os=-bsd
|
os=-bsd
|
||||||
;;
|
;;
|
||||||
*-sgi)
|
*-sgi)
|
||||||
os=-irix
|
os=-irix
|
||||||
;;
|
;;
|
||||||
*-siemens)
|
*-siemens)
|
||||||
os=-sysv4
|
os=-sysv4
|
||||||
;;
|
;;
|
||||||
*-masscomp)
|
*-masscomp)
|
||||||
os=-rtu
|
os=-rtu
|
||||||
;;
|
;;
|
||||||
f301-fujitsu)
|
f30[01]-fujitsu | f700-fujitsu)
|
||||||
os=-uxpv
|
os=-uxpv
|
||||||
;;
|
;;
|
||||||
*-rom68k)
|
*-rom68k)
|
||||||
@@ -1187,13 +1464,13 @@ case $basic_machine in
|
|||||||
-genix*)
|
-genix*)
|
||||||
vendor=ns
|
vendor=ns
|
||||||
;;
|
;;
|
||||||
-mvs*)
|
-mvs* | -opened*)
|
||||||
vendor=ibm
|
vendor=ibm
|
||||||
;;
|
;;
|
||||||
-ptx*)
|
-ptx*)
|
||||||
vendor=sequent
|
vendor=sequent
|
||||||
;;
|
;;
|
||||||
-vxsim* | -vxworks*)
|
-vxsim* | -vxworks* | -windiss*)
|
||||||
vendor=wrs
|
vendor=wrs
|
||||||
;;
|
;;
|
||||||
-aux*)
|
-aux*)
|
||||||
@@ -1205,12 +1482,23 @@ case $basic_machine in
|
|||||||
-mpw* | -macos*)
|
-mpw* | -macos*)
|
||||||
vendor=apple
|
vendor=apple
|
||||||
;;
|
;;
|
||||||
-*mint | -*MiNT)
|
-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
|
||||||
vendor=atari
|
vendor=atari
|
||||||
;;
|
;;
|
||||||
|
-vos*)
|
||||||
|
vendor=stratus
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
|
basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
echo $basic_machine$os
|
echo $basic_machine$os
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
# Local variables:
|
||||||
|
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||||
|
# time-stamp-start: "timestamp='"
|
||||||
|
# time-stamp-format: "%:y-%02m-%02d"
|
||||||
|
# time-stamp-end: "'"
|
||||||
|
# End:
|
||||||
|
|||||||
@@ -1,19 +1,38 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
|
||||||
# install - install a program, script, or datafile
|
# install - install a program, script, or datafile
|
||||||
# This comes from X11R5 (mit/util/scripts/install.sh).
|
|
||||||
|
scriptversion=2003-06-13.21
|
||||||
|
|
||||||
|
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||||
|
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||||
|
# following copyright and license.
|
||||||
#
|
#
|
||||||
# Copyright 1991 by the Massachusetts Institute of Technology
|
# Copyright (C) 1994 X Consortium
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, distribute, and sell this software and its
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# documentation for any purpose is hereby granted without fee, provided that
|
# of this software and associated documentation files (the "Software"), to
|
||||||
# the above copyright notice appear in all copies and that both that
|
# deal in the Software without restriction, including without limitation the
|
||||||
# copyright notice and this permission notice appear in supporting
|
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
# documentation, and that the name of M.I.T. not be used in advertising or
|
# sell copies of the Software, and to permit persons to whom the Software is
|
||||||
# publicity pertaining to distribution of the software without specific,
|
# furnished to do so, subject to the following conditions:
|
||||||
# written prior permission. M.I.T. makes no representations about the
|
#
|
||||||
# suitability of this software for any purpose. It is provided "as is"
|
# The above copyright notice and this permission notice shall be included in
|
||||||
# without express or implied warranty.
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||||
|
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
#
|
||||||
|
# Except as contained in this notice, the name of the X Consortium shall not
|
||||||
|
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||||
|
# ings in this Software without prior written authorization from the X Consor-
|
||||||
|
# tium.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# FSF changes to this file are in the public domain.
|
||||||
#
|
#
|
||||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||||
# `make' implicit rules from creating a file called install from it
|
# `make' implicit rules from creating a file called install from it
|
||||||
@@ -23,13 +42,11 @@
|
|||||||
# from scratch. It can only install one file at a time, a restriction
|
# from scratch. It can only install one file at a time, a restriction
|
||||||
# shared with many OS's install programs.
|
# shared with many OS's install programs.
|
||||||
|
|
||||||
|
|
||||||
# set DOITPROG to echo to test this script
|
# set DOITPROG to echo to test this script
|
||||||
|
|
||||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||||
doit="${DOITPROG-}"
|
doit="${DOITPROG-}"
|
||||||
|
|
||||||
|
|
||||||
# put in absolute paths if you don't have them in your path; or use env. vars.
|
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||||
|
|
||||||
mvprog="${MVPROG-mv}"
|
mvprog="${MVPROG-mv}"
|
||||||
@@ -41,211 +58,229 @@ stripprog="${STRIPPROG-strip}"
|
|||||||
rmprog="${RMPROG-rm}"
|
rmprog="${RMPROG-rm}"
|
||||||
mkdirprog="${MKDIRPROG-mkdir}"
|
mkdirprog="${MKDIRPROG-mkdir}"
|
||||||
|
|
||||||
transformbasename=""
|
transformbasename=
|
||||||
transform_arg=""
|
transform_arg=
|
||||||
instcmd="$mvprog"
|
instcmd="$mvprog"
|
||||||
chmodcmd="$chmodprog 0755"
|
chmodcmd="$chmodprog 0755"
|
||||||
chowncmd=""
|
chowncmd=
|
||||||
chgrpcmd=""
|
chgrpcmd=
|
||||||
stripcmd=""
|
stripcmd=
|
||||||
rmcmd="$rmprog -f"
|
rmcmd="$rmprog -f"
|
||||||
mvcmd="$mvprog"
|
mvcmd="$mvprog"
|
||||||
src=""
|
src=
|
||||||
dst=""
|
dst=
|
||||||
dir_arg=""
|
dir_arg=
|
||||||
|
|
||||||
while [ x"$1" != x ]; do
|
usage="Usage: $0 [OPTION]... SRCFILE DSTFILE
|
||||||
case $1 in
|
or: $0 -d DIR1 DIR2...
|
||||||
-c) instcmd="$cpprog"
|
|
||||||
shift
|
|
||||||
continue;;
|
|
||||||
|
|
||||||
-d) dir_arg=true
|
In the first form, install SRCFILE to DSTFILE, removing SRCFILE by default.
|
||||||
shift
|
In the second, create the directory path DIR.
|
||||||
continue;;
|
|
||||||
|
|
||||||
-m) chmodcmd="$chmodprog $2"
|
Options:
|
||||||
shift
|
-b=TRANSFORMBASENAME
|
||||||
shift
|
-c copy source (using $cpprog) instead of moving (using $mvprog).
|
||||||
continue;;
|
-d create directories instead of installing files.
|
||||||
|
-g GROUP $chgrp installed files to GROUP.
|
||||||
|
-m MODE $chmod installed files to MODE.
|
||||||
|
-o USER $chown installed files to USER.
|
||||||
|
-s strip installed files (using $stripprog).
|
||||||
|
-t=TRANSFORM
|
||||||
|
--help display this help and exit.
|
||||||
|
--version display version info and exit.
|
||||||
|
|
||||||
-o) chowncmd="$chownprog $2"
|
Environment variables override the default commands:
|
||||||
shift
|
CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
|
||||||
shift
|
"
|
||||||
continue;;
|
|
||||||
|
|
||||||
-g) chgrpcmd="$chgrpprog $2"
|
while test -n "$1"; do
|
||||||
shift
|
case $1 in
|
||||||
shift
|
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||||
continue;;
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
-s) stripcmd="$stripprog"
|
-c) instcmd=$cpprog
|
||||||
shift
|
shift
|
||||||
continue;;
|
continue;;
|
||||||
|
|
||||||
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
-d) dir_arg=true
|
||||||
shift
|
shift
|
||||||
continue;;
|
continue;;
|
||||||
|
|
||||||
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
-g) chgrpcmd="$chgrpprog $2"
|
||||||
shift
|
shift
|
||||||
continue;;
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
*) if [ x"$src" = x ]
|
--help) echo "$usage"; exit 0;;
|
||||||
then
|
|
||||||
src=$1
|
-m) chmodcmd="$chmodprog $2"
|
||||||
else
|
shift
|
||||||
# this colon is to work around a 386BSD /bin/sh bug
|
shift
|
||||||
:
|
continue;;
|
||||||
dst=$1
|
|
||||||
fi
|
-o) chowncmd="$chownprog $2"
|
||||||
shift
|
shift
|
||||||
continue;;
|
shift
|
||||||
esac
|
continue;;
|
||||||
|
|
||||||
|
-s) stripcmd=$stripprog
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
|
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
|
--version) echo "$0 $scriptversion"; exit 0;;
|
||||||
|
|
||||||
|
*) if test -z "$src"; then
|
||||||
|
src=$1
|
||||||
|
else
|
||||||
|
# this colon is to work around a 386BSD /bin/sh bug
|
||||||
|
:
|
||||||
|
dst=$1
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ x"$src" = x ]
|
if test -z "$src"; then
|
||||||
then
|
echo "$0: no input file specified." >&2
|
||||||
echo "install: no input file specified"
|
exit 1
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
true
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ x"$dir_arg" != x ]; then
|
if test -n "$dir_arg"; then
|
||||||
dst=$src
|
dst=$src
|
||||||
src=""
|
src=
|
||||||
|
|
||||||
if [ -d $dst ]; then
|
if test -d "$dst"; then
|
||||||
instcmd=:
|
instcmd=:
|
||||||
chmodcmd=""
|
chmodcmd=
|
||||||
else
|
else
|
||||||
instcmd=mkdir
|
instcmd=$mkdirprog
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
|
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
||||||
|
# might cause directories to be created, which would be especially bad
|
||||||
|
# if $src (and thus $dsttmp) contains '*'.
|
||||||
|
if test ! -f "$src" && test ! -d "$src"; then
|
||||||
|
echo "$0: $src does not exist." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
if test -z "$dst"; then
|
||||||
# might cause directories to be created, which would be especially bad
|
echo "$0: no destination specified." >&2
|
||||||
# if $src (and thus $dsttmp) contains '*'.
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -f $src -o -d $src ]
|
# If destination is a directory, append the input filename; won't work
|
||||||
then
|
# if double slashes aren't ignored.
|
||||||
true
|
if test -d "$dst"; then
|
||||||
else
|
dst=$dst/`basename "$src"`
|
||||||
echo "install: $src does not exist"
|
fi
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ x"$dst" = x ]
|
|
||||||
then
|
|
||||||
echo "install: no destination specified"
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
true
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If destination is a directory, append the input filename; if your system
|
|
||||||
# does not like double slashes in filenames, you may need to add some logic
|
|
||||||
|
|
||||||
if [ -d $dst ]
|
|
||||||
then
|
|
||||||
dst="$dst"/`basename $src`
|
|
||||||
else
|
|
||||||
true
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
## this sed command emulates the dirname command
|
## this sed command emulates the dirname command
|
||||||
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||||
|
|
||||||
# Make sure that the destination directory exists.
|
# Make sure that the destination directory exists.
|
||||||
# this part is taken from Noah Friedman's mkinstalldirs script
|
# (this part is taken from Noah Friedman's mkinstalldirs script.)
|
||||||
|
|
||||||
# Skip lots of stat calls in the usual case.
|
# Skip lots of stat calls in the usual case.
|
||||||
if [ ! -d "$dstdir" ]; then
|
if test ! -d "$dstdir"; then
|
||||||
defaultIFS='
|
defaultIFS='
|
||||||
'
|
'
|
||||||
IFS="${IFS-${defaultIFS}}"
|
IFS="${IFS-$defaultIFS}"
|
||||||
|
|
||||||
oIFS="${IFS}"
|
oIFS=$IFS
|
||||||
# Some sh's can't handle IFS=/ for some reason.
|
# Some sh's can't handle IFS=/ for some reason.
|
||||||
IFS='%'
|
IFS='%'
|
||||||
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
|
set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||||
IFS="${oIFS}"
|
IFS=$oIFS
|
||||||
|
|
||||||
pathcomp=''
|
pathcomp=
|
||||||
|
|
||||||
while [ $# -ne 0 ] ; do
|
while test $# -ne 0 ; do
|
||||||
pathcomp="${pathcomp}${1}"
|
pathcomp=$pathcomp$1
|
||||||
shift
|
shift
|
||||||
|
test -d "$pathcomp" || $mkdirprog "$pathcomp"
|
||||||
if [ ! -d "${pathcomp}" ] ;
|
pathcomp=$pathcomp/
|
||||||
then
|
done
|
||||||
$mkdirprog "${pathcomp}"
|
|
||||||
else
|
|
||||||
true
|
|
||||||
fi
|
|
||||||
|
|
||||||
pathcomp="${pathcomp}/"
|
|
||||||
done
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ x"$dir_arg" != x ]
|
if test -n "$dir_arg"; then
|
||||||
then
|
$doit $instcmd "$dst" \
|
||||||
$doit $instcmd $dst &&
|
&& { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
|
||||||
|
&& { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
|
||||||
|
&& { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
|
||||||
|
&& { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
|
||||||
|
|
||||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
|
|
||||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
|
|
||||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
|
|
||||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
|
|
||||||
else
|
else
|
||||||
|
# If we're going to rename the final executable, determine the name now.
|
||||||
|
if test -z "$transformarg"; then
|
||||||
|
dstfile=`basename "$dst"`
|
||||||
|
else
|
||||||
|
dstfile=`basename "$dst" $transformbasename \
|
||||||
|
| sed $transformarg`$transformbasename
|
||||||
|
fi
|
||||||
|
|
||||||
# If we're going to rename the final executable, determine the name now.
|
# don't allow the sed command to completely eliminate the filename.
|
||||||
|
test -z "$dstfile" && dstfile=`basename "$dst"`
|
||||||
|
|
||||||
if [ x"$transformarg" = x ]
|
# Make a couple of temp file names in the proper directory.
|
||||||
then
|
dsttmp=$dstdir/_inst.$$_
|
||||||
dstfile=`basename $dst`
|
rmtmp=$dstdir/_rm.$$_
|
||||||
else
|
|
||||||
dstfile=`basename $dst $transformbasename |
|
|
||||||
sed $transformarg`$transformbasename
|
|
||||||
fi
|
|
||||||
|
|
||||||
# don't allow the sed command to completely eliminate the filename
|
# Trap to clean up those temp files at exit.
|
||||||
|
trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0
|
||||||
|
trap '(exit $?); exit' 1 2 13 15
|
||||||
|
|
||||||
if [ x"$dstfile" = x ]
|
# Move or copy the file name to the temp name
|
||||||
then
|
$doit $instcmd "$src" "$dsttmp" &&
|
||||||
dstfile=`basename $dst`
|
|
||||||
else
|
|
||||||
true
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Make a temp file name in the proper directory.
|
# and set any options; do chmod last to preserve setuid bits.
|
||||||
|
#
|
||||||
|
# If any of these fail, we abort the whole thing. If we want to
|
||||||
|
# ignore errors from any of these, just make sure not to ignore
|
||||||
|
# errors from the above "$doit $instcmd $src $dsttmp" command.
|
||||||
|
#
|
||||||
|
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
|
||||||
|
&& { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
|
||||||
|
&& { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
|
||||||
|
&& { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } &&
|
||||||
|
|
||||||
dsttmp=$dstdir/#inst.$$#
|
# Now remove or move aside any old file at destination location. We
|
||||||
|
# try this two ways since rm can't unlink itself on some systems and
|
||||||
# Move or copy the file name to the temp name
|
# the destination file might be busy for other reasons. In this case,
|
||||||
|
# the final cleanup might fail but the new file should still install
|
||||||
$doit $instcmd $src $dsttmp &&
|
# successfully.
|
||||||
|
{
|
||||||
trap "rm -f ${dsttmp}" 0 &&
|
if test -f "$dstdir/$dstfile"; then
|
||||||
|
$doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
|
||||||
# and set any options; do chmod last to preserve setuid bits
|
|| $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
|
||||||
|
|| {
|
||||||
# If any of these fail, we abort the whole thing. If we want to
|
echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
|
||||||
# ignore errors from any of these, just make sure not to ignore
|
(exit 1); exit
|
||||||
# errors from the above "$doit $instcmd $src $dsttmp" command.
|
}
|
||||||
|
else
|
||||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
|
:
|
||||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
|
fi
|
||||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
|
} &&
|
||||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
|
|
||||||
|
|
||||||
# Now rename the file to the real destination.
|
|
||||||
|
|
||||||
$doit $rmcmd -f $dstdir/$dstfile &&
|
|
||||||
$doit $mvcmd $dsttmp $dstdir/$dstfile
|
|
||||||
|
|
||||||
|
# Now rename the file to the real destination.
|
||||||
|
$doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
|
||||||
fi &&
|
fi &&
|
||||||
|
|
||||||
|
# The final little trick to "correctly" pass the exit status to the exit trap.
|
||||||
|
{
|
||||||
|
(exit 0); exit
|
||||||
|
}
|
||||||
|
|
||||||
exit 0
|
# Local variables:
|
||||||
|
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||||
|
# time-stamp-start: "scriptversion="
|
||||||
|
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||||
|
# time-stamp-end: "$"
|
||||||
|
# End:
|
||||||
|
|||||||
204
configure.in
204
configure.in
@@ -1,4 +1,3 @@
|
|||||||
################################################################################
|
|
||||||
##
|
##
|
||||||
## Copyright 1999-2000 Sistina Software, Inc.
|
## Copyright 1999-2000 Sistina Software, Inc.
|
||||||
##
|
##
|
||||||
@@ -46,6 +45,32 @@ AC_TYPE_SIZE_T
|
|||||||
AC_STRUCT_ST_RDEV
|
AC_STRUCT_ST_RDEV
|
||||||
AC_HEADER_TIME
|
AC_HEADER_TIME
|
||||||
|
|
||||||
|
dnl Get system type
|
||||||
|
AC_CANONICAL_SYSTEM
|
||||||
|
|
||||||
|
case "$host_os" in
|
||||||
|
linux*)
|
||||||
|
CFLAGS=
|
||||||
|
CLDFLAGS="-Wl,--version-script,.export.sym"
|
||||||
|
CLDWHOLEARCHIVE="-Wl,-whole-archive"
|
||||||
|
CLDNOWHOLEARCHIVE="-Wl,-no-whole-archive"
|
||||||
|
LD_DEPS=".export.sym"
|
||||||
|
LD_FLAGS="-Wl,--export-dynamic"
|
||||||
|
SOFLAG="-shared"
|
||||||
|
DEVMAPPER=yes
|
||||||
|
ODIRECT=yes ;;
|
||||||
|
darwin*)
|
||||||
|
CFLAGS="-no-cpp-precomp -fno-common"
|
||||||
|
CLDFLAGS=
|
||||||
|
CLDWHOLEARCHIVE="-all_load"
|
||||||
|
CLDNOWHOLEARCHIVE=
|
||||||
|
LD_DEPS=
|
||||||
|
LD_FLAGS=
|
||||||
|
SOFLAG="-dynamiclib"
|
||||||
|
DEVMAPPER=no
|
||||||
|
ODIRECT=no ;;
|
||||||
|
esac
|
||||||
|
|
||||||
dnl -- prefix is /usr by default, the exec_prefix default is setup later
|
dnl -- prefix is /usr by default, the exec_prefix default is setup later
|
||||||
AC_PREFIX_DEFAULT(/usr)
|
AC_PREFIX_DEFAULT(/usr)
|
||||||
|
|
||||||
@@ -61,15 +86,81 @@ AC_ARG_WITH(group,
|
|||||||
[ GROUP="$withval" ],
|
[ GROUP="$withval" ],
|
||||||
[ GROUP="root" ])
|
[ GROUP="root" ])
|
||||||
|
|
||||||
AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=)
|
dnl -- LVM1 tool fallback option
|
||||||
|
AC_ARG_ENABLE(lvm1_fallback, [ --enable-lvm1_fallback Use this to fall back and use LVM1 binaries if
|
||||||
|
device-mapper is missing from the kernel], LVM1_FALLBACK=$enableval, LVM1_FALLBACK=no)
|
||||||
|
|
||||||
dnl Enables staticly linked tools
|
if test x$LVM1_FALLBACK = xyes; then
|
||||||
AC_ARG_ENABLE(static_link, [ --enable-static_link Use this to link the tools to the liblvm library
|
CFLAGS="$CFLAGS -DLVM1_FALLBACK"
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl -- format1 inclusion type
|
||||||
|
AC_ARG_WITH(lvm1,
|
||||||
|
[ --with-lvm1=TYPE LVM1 metadata support: internal/shared/none
|
||||||
|
[TYPE=internal] ],
|
||||||
|
[ LVM1="$withval" ],
|
||||||
|
[ LVM1="internal" ])
|
||||||
|
|
||||||
|
if [[ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]];
|
||||||
|
then AC_MSG_ERROR(
|
||||||
|
--with-lvm1 parameter invalid
|
||||||
|
)
|
||||||
|
exit
|
||||||
|
fi;
|
||||||
|
|
||||||
|
if test x$LVM1 = xinternal; then
|
||||||
|
CFLAGS="$CFLAGS -DLVM1_INTERNAL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=-j2)
|
||||||
|
|
||||||
|
dnl Enables staticly-linked tools
|
||||||
|
AC_ARG_ENABLE(static_link, [ --enable-static_link Use this to link the tools to their libraries
|
||||||
statically. Default is dynamic linking], STATIC_LINK=$enableval, STATIC_LINK=no)
|
statically. Default is dynamic linking], STATIC_LINK=$enableval, STATIC_LINK=no)
|
||||||
|
|
||||||
dnl Disable readline
|
dnl Enable readline
|
||||||
AC_ARG_ENABLE(readline, [ --disable-readline Disable readline support], \
|
AC_ARG_ENABLE(readline, [ --enable-readline Enable readline support], \
|
||||||
READLINE=$enableval, READLINE=yes)
|
READLINE=$enableval, READLINE=no)
|
||||||
|
|
||||||
|
if test x$READLINE = xyes; then
|
||||||
|
CFLAGS="$CFLAGS -DREADLINE_SUPPORT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $ac_n "checking whether to enable debugging""... $ac_c" 1>&6
|
||||||
|
dnl Enable Debugging
|
||||||
|
AC_ARG_ENABLE(debug, [ --enable-debug Enable debugging], \
|
||||||
|
DEBUG=yes, DEBUG=no)
|
||||||
|
echo "$ac_t""$DEBUG" 1>&6
|
||||||
|
|
||||||
|
echo $ac_n "checking whether to enable device-mapper""... $ac_c" 1>&6
|
||||||
|
dnl Disable devmapper
|
||||||
|
AC_ARG_ENABLE(devmapper, [ --disable-devmapper Disable device-mapper interaction], \
|
||||||
|
DEVMAPPER=no)
|
||||||
|
echo "$ac_t""$DEVMAPPER" 1>&6
|
||||||
|
|
||||||
|
if test x$DEVMAPPER = xyes; then
|
||||||
|
CFLAGS="$CFLAGS -DDEVMAPPER_SUPPORT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $ac_n "checking whether to enable O_DIRECT""... $ac_c" 1>&6
|
||||||
|
dnl Disable O_DIRECT
|
||||||
|
AC_ARG_ENABLE(o_direct, [ --disable-o_direct Disable O_DIRECT], \
|
||||||
|
ODIRECT=no)
|
||||||
|
echo "$ac_t""$ODIRECT" 1>&6
|
||||||
|
|
||||||
|
if test x$ODIRECT = xyes; then
|
||||||
|
CFLAGS="$CFLAGS -DO_DIRECT_SUPPORT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $ac_n "checking whether to compile liblvm2cmd.so""... $ac_c" 1>&6
|
||||||
|
dnl Enable cmdlib
|
||||||
|
AC_ARG_ENABLE(cmdlib, [ --enable-cmdlib Build shared command library], \
|
||||||
|
CMDLIB=yes, CMDLIB=no)
|
||||||
|
echo "$ac_t""$CMDLIB" 1>&6
|
||||||
|
|
||||||
|
if test x$CMDLIB = xyes; then
|
||||||
|
CFLAGS="$CFLAGS -DCMDLIB"
|
||||||
|
fi
|
||||||
|
|
||||||
dnl Mess with default exec_prefix
|
dnl Mess with default exec_prefix
|
||||||
if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
|
if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
|
||||||
@@ -99,6 +190,35 @@ Note: (n)curses also seems to work as a substitute for termcap. This was
|
|||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
dnl Check for dlopen
|
||||||
|
AC_CHECK_LIB(dl, dlopen, HAVE_LIBDL=yes, HAVE_LIBDL=no)
|
||||||
|
|
||||||
|
if [[ "x$HAVE_LIBDL" = xyes -a "xSTATIC_LINK" = xno ]]; then
|
||||||
|
CFLAGS="$CFLAGS -DHAVE_LIBDL"
|
||||||
|
LIBS="-ldl $LIBS"
|
||||||
|
else
|
||||||
|
HAVE_LIBDL=no
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl Check for shared/static conflicts
|
||||||
|
if [[ "x$LVM1" = xshared -a "x$STATIC_LINK" = xyes ]];
|
||||||
|
then AC_MSG_ERROR(
|
||||||
|
Features cannot be 'shared' when building statically
|
||||||
|
)
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl Check for is_selinux_enabled
|
||||||
|
AC_CHECK_LIB(selinux, is_selinux_enabled, HAVE_SELINUX=yes, HAVE_SELINUX=no)
|
||||||
|
|
||||||
|
if test x$HAVE_SELINUX = xyes; then
|
||||||
|
CFLAGS="$CFLAGS -DHAVE_SELINUX"
|
||||||
|
LIBS="-lselinux $LIBS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl Check for getopt
|
||||||
|
AC_CHECK_HEADERS(getopt.h, CFLAGS="$CFLAGS -DHAVE_GETOPTLONG")
|
||||||
|
|
||||||
dnl Check for readline (Shamelessly copied from parted 1.4.17)
|
dnl Check for readline (Shamelessly copied from parted 1.4.17)
|
||||||
if test x$READLINE = xyes; then
|
if test x$READLINE = xyes; then
|
||||||
AC_CHECK_LIB(readline, readline, ,
|
AC_CHECK_LIB(readline, readline, ,
|
||||||
@@ -112,10 +232,43 @@ package as well (which may be called readline-devel or something similar).
|
|||||||
)
|
)
|
||||||
exit
|
exit
|
||||||
)
|
)
|
||||||
AC_CHECK_FUNC(rl_completion_matches, HAVE_RL_COMPLETION_MATCHES=yes,
|
AC_CHECK_FUNC(rl_completion_matches, CFLAGS="$CFLAGS -DHAVE_RL_COMPLETION_MATCHES")
|
||||||
HAVE_RL_COMPLETION_MATCHES=no)
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo $ac_n "checking whether to enable internationalisation""... $ac_c" 1>&6
|
||||||
|
dnl Internationalisation stuff
|
||||||
|
AC_ARG_ENABLE(nls, [ --enable-nls Enable Native Language Support],\
|
||||||
|
INTL=yes, INTL=no)
|
||||||
|
echo "$ac_t""$INTL" 1>&6
|
||||||
|
|
||||||
|
if test x$INTL = xyes; then
|
||||||
|
INTL_PACKAGE="lvm2"
|
||||||
|
AC_PATH_PROG(MSGFMT, msgfmt)
|
||||||
|
if [[ "x$MSGFMT" == x ]];
|
||||||
|
then AC_MSG_ERROR(
|
||||||
|
msgfmt not found in path $PATH
|
||||||
|
)
|
||||||
|
exit
|
||||||
|
fi;
|
||||||
|
|
||||||
|
AC_ARG_WITH(localedir,
|
||||||
|
[ --with-localedir=DIR Translation files in DIR [PREFIX/share/locale]],
|
||||||
|
[ LOCALEDIR="$withval" ],
|
||||||
|
[ LOCALEDIR='${prefix}/share/locale' ])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_ARG_WITH(confdir,
|
||||||
|
[ --with-confdir=DIR Configuration files in DIR [/etc]],
|
||||||
|
[ CONFDIR="$withval" ],
|
||||||
|
[ CONFDIR='/etc' ])
|
||||||
|
|
||||||
|
AC_ARG_WITH(staticdir,
|
||||||
|
[ --with-staticdir=DIR Static binary in DIR [EXEC_PREFIX/sbin]],
|
||||||
|
[ STATICDIR="$withval" ],
|
||||||
|
[ STATICDIR='${exec_prefix}/sbin' ])
|
||||||
|
|
||||||
|
|
||||||
if test "-f VERSION"; then
|
if test "-f VERSION"; then
|
||||||
LVM_VERSION="\"`cat VERSION`\""
|
LVM_VERSION="\"`cat VERSION`\""
|
||||||
else
|
else
|
||||||
@@ -124,20 +277,42 @@ fi
|
|||||||
|
|
||||||
AC_SUBST(JOBS)
|
AC_SUBST(JOBS)
|
||||||
AC_SUBST(STATIC_LINK)
|
AC_SUBST(STATIC_LINK)
|
||||||
AC_SUBST(READLINE)
|
AC_SUBST(LVM1)
|
||||||
AC_SUBST(HAVE_RL_COMPLETION_MATCHES)
|
|
||||||
AC_SUBST(OWNER)
|
AC_SUBST(OWNER)
|
||||||
AC_SUBST(GROUP)
|
AC_SUBST(GROUP)
|
||||||
|
AC_SUBST(CFLAGS)
|
||||||
|
AC_SUBST(CLDFLAGS)
|
||||||
|
AC_SUBST(CLDWHOLEARCHIVE)
|
||||||
|
AC_SUBST(CLDNOWHOLEARCHIVE)
|
||||||
|
AC_SUBST(LD_DEPS)
|
||||||
|
AC_SUBST(LD_FLAGS)
|
||||||
|
AC_SUBST(SOFLAG)
|
||||||
AC_SUBST(LIBS)
|
AC_SUBST(LIBS)
|
||||||
AC_SUBST(LVM_VERSION)
|
AC_SUBST(LVM_VERSION)
|
||||||
|
AC_SUBST(LVM1_FALLBACK)
|
||||||
|
AC_SUBST(DEBUG)
|
||||||
|
AC_SUBST(DEVMAPPER)
|
||||||
|
AC_SUBST(HAVE_LIBDL)
|
||||||
|
AC_SUBST(HAVE_SELINUX)
|
||||||
|
AC_SUBST(CMDLIB)
|
||||||
|
AC_SUBST(MSGFMT)
|
||||||
|
AC_SUBST(LOCALEDIR)
|
||||||
|
AC_SUBST(CONFDIR)
|
||||||
|
AC_SUBST(STATICDIR)
|
||||||
|
AC_SUBST(INTL_PACKAGE)
|
||||||
|
AC_SUBST(INTL)
|
||||||
|
|
||||||
dnl First and last lines should not contain files to generate in order to
|
dnl First and last lines should not contain files to generate in order to
|
||||||
dnl keep utility scripts running properly
|
dnl keep utility scripts running properly
|
||||||
AC_OUTPUT( \
|
AC_OUTPUT( \
|
||||||
Makefile \
|
Makefile \
|
||||||
make.tmpl \
|
make.tmpl \
|
||||||
|
doc/Makefile \
|
||||||
include/Makefile \
|
include/Makefile \
|
||||||
lib/Makefile \
|
lib/Makefile \
|
||||||
|
lib/format1/Makefile \
|
||||||
man/Makefile \
|
man/Makefile \
|
||||||
|
po/Makefile \
|
||||||
tools/Makefile \
|
tools/Makefile \
|
||||||
tools/version.h \
|
tools/version.h \
|
||||||
test/mm/Makefile \
|
test/mm/Makefile \
|
||||||
@@ -146,3 +321,10 @@ test/format1/Makefile \
|
|||||||
test/regex/Makefile \
|
test/regex/Makefile \
|
||||||
test/filters/Makefile \
|
test/filters/Makefile \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if test x$ODIRECT != xyes; then
|
||||||
|
echo
|
||||||
|
echo Warning: O_DIRECT disabled.
|
||||||
|
echo Use of pvmove may cause machine to lock up under low memory conditions.
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
|||||||
6
debian/README.Debian
vendored
Normal file
6
debian/README.Debian
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
LVM2 requires the device-mapper kernel module (dm-mod). This is
|
||||||
|
available as a kernel patch for 2.4 (in kernel-patch-device-mapper), and
|
||||||
|
is distributed with linux 2.5 and above. The LVM1 kernel module (lvm-mod)
|
||||||
|
will not work with lvm2 packages. dm-mod and lvm-mod may both be loaded
|
||||||
|
in the kernel at the same time with no problems. Without dm-mod, this
|
||||||
|
package is pretty useless.
|
||||||
38
debian/changelog
vendored
38
debian/changelog
vendored
@@ -1,3 +1,41 @@
|
|||||||
|
lvm2 (1.95.15-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* New upstream release.
|
||||||
|
* Remove undocumented manpage symlinks.
|
||||||
|
* Update description to be more informative. (Closes: #173499)
|
||||||
|
* Add kernel-patch-device-mapper suggestion.
|
||||||
|
* Update standards version.
|
||||||
|
|
||||||
|
-- Andres Salomon <dilinger@mp3revolution.net> Sun, 16 Feb 2002 04:21:26 -0400
|
||||||
|
|
||||||
|
lvm2 (1.95.11-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* New upstream release. (Closes: #171436)
|
||||||
|
* Removed TODO and INTRO from debian/docs; added WHATS_NEW.
|
||||||
|
* Remove vgcfgrestore.8 undocumented symlink.
|
||||||
|
* Added a README.Debian, mentioning the device-mapper kernel module
|
||||||
|
requirement that lvm2 has. (Closes: #171674, #163020)
|
||||||
|
* Get rid of debian/conffiles (debhelper's smart enough to figure that out).
|
||||||
|
* debian/copyright fix to appease lintian.
|
||||||
|
* Fix typo in tools/commands.h that caused /usr/sbin/; to be created.
|
||||||
|
|
||||||
|
-- Andres Salomon <dilinger@mp3revolution.net> Mon, 9 Dec 2002 02:51:02 -0400
|
||||||
|
|
||||||
|
lvm2 (1.95.10-2) unstable; urgency=low
|
||||||
|
|
||||||
|
* Fix software raid problems by ensuring lvm init script runs after
|
||||||
|
raidtools init script. (Closes: #152569)
|
||||||
|
|
||||||
|
-- Andres Salomon <dilinger@mp3revolution.net> Tue, 3 Sep 2002 04:05:43 -0400
|
||||||
|
|
||||||
|
lvm2 (1.95.10-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* New upstream release (Beta 3.2).
|
||||||
|
* Change all references to /dev/device-mapper/control to
|
||||||
|
/dev/mapper/control.
|
||||||
|
|
||||||
|
-- Andres Salomon <dilinger@mp3revolution.net> Sun, 1 Sep 2002 18:55:12 -0400
|
||||||
|
|
||||||
lvm2 (0.95.05-3) unstable; urgency=low
|
lvm2 (0.95.05-3) unstable; urgency=low
|
||||||
|
|
||||||
* Get rid of awk dependency in init script. (Closes: #146257)
|
* Get rid of awk dependency in init script. (Closes: #146257)
|
||||||
|
|||||||
2
debian/conffiles
vendored
2
debian/conffiles
vendored
@@ -1,2 +0,0 @@
|
|||||||
/etc/lvm/lvm.conf
|
|
||||||
/etc/init.d/lvm2
|
|
||||||
10
debian/control
vendored
10
debian/control
vendored
@@ -2,8 +2,8 @@ Source: lvm2
|
|||||||
Section: admin
|
Section: admin
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: Andres Salomon <dilinger@mp3revolution.net>
|
Maintainer: Andres Salomon <dilinger@mp3revolution.net>
|
||||||
Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev, libreadline4-dev
|
Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev (>= 0.96.04), libreadline4-dev
|
||||||
Standards-Version: 3.5.2
|
Standards-Version: 3.5.8.0
|
||||||
|
|
||||||
Package: lvm2
|
Package: lvm2
|
||||||
Architecture: any
|
Architecture: any
|
||||||
@@ -11,10 +11,14 @@ Depends: ${shlibs:Depends}
|
|||||||
Conflicts: lvm10, lvm-common
|
Conflicts: lvm10, lvm-common
|
||||||
Replaces: lvm10, lvm-common
|
Replaces: lvm10, lvm-common
|
||||||
Provides: lvm-binaries
|
Provides: lvm-binaries
|
||||||
Suggests: dmsetup
|
Suggests: dmsetup, kernel-patch-device-mapper
|
||||||
Description: The Linux Logical Volume Manager
|
Description: The Linux Logical Volume Manager
|
||||||
This is LVM2, the rewrite of The Linux Logical Volume Manager. LVM
|
This is LVM2, the rewrite of The Linux Logical Volume Manager. LVM
|
||||||
supports enterprise level volume management of disk and disk subsystems
|
supports enterprise level volume management of disk and disk subsystems
|
||||||
by grouping arbitrary disks into volume groups. The total capacity of
|
by grouping arbitrary disks into volume groups. The total capacity of
|
||||||
volume groups can be allocated to logical volumes, which are accessed as
|
volume groups can be allocated to logical volumes, which are accessed as
|
||||||
regular block devices.
|
regular block devices.
|
||||||
|
.
|
||||||
|
LVM2 is currently stable, but has some unimplemented features (most notably,
|
||||||
|
pvmove and e2fsadm). It is not yet recommended for production use. It is
|
||||||
|
backwards-compatible with LVM1 (lvm10), and requires Linux kernel 2.4.
|
||||||
|
|||||||
2
debian/copyright
vendored
2
debian/copyright
vendored
@@ -3,7 +3,7 @@ Wed, 20 Feb 2002 03:17:25 -0500.
|
|||||||
|
|
||||||
It was downloaded from http://www.sistina.com/products_lvm.htm
|
It was downloaded from http://www.sistina.com/products_lvm.htm
|
||||||
|
|
||||||
Upstream Author(s): LVM Development Team
|
Upstream Author: LVM Development Team
|
||||||
|
|
||||||
Copyright (c) 2001-2002 LVM Development Team
|
Copyright (c) 2001-2002 LVM Development Team
|
||||||
|
|
||||||
|
|||||||
3
debian/docs
vendored
3
debian/docs
vendored
@@ -1,6 +1,5 @@
|
|||||||
BUGS
|
BUGS
|
||||||
INTRO
|
|
||||||
README
|
README
|
||||||
TODO
|
|
||||||
VERSION
|
VERSION
|
||||||
|
WHATS_NEW
|
||||||
doc/*
|
doc/*
|
||||||
|
|||||||
2
debian/init.d
vendored
2
debian/init.d
vendored
@@ -14,7 +14,7 @@ modprobe dm-mod >/dev/null 2>&1
|
|||||||
|
|
||||||
# Create necessary files in /dev for device-mapper
|
# Create necessary files in /dev for device-mapper
|
||||||
create_devfiles() {
|
create_devfiles() {
|
||||||
DIR="/dev/device-mapper"
|
DIR="/dev/mapper"
|
||||||
FILE="$DIR/control"
|
FILE="$DIR/control"
|
||||||
major=$(grep "[0-9] misc$" /proc/devices | sed 's/[ ]\+misc//')
|
major=$(grep "[0-9] misc$" /proc/devices | sed 's/[ ]\+misc//')
|
||||||
minor=$(grep "[0-9] device-mapper$" /proc/misc | sed 's/[ ]\+device-mapper//')
|
minor=$(grep "[0-9] device-mapper$" /proc/misc | sed 's/[ ]\+device-mapper//')
|
||||||
|
|||||||
3
debian/rules
vendored
3
debian/rules
vendored
@@ -98,11 +98,10 @@ binary-arch: build install
|
|||||||
# dh_installemacsen -a
|
# dh_installemacsen -a
|
||||||
# dh_installpam -a
|
# dh_installpam -a
|
||||||
# dh_installmime -a
|
# dh_installmime -a
|
||||||
dh_installinit --update-rcd-params="start 25 S . start 50 0 6 ."
|
dh_installinit --update-rcd-params="start 26 S . start 50 0 6 ."
|
||||||
dh_installcron
|
dh_installcron
|
||||||
dh_installman
|
dh_installman
|
||||||
dh_installinfo
|
dh_installinfo
|
||||||
dh_undocumented
|
|
||||||
dh_installchangelogs
|
dh_installchangelogs
|
||||||
dh_strip
|
dh_strip
|
||||||
dh_link
|
dh_link
|
||||||
|
|||||||
14
debian/undocumented
vendored
14
debian/undocumented
vendored
@@ -1,14 +0,0 @@
|
|||||||
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
|
|
||||||
29
doc/Makefile.in
Normal file
29
doc/Makefile.in
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#
|
||||||
|
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
|
#
|
||||||
|
# This file is part of the LVM2.
|
||||||
|
#
|
||||||
|
# This copyrighted material is made available to anyone wishing to use,
|
||||||
|
# modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
# of the GNU General Public License v.2.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
VPATH = @srcdir@
|
||||||
|
|
||||||
|
CONFSRC=example.conf
|
||||||
|
CONFDEST=lvm.conf
|
||||||
|
|
||||||
|
include ../make.tmpl
|
||||||
|
|
||||||
|
install:
|
||||||
|
@if [ ! -e $(confdir)/$(CONFDEST) ]; then \
|
||||||
|
echo "Installing $(CONFSRC) as $(confdir)/$(CONFDEST)"; \
|
||||||
|
@INSTALL@ -D -o $(OWNER) -g $(GROUP) -m 644 $(CONFSRC) \
|
||||||
|
$(confdir)/$(CONFDEST); \
|
||||||
|
fi
|
||||||
|
|
||||||
219
doc/example.conf
219
doc/example.conf
@@ -1,74 +1,98 @@
|
|||||||
# This is an example configuration file for the LVM2 system. It
|
# This is an example configuration file for the LVM2 system.
|
||||||
# contains the default settings that would be used if there was no
|
# It contains the default settings that would be used if there was no
|
||||||
# /etc/lvm/lvm.conf file.
|
# /etc/lvm/lvm.conf file.
|
||||||
# Refer to 'man lvm.conf' for further information.
|
#
|
||||||
|
# Refer to 'man lvm.conf' for further information including the file layout.
|
||||||
|
#
|
||||||
|
# To put this file in a different directory and override /etc/lvm set
|
||||||
|
# the environment variable LVM_SYSTEM_DIR before running the tools.
|
||||||
|
|
||||||
|
|
||||||
# This section allows the user to configure which block devices should
|
# This section allows you to configure which block devices should
|
||||||
# be used by the LVM system.
|
# be used by the LVM system.
|
||||||
devices {
|
devices {
|
||||||
|
|
||||||
# where do you want your volume groups to appear ?
|
# Where do you want your volume groups to appear ?
|
||||||
dir = "/dev"
|
dir = "/dev"
|
||||||
|
|
||||||
# An array of directories that contain the device nodes you wish
|
# An array of directories that contain the device nodes you wish
|
||||||
# to use with LVM2.
|
# to use with LVM2.
|
||||||
scan = "/dev"
|
scan = [ "/dev" ]
|
||||||
|
|
||||||
# A very important option, that allows you to tune the LVM2 system
|
|
||||||
# to just look at a restricted set of devices that you're
|
|
||||||
# interested in.
|
|
||||||
|
|
||||||
|
# A filter that tells LVM2 to only use a restricted set of devices.
|
||||||
# The filter consists of an array of regular expressions. These
|
# The filter consists of an array of regular expressions. These
|
||||||
# expressions can be delimited by a character of your choice, and
|
# expressions can be delimited by a character of your choice, and
|
||||||
# prefixed with either an 'a' (for accept) or 'r' (for reject).
|
# prefixed with either an 'a' (for accept) or 'r' (for reject).
|
||||||
# ATM you cannot use anchors (^ or $) in your regular expression.
|
# The first expression found to match a device name determines if
|
||||||
|
# the device will be accepted or rejected (ignored). Devices that
|
||||||
|
# don't match any patterns are accepted.
|
||||||
|
|
||||||
# Remember to run vgscan after you change this parameter.
|
# If using RAID md devices as physical volumes, you should
|
||||||
|
# set up a filter here to reject the constituent devices.
|
||||||
|
|
||||||
|
# Remember to run vgscan after you change this parameter to ensure
|
||||||
|
# that the cache file gets regenerated (see below).
|
||||||
|
|
||||||
# By default we accept every block device:
|
# By default we accept every block device:
|
||||||
filter = "a/.*/"
|
filter = [ "a/.*/" ]
|
||||||
|
|
||||||
|
# Exclude the cdrom drive
|
||||||
|
# filter = [ "r|/dev/cdrom|" ]
|
||||||
|
|
||||||
# When testing I like to work with just loopback devices:
|
# When testing I like to work with just loopback devices:
|
||||||
# filter = ["a/loop/", "r/.*/"]
|
# filter = [ "a/loop/", "r/.*/" ]
|
||||||
|
|
||||||
# Or maybe all loops and ide drives except hdc:
|
# Or maybe all loops and ide drives except hdc:
|
||||||
# filter =["a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|"]
|
# filter =[ "a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|" ]
|
||||||
|
|
||||||
# The results of all the filtering are cached on disk to avoid
|
# Use anchors if you want to be really specific
|
||||||
|
# filter = [ "a|^/dev/hda8$|", "r/.*/" ]
|
||||||
|
|
||||||
|
# The results of the filtering are cached on disk to avoid
|
||||||
# rescanning dud devices (which can take a very long time). By
|
# rescanning dud devices (which can take a very long time). By
|
||||||
# default this cache file is hidden in the /etc/lvm directory, it
|
# default this cache file is hidden in the /etc/lvm directory.
|
||||||
# is human readable to aid filter debugging.
|
# It is safe to delete this file: the tools regenerate it.
|
||||||
cache = "/etc/lvm/.cache"
|
cache = "/etc/lvm/.cache"
|
||||||
|
|
||||||
# You can turn off writing this cache file by setting this to 0.
|
# You can turn off writing this cache file by setting this to 0.
|
||||||
write_cache_state = 1
|
write_cache_state = 1
|
||||||
|
|
||||||
|
# An advanced setting.
|
||||||
|
# List of pairs of additional acceptable block device types found
|
||||||
|
# in /proc/devices with maximum (non-zero) number of partitions.
|
||||||
|
# types = [ "fd", 16 ]
|
||||||
|
|
||||||
|
# If sysfs is mounted (2.6 kernels) restrict device scanning to
|
||||||
|
# the block devices it believes are valid.
|
||||||
|
sysfs_scan = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# A section that allows the user to configure the nature of the
|
# This section that allows you to configure the nature of the
|
||||||
# information that LVM2 reports.
|
# information that LVM2 reports.
|
||||||
log {
|
log {
|
||||||
|
|
||||||
# Where should the log of error and debug messages go ? By
|
# Controls the messages sent to stdout or stderr.
|
||||||
# default there is no log.
|
# There are three levels of verbosity, 3 being the most verbose.
|
||||||
#file = "/var/log/lvm2.log"
|
|
||||||
|
|
||||||
# Should we overwrite the last log. By default we append.
|
|
||||||
overwrite = 0
|
|
||||||
|
|
||||||
# There are 9 log levels, with 9 being the most verbose.
|
|
||||||
level = 3
|
|
||||||
|
|
||||||
# Controls the messages sent to stdout or stderr while running
|
|
||||||
# LVM2. There are three levels of verbosity, 3 being the most
|
|
||||||
# verbose.
|
|
||||||
verbose = 0
|
verbose = 0
|
||||||
|
|
||||||
# Should we send log messages through syslog?
|
# Should we send log messages through syslog?
|
||||||
# 1 is yes; 0 is no.
|
# 1 is yes; 0 is no.
|
||||||
syslog = 1
|
syslog = 1
|
||||||
|
|
||||||
# Choose format of output messages
|
# Should we log error and debug messages to a file?
|
||||||
|
# By default there is no log file.
|
||||||
|
#file = "/var/log/lvm2.log"
|
||||||
|
|
||||||
|
# Should we overwrite the log file each time the program is run?
|
||||||
|
# By default we append.
|
||||||
|
overwrite = 0
|
||||||
|
|
||||||
|
# What level of log messages should we send to the log file and/or syslog?
|
||||||
|
# There are 6 syslog-like log levels currently in use - 2 to 7 inclusive.
|
||||||
|
# 7 is the most verbose (LOG_DEBUG).
|
||||||
|
level = 0
|
||||||
|
|
||||||
|
# Format of output messages
|
||||||
# Whether or not (1 or 0) to indent messages according to their severity
|
# Whether or not (1 or 0) to indent messages according to their severity
|
||||||
indent = 1
|
indent = 1
|
||||||
|
|
||||||
@@ -76,13 +100,18 @@ log {
|
|||||||
command_names = 0
|
command_names = 0
|
||||||
|
|
||||||
# A prefix to use before the message text (but after the command name,
|
# A prefix to use before the message text (but after the command name,
|
||||||
# if selected)
|
# if selected). Default is two spaces, so you can see/grep the severity
|
||||||
|
# of each message.
|
||||||
prefix = " "
|
prefix = " "
|
||||||
|
|
||||||
# To make the messages look similar to the original LVM use:
|
# To make the messages look similar to the original LVM tools use:
|
||||||
# indent = 0
|
# indent = 0
|
||||||
# command_names = 1
|
# command_names = 1
|
||||||
# prefix = " -- "
|
# prefix = " -- "
|
||||||
|
|
||||||
|
# Set this if you want log messages during activation.
|
||||||
|
# Don't use this in low memory situations (can deadlock).
|
||||||
|
# activation = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# Configuration of metadata backups and archiving. In LVM2 when we
|
# Configuration of metadata backups and archiving. In LVM2 when we
|
||||||
@@ -93,19 +122,20 @@ backup {
|
|||||||
|
|
||||||
# Should we maintain a backup of the current metadata configuration ?
|
# Should we maintain a backup of the current metadata configuration ?
|
||||||
# Use 1 for Yes; 0 for No.
|
# Use 1 for Yes; 0 for No.
|
||||||
# Think very hard before turning this off.
|
# Think very hard before turning this off!
|
||||||
backup = 1
|
backup = 1
|
||||||
|
|
||||||
# Where shall we keep it ?
|
# Where shall we keep it ?
|
||||||
|
# Remember to back up this directory regularly!
|
||||||
backup_dir = "/etc/lvm/backup"
|
backup_dir = "/etc/lvm/backup"
|
||||||
|
|
||||||
|
|
||||||
# Should we maintain an archive of old metadata configurations.
|
# Should we maintain an archive of old metadata configurations.
|
||||||
# Use 1 for Yes; 0 for No.
|
# Use 1 for Yes; 0 for No.
|
||||||
# On by default. Think very hard before turning this off.
|
# On by default. Think very hard before turning this off.
|
||||||
archive = 1
|
archive = 1
|
||||||
|
|
||||||
# Where should archived files go ?
|
# Where should archived files go ?
|
||||||
|
# Remember to back up this directory regularly!
|
||||||
archive_dir = "/etc/lvm/archive"
|
archive_dir = "/etc/lvm/archive"
|
||||||
|
|
||||||
# What is the minimum number of archive files you wish to keep ?
|
# What is the minimum number of archive files you wish to keep ?
|
||||||
@@ -115,20 +145,15 @@ backup {
|
|||||||
retain_days = 30
|
retain_days = 30
|
||||||
}
|
}
|
||||||
|
|
||||||
# Settings for the running LVM2 in shell mode.
|
# Settings for the running LVM2 in shell (readline) mode.
|
||||||
shell {
|
shell {
|
||||||
|
|
||||||
# Number of lines of history to store in ~/.lvm_history
|
# Number of lines of history to store in ~/.lvm_history
|
||||||
history_size = 100
|
history_size = 100
|
||||||
}
|
}
|
||||||
|
|
||||||
# Metadata settings
|
|
||||||
metadata {
|
|
||||||
# List of directories holding copies of text format metadata
|
|
||||||
dirs = [ "/etc/lvm/metadata" ]
|
|
||||||
}
|
|
||||||
|
|
||||||
# Miscellaneous global settings
|
# Miscellaneous global LVM2 settings
|
||||||
global {
|
global {
|
||||||
|
|
||||||
# The file creation mask for any files and directories created.
|
# The file creation mask for any files and directories created.
|
||||||
@@ -143,10 +168,112 @@ global {
|
|||||||
# command. Defaults to off.
|
# command. Defaults to off.
|
||||||
test = 0
|
test = 0
|
||||||
|
|
||||||
# Default metadata format commands use - "lvm1" (default) or "text"
|
# Whether or not to communicate with the kernel device-mapper.
|
||||||
format = "lvm1"
|
# Set to 0 if you want to use the tools to manipulate LVM metadata
|
||||||
|
# without activating any logical volumes.
|
||||||
|
# If the device-mapper kernel driver is not present in your kernel
|
||||||
|
# setting this to 0 should suppress the error messages.
|
||||||
|
activation = 1
|
||||||
|
|
||||||
|
# If we can't communicate with device-mapper, should we try running
|
||||||
|
# the LVM1 tools?
|
||||||
|
# This option only applies to 2.4 kernels and is provided to help you
|
||||||
|
# switch between device-mapper kernels and LVM1 kernels.
|
||||||
|
# The LVM1 tools need to be installed with .lvm1 suffices
|
||||||
|
# e.g. vgscan.lvm1 and they will stop working after you start using
|
||||||
|
# the new lvm2 on-disk metadata format.
|
||||||
|
# The default value is set when the tools are built.
|
||||||
|
# fallback_to_lvm1 = 0
|
||||||
|
|
||||||
|
# The default metadata format that commands should use - "lvm1" or "lvm2".
|
||||||
|
# The command line override is -M1 or -M2.
|
||||||
|
# Defaults to "lvm1" if compiled in, else "lvm2".
|
||||||
|
# format = "lvm1"
|
||||||
|
|
||||||
# Location of proc filesystem
|
# Location of proc filesystem
|
||||||
proc = "/proc"
|
proc = "/proc"
|
||||||
|
|
||||||
|
# Type of locking to use. Defaults to file-based locking (1).
|
||||||
|
# Turn locking off by setting to 0 (dangerous: risks metadata corruption
|
||||||
|
# if LVM2 commands get run concurrently).
|
||||||
|
locking_type = 1
|
||||||
|
|
||||||
|
# Local non-LV directory that holds file-based locks while commands are
|
||||||
|
# in progress. A directory like /tmp that may get wiped on reboot is OK.
|
||||||
|
locking_dir = "/var/lock/lvm"
|
||||||
|
|
||||||
|
# Other entries can go here to allow you to load shared libraries
|
||||||
|
# e.g. if support for LVM1 metadata was compiled as a shared library use
|
||||||
|
# format_libraries = "liblvm2format1.so"
|
||||||
|
# Full pathnames can be given.
|
||||||
|
|
||||||
|
# Search this directory first for shared libraries.
|
||||||
|
# library_dir = "/lib"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
activation {
|
||||||
|
# Device used in place of missing stripes if activating incomplete volume.
|
||||||
|
# For now, you need to set this up yourself first (e.g. with 'dmsetup')
|
||||||
|
# For example, you could make it return I/O errors using the 'error'
|
||||||
|
# target or make it return zeros.
|
||||||
|
missing_stripe_filler = "/dev/ioerror"
|
||||||
|
|
||||||
|
# Size (in KB) of each copy operation when mirroring
|
||||||
|
mirror_region_size = 512
|
||||||
|
|
||||||
|
# How much stack (in KB) to reserve for use while devices suspended
|
||||||
|
reserved_stack = 256
|
||||||
|
|
||||||
|
# How much memory (in KB) to reserve for use while devices suspended
|
||||||
|
reserved_memory = 8192
|
||||||
|
|
||||||
|
# Nice value used while devices suspended
|
||||||
|
process_priority = -18
|
||||||
|
|
||||||
|
# If volume_list is defined, each LV is only activated if there is a
|
||||||
|
# match against the list.
|
||||||
|
# "vgname" and "vgname/lvname" are matched exactly.
|
||||||
|
# "@tag" matches any tag set in the LV or VG.
|
||||||
|
# "@*" matches if any tag defined on the host is also set in the LV or VG
|
||||||
|
#
|
||||||
|
# volume_list = [ "vg1", "vg2/lvol1", "@tag1", "@*" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
####################
|
||||||
|
# Advanced section #
|
||||||
|
####################
|
||||||
|
|
||||||
|
# Metadata settings
|
||||||
|
#
|
||||||
|
# metadata {
|
||||||
|
# Default number of copies of metadata to hold on each PV. 0, 1 or 2.
|
||||||
|
# It's best to leave this at 2.
|
||||||
|
# You might want to override it from the command line with 0 or 1
|
||||||
|
# when running pvcreate on new PVs which are to be added to large VGs.
|
||||||
|
|
||||||
|
# pvmetadatacopies = 2
|
||||||
|
|
||||||
|
# Approximate default size of on-disk metadata areas in sectors.
|
||||||
|
# You should increase this if you have large volume groups or
|
||||||
|
# you want to retain a large on-disk history of your metadata changes.
|
||||||
|
|
||||||
|
# pvmetadatasize = 255
|
||||||
|
|
||||||
|
# List of directories holding live copies of text format metadata.
|
||||||
|
# These directories must not be on logical volumes!
|
||||||
|
# It's possible to use LVM2 with a couple of directories here,
|
||||||
|
# preferably on different (non-LV) filesystems, and with no other
|
||||||
|
# on-disk metadata (pvmetadatacopies = 0). Or this can be in
|
||||||
|
# addition to on-disk metadata areas.
|
||||||
|
# The feature was originally added to simplify testing and is not
|
||||||
|
# supported under low memory situations - the machine could lock up.
|
||||||
|
#
|
||||||
|
# Never edit any files in these directories by hand unless you
|
||||||
|
# you are absolutely sure you know what you are doing! Use
|
||||||
|
# the supplied toolset to make changes (e.g. vgcfgrestore).
|
||||||
|
|
||||||
|
# dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ]
|
||||||
|
#}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
47
doc/example_cmdlib.c
Normal file
47
doc/example_cmdlib.c
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lvm2cmd.h"
|
||||||
|
|
||||||
|
/* All output gets passed to this function line-by-line */
|
||||||
|
void test_log_fn(int level, const char *file, int line, const char *format)
|
||||||
|
{
|
||||||
|
/* Extract and process output here rather than printing it */
|
||||||
|
|
||||||
|
if (level != 4)
|
||||||
|
return;
|
||||||
|
|
||||||
|
printf("%s\n", format);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
void *handle;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
lvm2_log_fn(test_log_fn);
|
||||||
|
|
||||||
|
handle = lvm2_init();
|
||||||
|
|
||||||
|
lvm2_log_level(handle, 1);
|
||||||
|
r = lvm2_run(handle, "vgs --noheadings vg1");
|
||||||
|
|
||||||
|
/* More commands here */
|
||||||
|
|
||||||
|
lvm2_exit(handle);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
../lib/activate/activate.h
|
../lib/activate/activate.h
|
||||||
|
../lib/cache/lvmcache.h
|
||||||
../lib/commands/errors.h
|
../lib/commands/errors.h
|
||||||
../lib/commands/toolcontext.h
|
../lib/commands/toolcontext.h
|
||||||
../lib/config/config.h
|
../lib/config/config.h
|
||||||
@@ -8,26 +9,34 @@
|
|||||||
../lib/datastruct/hash.h
|
../lib/datastruct/hash.h
|
||||||
../lib/datastruct/list.h
|
../lib/datastruct/list.h
|
||||||
../lib/datastruct/lvm-types.h
|
../lib/datastruct/lvm-types.h
|
||||||
|
../lib/datastruct/str_list.h
|
||||||
../lib/device/dev-cache.h
|
../lib/device/dev-cache.h
|
||||||
../lib/device/device.h
|
../lib/device/device.h
|
||||||
../lib/display/display.h
|
../lib/display/display.h
|
||||||
../lib/filters/filter-composite.h
|
../lib/filters/filter-composite.h
|
||||||
../lib/filters/filter-persistent.h
|
../lib/filters/filter-persistent.h
|
||||||
../lib/filters/filter-regex.h
|
../lib/filters/filter-regex.h
|
||||||
|
../lib/filters/filter-sysfs.h
|
||||||
../lib/filters/filter.h
|
../lib/filters/filter.h
|
||||||
../lib/format1/format1.h
|
../lib/format1/format1.h
|
||||||
../lib/format1/lvm1_label.h
|
|
||||||
../lib/format_text/format-text.h
|
../lib/format_text/format-text.h
|
||||||
../lib/label/label.h
|
../lib/label/label.h
|
||||||
../lib/label/uuid-map.h
|
|
||||||
../lib/locking/locking.h
|
../lib/locking/locking.h
|
||||||
../lib/log/log.h
|
../lib/log/log.h
|
||||||
|
../lib/metadata/lv_alloc.h
|
||||||
../lib/metadata/metadata.h
|
../lib/metadata/metadata.h
|
||||||
../lib/mm/dbg_malloc.h
|
../lib/mm/dbg_malloc.h
|
||||||
|
../lib/mm/memlock.h
|
||||||
../lib/mm/pool.h
|
../lib/mm/pool.h
|
||||||
../lib/mm/xlate.h
|
../lib/mm/xlate.h
|
||||||
|
../lib/misc/crc.h
|
||||||
|
../lib/misc/intl.h
|
||||||
|
../lib/misc/lib.h
|
||||||
../lib/misc/lvm-file.h
|
../lib/misc/lvm-file.h
|
||||||
../lib/misc/lvm-string.h
|
../lib/misc/lvm-string.h
|
||||||
|
../lib/misc/selinux.h
|
||||||
|
../lib/misc/sharedlib.h
|
||||||
../lib/regex/matcher.h
|
../lib/regex/matcher.h
|
||||||
|
../lib/report/report.h
|
||||||
../lib/uuid/uuid.h
|
../lib/uuid/uuid.h
|
||||||
../lib/vgcache/vgcache.h
|
../po/pogen.h
|
||||||
|
|||||||
@@ -1,20 +1,16 @@
|
|||||||
#
|
#
|
||||||
# Copyright (C) 2001 Sistina Software
|
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
#
|
#
|
||||||
# This LVM library is free software; you can redistribute it and/or
|
# This file is part of the LVM2.
|
||||||
# modify it under the terms of the GNU Library General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2 of the License, or (at your option) any later version.
|
|
||||||
#
|
#
|
||||||
# This LVM library is distributed in the hope that it will be useful,
|
# This copyrighted material is made available to anyone wishing to use,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# modify, copy, or redistribute it subject to the terms and conditions
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
# of the GNU General Public License v.2.
|
||||||
# Library General Public License for more details.
|
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Library General Public
|
# You should have received a copy of the GNU General Public License
|
||||||
# License along with this LVM library; if not, write to the Free
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
# MA 02111-1307, USA
|
|
||||||
|
|
||||||
SHELL = /bin/sh
|
SHELL = /bin/sh
|
||||||
|
|
||||||
@@ -35,9 +31,11 @@ distclean:
|
|||||||
find . -maxdepth 1 -type l -exec $(RM) \{\} \;
|
find . -maxdepth 1 -type l -exec $(RM) \{\} \;
|
||||||
$(RM) Makefile .include_symlinks .symlinks_created
|
$(RM) Makefile .include_symlinks .symlinks_created
|
||||||
|
|
||||||
|
pofile: all
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
|
||||||
install:
|
install:
|
||||||
|
|
||||||
.PHONY: clean distclean all install
|
.PHONY: clean distclean all install pofile
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,34 @@
|
|||||||
#
|
#
|
||||||
# Copyright (C) 2001 Sistina Software (UK) Limited
|
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
#
|
#
|
||||||
# This file is released under the GPL.
|
# This file is part of the LVM2.
|
||||||
#
|
#
|
||||||
|
# This copyrighted material is made available to anyone wishing to use,
|
||||||
|
# modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
# of the GNU General Public License v.2.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@
|
||||||
|
|
||||||
SOURCES=\
|
ifeq ("@LVM1@", "shared")
|
||||||
|
SUBDIRS = format1
|
||||||
|
endif
|
||||||
|
|
||||||
|
SOURCES =\
|
||||||
activate/activate.c \
|
activate/activate.c \
|
||||||
activate/dev_manager.c \
|
cache/lvmcache.c \
|
||||||
activate/fs.c \
|
commands/toolcontext.c \
|
||||||
config/config.c \
|
config/config.c \
|
||||||
datastruct/bitset.c \
|
datastruct/bitset.c \
|
||||||
datastruct/btree.c \
|
datastruct/btree.c \
|
||||||
datastruct/hash.c \
|
datastruct/hash.c \
|
||||||
|
datastruct/str_list.c \
|
||||||
device/dev-cache.c \
|
device/dev-cache.c \
|
||||||
device/dev-io.c \
|
device/dev-io.c \
|
||||||
device/device.c \
|
device/device.c \
|
||||||
@@ -23,22 +36,17 @@ SOURCES=\
|
|||||||
filters/filter-composite.c \
|
filters/filter-composite.c \
|
||||||
filters/filter-persistent.c \
|
filters/filter-persistent.c \
|
||||||
filters/filter-regex.c \
|
filters/filter-regex.c \
|
||||||
|
filters/filter-sysfs.c \
|
||||||
filters/filter.c \
|
filters/filter.c \
|
||||||
format1/disk-rep.c \
|
|
||||||
format1/format1.c \
|
|
||||||
format1/import-export.c \
|
|
||||||
format1/import-extents.c \
|
|
||||||
format1/layout.c \
|
|
||||||
format1/lvm1_label.c \
|
|
||||||
format1/vg_number.c \
|
|
||||||
format_text/archive.c \
|
format_text/archive.c \
|
||||||
format_text/export.c \
|
format_text/export.c \
|
||||||
format_text/flags.c \
|
format_text/flags.c \
|
||||||
format_text/format-text.c \
|
format_text/format-text.c \
|
||||||
format_text/import.c \
|
format_text/import.c \
|
||||||
|
format_text/import_vsn1.c \
|
||||||
|
format_text/tags.c \
|
||||||
|
format_text/text_label.c \
|
||||||
label/label.c \
|
label/label.c \
|
||||||
label/uuid-map.c \
|
|
||||||
locking/external_locking.c \
|
|
||||||
locking/file_locking.c \
|
locking/file_locking.c \
|
||||||
locking/locking.c \
|
locking/locking.c \
|
||||||
locking/no_locking.c \
|
locking/no_locking.c \
|
||||||
@@ -46,23 +54,54 @@ SOURCES=\
|
|||||||
metadata/lv_manip.c \
|
metadata/lv_manip.c \
|
||||||
metadata/merge.c \
|
metadata/merge.c \
|
||||||
metadata/metadata.c \
|
metadata/metadata.c \
|
||||||
|
metadata/mirror.c \
|
||||||
metadata/pv_map.c \
|
metadata/pv_map.c \
|
||||||
metadata/snapshot_manip.c \
|
metadata/snapshot_manip.c \
|
||||||
|
misc/crc.c \
|
||||||
misc/lvm-file.c \
|
misc/lvm-file.c \
|
||||||
mm/dbg_malloc.c \
|
misc/lvm-string.c \
|
||||||
|
mm/memlock.c \
|
||||||
mm/pool.c \
|
mm/pool.c \
|
||||||
regex/matcher.c \
|
regex/matcher.c \
|
||||||
regex/parse_rx.c \
|
regex/parse_rx.c \
|
||||||
regex/ttree.c \
|
regex/ttree.c \
|
||||||
uuid/uuid.c \
|
report/report.c \
|
||||||
vgcache/vgcache.c
|
uuid/uuid.c
|
||||||
|
|
||||||
TARGETS=liblvm.a
|
ifeq ("@LVM1@", "internal")
|
||||||
|
SOURCES +=\
|
||||||
|
format1/disk-rep.c \
|
||||||
|
format1/format1.c \
|
||||||
|
format1/import-export.c \
|
||||||
|
format1/import-extents.c \
|
||||||
|
format1/layout.c \
|
||||||
|
format1/lvm1-label.c \
|
||||||
|
format1/vg_number.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ("@DEBUG@", "yes")
|
||||||
|
SOURCES += mm/dbg_malloc.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ("@DEVMAPPER@", "yes")
|
||||||
|
SOURCES +=\
|
||||||
|
activate/dev_manager.c \
|
||||||
|
activate/fs.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ("@HAVE_LIBDL@", "yes")
|
||||||
|
SOURCES +=\
|
||||||
|
locking/external_locking.c \
|
||||||
|
misc/sharedlib.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ("@HAVE_SELINUX@", "yes")
|
||||||
|
SOURCES += misc/selinux.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
LIB_STATIC = liblvm.a
|
||||||
|
|
||||||
|
$(SUBDIRS): $(LIB_STATIC)
|
||||||
|
|
||||||
include ../make.tmpl
|
include ../make.tmpl
|
||||||
|
|
||||||
liblvm.a: $(OBJECTS)
|
|
||||||
$(RM) $@
|
|
||||||
$(AR) r $@ $(OBJECTS)
|
|
||||||
$(RANLIB) $@
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +1,260 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
#include "activate.h"
|
#include "activate.h"
|
||||||
|
#include "memlock.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "log.h"
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
|
#include "lvm-file.h"
|
||||||
#include "lvm-string.h"
|
#include "lvm-string.h"
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
#include "toolcontext.h"
|
#include "toolcontext.h"
|
||||||
#include "dev_manager.h"
|
#include "dev_manager.h"
|
||||||
|
#include "str_list.h"
|
||||||
/* FIXME Temporary */
|
|
||||||
#include "vgcache.h"
|
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <linux/kdev_t.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#define _skip(fmt, args...) log_very_verbose("Skipping: " fmt , ## args)
|
#define _skip(fmt, args...) log_very_verbose("Skipping: " fmt , ## args)
|
||||||
|
|
||||||
|
int lvm1_present(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
char path[PATH_MAX];
|
||||||
|
|
||||||
|
if (lvm_snprintf(path, sizeof(path), "%s/lvm/global", cmd->proc_dir)
|
||||||
|
< 0) {
|
||||||
|
log_error("LVM1 proc global snprintf failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path_exists(path))
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef DEVMAPPER_SUPPORT
|
||||||
|
void set_activation(int act)
|
||||||
|
{
|
||||||
|
static int warned = 0;
|
||||||
|
|
||||||
|
if (warned || !act)
|
||||||
|
return;
|
||||||
|
|
||||||
|
log_error("Compiled without libdevmapper support. "
|
||||||
|
"Can't enable activation.");
|
||||||
|
|
||||||
|
warned = 1;
|
||||||
|
}
|
||||||
|
int activation(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
int library_version(char *version, size_t size)
|
int library_version(char *version, size_t size)
|
||||||
{
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int driver_version(char *version, size_t size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int target_present(const char *target_name)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int lv_info(const struct logical_volume *lv, struct lvinfo *info)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
|
||||||
|
struct lvinfo *info)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int lv_snapshot_percent(struct logical_volume *lv, float *percent)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
|
||||||
|
uint32_t *event_nr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int lvs_in_vg_activated(struct volume_group *vg)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int lvs_in_vg_opened(struct volume_group *vg)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int lv_suspend(struct cmd_context *cmd, const char *lvid_s)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int lv_resume(struct cmd_context *cmd, const char *lvid_s)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
|
||||||
|
int *activate_lv)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int lv_activate(struct cmd_context *cmd, const char *lvid_s)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void activation_exit(void)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* DEVMAPPER_SUPPORT */
|
||||||
|
|
||||||
|
static int _activation = 1;
|
||||||
|
|
||||||
|
void set_activation(int act)
|
||||||
|
{
|
||||||
|
if (act == _activation)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_activation = act;
|
||||||
|
if (_activation)
|
||||||
|
log_verbose("Activation enabled. Device-mapper kernel "
|
||||||
|
"driver will be used.");
|
||||||
|
else
|
||||||
|
log_verbose("Activation disabled. No device-mapper "
|
||||||
|
"interaction will be attempted.");
|
||||||
|
}
|
||||||
|
|
||||||
|
int activation(void)
|
||||||
|
{
|
||||||
|
return _activation;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _passes_activation_filter(struct cmd_context *cmd,
|
||||||
|
struct logical_volume *lv)
|
||||||
|
{
|
||||||
|
struct config_node *cn;
|
||||||
|
struct config_value *cv;
|
||||||
|
char *str;
|
||||||
|
char path[PATH_MAX];
|
||||||
|
|
||||||
|
if (!(cn = find_config_node(cmd->cft->root, "activation/volume_list"))) {
|
||||||
|
/* If no hosts tags defined, activate */
|
||||||
|
if (list_empty(&cmd->tags))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* If any host tag matches any LV or VG tag, activate */
|
||||||
|
if (str_list_match_list(&cmd->tags, &lv->tags) ||
|
||||||
|
str_list_match_list(&cmd->tags, &lv->vg->tags))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Don't activate */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cv = cn->v; cv; cv = cv->next) {
|
||||||
|
if (cv->type != CFG_STRING) {
|
||||||
|
log_error("Ignoring invalid string in config file "
|
||||||
|
"activation/volume_list");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
str = cv->v.str;
|
||||||
|
if (!*str) {
|
||||||
|
log_error("Ignoring empty string in config file "
|
||||||
|
"activation/volume_list");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tag? */
|
||||||
|
if (*str == '@') {
|
||||||
|
str++;
|
||||||
|
if (!*str) {
|
||||||
|
log_error("Ignoring empty tag in config file "
|
||||||
|
"activation/volume_list");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* If any host tag matches any LV or VG tag, activate */
|
||||||
|
if (!strcmp(str, "*")) {
|
||||||
|
if (str_list_match_list(&cmd->tags, &lv->tags)
|
||||||
|
|| str_list_match_list(&cmd->tags,
|
||||||
|
&lv->vg->tags))
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* If supplied tag matches LV or VG tag, activate */
|
||||||
|
if (str_list_match_item(&lv->tags, str) ||
|
||||||
|
str_list_match_item(&lv->vg->tags, str))
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!index(str, '/')) {
|
||||||
|
/* vgname supplied */
|
||||||
|
if (!strcmp(str, lv->vg->name))
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* vgname/lvname */
|
||||||
|
if (lvm_snprintf(path, sizeof(path), "%s/%s", lv->vg->name,
|
||||||
|
lv->name) < 0) {
|
||||||
|
log_error("lvm_snprintf error from %s/%s", lv->vg->name,
|
||||||
|
lv->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(path, str))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int library_version(char *version, size_t size)
|
||||||
|
{
|
||||||
|
if (!activation())
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (!dm_get_library_version(version, size))
|
if (!dm_get_library_version(version, size))
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -35,6 +265,9 @@ int driver_version(char *version, size_t size)
|
|||||||
int r = 0;
|
int r = 0;
|
||||||
struct dm_task *dmt;
|
struct dm_task *dmt;
|
||||||
|
|
||||||
|
if (!activation())
|
||||||
|
return 0;
|
||||||
|
|
||||||
log_very_verbose("Getting driver version");
|
log_very_verbose("Getting driver version");
|
||||||
if (!(dmt = dm_task_create(DM_DEVICE_VERSION))) {
|
if (!(dmt = dm_task_create(DM_DEVICE_VERSION))) {
|
||||||
stack;
|
stack;
|
||||||
@@ -55,42 +288,145 @@ int driver_version(char *version, size_t size)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
int target_present(const char *target_name)
|
||||||
* Returns 1 if info structure populated, else 0 on failure.
|
|
||||||
*/
|
|
||||||
int lv_info(struct logical_volume *lv, struct dm_info *info)
|
|
||||||
{
|
{
|
||||||
int r;
|
int r = 0;
|
||||||
struct dev_manager *dm;
|
struct dm_task *dmt;
|
||||||
|
struct dm_versions *target, *last_target;
|
||||||
|
|
||||||
if (!(dm = dev_manager_create(lv->vg->name))) {
|
if (!activation())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
log_very_verbose("Getting target version for %s", target_name);
|
||||||
|
if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(r = dev_manager_info(dm, lv, info)))
|
if (!dm_task_run(dmt)) {
|
||||||
|
log_debug("Failed to get %s target version", target_name);
|
||||||
|
/* Assume this was because LIST_VERSIONS isn't supported */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
target = dm_task_get_versions(dmt);
|
||||||
|
|
||||||
|
do {
|
||||||
|
last_target = target;
|
||||||
|
|
||||||
|
if (!strcmp(target_name, target->name)) {
|
||||||
|
r = 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
target = (void *) target + target->next;
|
||||||
|
} while (last_target != target);
|
||||||
|
|
||||||
|
out:
|
||||||
|
dm_task_destroy(dmt);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns 1 if info structure populated, else 0 on failure.
|
||||||
|
*/
|
||||||
|
static int _lv_info(const struct logical_volume *lv, int mknodes,
|
||||||
|
struct lvinfo *info)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
struct dev_manager *dm;
|
||||||
|
struct dm_info dminfo;
|
||||||
|
|
||||||
|
if (!activation())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) {
|
||||||
stack;
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(r = dev_manager_info(dm, lv, mknodes, &dminfo)))
|
||||||
|
stack;
|
||||||
|
|
||||||
|
info->exists = dminfo.exists;
|
||||||
|
info->suspended = dminfo.suspended;
|
||||||
|
info->open_count = dminfo.open_count;
|
||||||
|
info->major = dminfo.major;
|
||||||
|
info->minor = dminfo.minor;
|
||||||
|
info->read_only = dminfo.read_only;
|
||||||
|
|
||||||
dev_manager_destroy(dm);
|
dev_manager_destroy(dm);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lv_info(const struct logical_volume *lv, struct lvinfo *info)
|
||||||
|
{
|
||||||
|
return _lv_info(lv, 0, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
|
||||||
|
struct lvinfo *info)
|
||||||
|
{
|
||||||
|
struct logical_volume *lv;
|
||||||
|
|
||||||
|
if (!(lv = lv_from_lvid(cmd, lvid_s)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return _lv_info(lv, 0, info);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns 1 if percent set, else 0 on failure.
|
* Returns 1 if percent set, else 0 on failure.
|
||||||
*/
|
*/
|
||||||
int lv_snapshot_percentage(struct logical_volume *lv, float *percent)
|
int lv_snapshot_percent(struct logical_volume *lv, float *percent)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
struct dev_manager *dm;
|
struct dev_manager *dm;
|
||||||
|
|
||||||
if (!(dm = dev_manager_create(lv->vg->name))) {
|
if (!activation())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(r = dev_manager_get_snapshot_use(dm, lv, percent)))
|
if (!(r = dev_manager_snapshot_percent(dm, lv, percent)))
|
||||||
stack;
|
stack;
|
||||||
|
|
||||||
|
dev_manager_destroy(dm);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME Merge with snapshot_percent */
|
||||||
|
int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
|
||||||
|
uint32_t *event_nr)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
struct dev_manager *dm;
|
||||||
|
struct lvinfo info;
|
||||||
|
|
||||||
|
if (!activation())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!lv_info(lv, &info)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info.exists)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(r = dev_manager_mirror_percent(dm, lv, wait, percent, event_nr)))
|
||||||
|
stack;
|
||||||
|
|
||||||
dev_manager_destroy(dm);
|
dev_manager_destroy(dm);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
@@ -98,7 +434,7 @@ int lv_snapshot_percentage(struct logical_volume *lv, float *percent)
|
|||||||
|
|
||||||
static int _lv_active(struct logical_volume *lv)
|
static int _lv_active(struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
struct dm_info info;
|
struct lvinfo info;
|
||||||
|
|
||||||
if (!lv_info(lv, &info)) {
|
if (!lv_info(lv, &info)) {
|
||||||
stack;
|
stack;
|
||||||
@@ -110,7 +446,7 @@ static int _lv_active(struct logical_volume *lv)
|
|||||||
|
|
||||||
static int _lv_open_count(struct logical_volume *lv)
|
static int _lv_open_count(struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
struct dm_info info;
|
struct lvinfo info;
|
||||||
|
|
||||||
if (!lv_info(lv, &info)) {
|
if (!lv_info(lv, &info)) {
|
||||||
stack;
|
stack;
|
||||||
@@ -121,12 +457,12 @@ static int _lv_open_count(struct logical_volume *lv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME Need to detect and handle an lv rename */
|
/* FIXME Need to detect and handle an lv rename */
|
||||||
static int _lv_activate(struct logical_volume *lv)
|
static int _lv_activate_lv(struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
struct dev_manager *dm;
|
struct dev_manager *dm;
|
||||||
|
|
||||||
if (!(dm = dev_manager_create(lv->vg->name))) {
|
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -143,7 +479,7 @@ static int _lv_deactivate(struct logical_volume *lv)
|
|||||||
int r;
|
int r;
|
||||||
struct dev_manager *dm;
|
struct dev_manager *dm;
|
||||||
|
|
||||||
if (!(dm = dev_manager_create(lv->vg->name))) {
|
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -155,12 +491,12 @@ static int _lv_deactivate(struct logical_volume *lv)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _lv_suspend(struct logical_volume *lv)
|
static int _lv_suspend_lv(struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
struct dev_manager *dm;
|
struct dev_manager *dm;
|
||||||
|
|
||||||
if (!(dm = dev_manager_create(lv->vg->name))) {
|
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -182,6 +518,9 @@ int lvs_in_vg_activated(struct volume_group *vg)
|
|||||||
struct logical_volume *lv;
|
struct logical_volume *lv;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
|
if (!activation())
|
||||||
|
return 0;
|
||||||
|
|
||||||
list_iterate(lvh, &vg->lvs) {
|
list_iterate(lvh, &vg->lvs) {
|
||||||
lv = list_item(lvh, struct lv_list)->lv;
|
lv = list_item(lvh, struct lv_list)->lv;
|
||||||
count += (_lv_active(lv) == 1);
|
count += (_lv_active(lv) == 1);
|
||||||
@@ -196,127 +535,32 @@ int lvs_in_vg_opened(struct volume_group *vg)
|
|||||||
struct logical_volume *lv;
|
struct logical_volume *lv;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
|
if (!activation())
|
||||||
|
return 0;
|
||||||
|
|
||||||
list_iterate(lvh, &vg->lvs) {
|
list_iterate(lvh, &vg->lvs) {
|
||||||
lv = list_item(lvh, struct lv_list)->lv;
|
lv = list_item(lvh, struct lv_list)->lv;
|
||||||
count += (_lv_open_count(lv) == 1);
|
count += (_lv_open_count(lv) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct logical_volume *_lv_from_lvid(struct cmd_context *cmd,
|
static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||||
const char *lvid_s)
|
int error_if_not_suspended)
|
||||||
{
|
|
||||||
struct lv_list *lvl;
|
|
||||||
struct volume_group *vg;
|
|
||||||
union lvid *lvid;
|
|
||||||
|
|
||||||
lvid = (union lvid *) lvid_s;
|
|
||||||
|
|
||||||
log_very_verbose("Finding volume group for uuid %s", lvid_s);
|
|
||||||
if (!(vg = vg_read_by_vgid(cmd, lvid->id[0].uuid))) {
|
|
||||||
log_error("Volume group for uuid not found: %s", lvid_s);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_verbose("Found volume group \"%s\"", vg->name);
|
|
||||||
if (vg->status & EXPORTED_VG) {
|
|
||||||
log_error("Volume group \"%s\" is exported", vg->name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(lvl = find_lv_in_vg_by_lvid(vg, lvid))) {
|
|
||||||
log_very_verbose("Can't find logical volume id %s", lvid_s);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lvl->lv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* These return success if the device is not active */
|
|
||||||
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s)
|
|
||||||
{
|
{
|
||||||
struct logical_volume *lv;
|
struct logical_volume *lv;
|
||||||
struct dm_info info;
|
struct lvinfo info;
|
||||||
|
|
||||||
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
|
if (!activation())
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!(lv = lv_from_lvid(cmd, lvid_s)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (test_mode()) {
|
if (test_mode()) {
|
||||||
_skip("Suspending '%s'.", lv->name);
|
_skip("Suspending '%s'.", lv->name);
|
||||||
return 0;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
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)) {
|
if (!lv_info(lv, &info)) {
|
||||||
@@ -325,7 +569,216 @@ int lv_activate(struct cmd_context *cmd, const char *lvid_s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!info.exists || info.suspended)
|
if (!info.exists || info.suspended)
|
||||||
return _lv_activate(lv);
|
return error_if_not_suspended ? 0 : 1;
|
||||||
|
|
||||||
|
memlock_inc();
|
||||||
|
if (!_lv_suspend_lv(lv)) {
|
||||||
|
memlock_dec();
|
||||||
|
fs_unlock();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns success if the device is not active */
|
||||||
|
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s)
|
||||||
|
{
|
||||||
|
return _lv_suspend(cmd, lvid_s, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lv_suspend(struct cmd_context *cmd, const char *lvid_s)
|
||||||
|
{
|
||||||
|
return _lv_suspend(cmd, lvid_s, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
||||||
|
int error_if_not_active)
|
||||||
|
{
|
||||||
|
struct logical_volume *lv;
|
||||||
|
struct lvinfo info;
|
||||||
|
|
||||||
|
if (!activation())
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!(lv = lv_from_lvid(cmd, lvid_s)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (test_mode()) {
|
||||||
|
_skip("Resuming '%s'.", lv->name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lv_info(lv, &info)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info.exists || !info.suspended)
|
||||||
|
return error_if_not_active ? 0 : 1;
|
||||||
|
|
||||||
|
if (!_lv_activate_lv(lv))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memlock_dec();
|
||||||
|
fs_unlock();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns success if the device is not active */
|
||||||
|
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s)
|
||||||
|
{
|
||||||
|
return _lv_resume(cmd, lvid_s, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lv_resume(struct cmd_context *cmd, const char *lvid_s)
|
||||||
|
{
|
||||||
|
return _lv_resume(cmd, lvid_s, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
|
||||||
|
{
|
||||||
|
struct logical_volume *lv;
|
||||||
|
struct lvinfo info;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!activation())
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!(lv = lv_from_lvid(cmd, lvid_s)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (test_mode()) {
|
||||||
|
_skip("Deactivating '%s'.", lv->name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lv_info(lv, &info)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info.exists)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (info.open_count && (lv->status & VISIBLE_LV)) {
|
||||||
|
log_error("LV %s/%s in use: not removing", lv->vg->name,
|
||||||
|
lv->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memlock_inc();
|
||||||
|
r = _lv_deactivate(lv);
|
||||||
|
memlock_dec();
|
||||||
|
fs_unlock();
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test if LV passes filter */
|
||||||
|
int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
|
||||||
|
int *activate_lv)
|
||||||
|
{
|
||||||
|
struct logical_volume *lv;
|
||||||
|
|
||||||
|
if (!activation())
|
||||||
|
goto activate;
|
||||||
|
|
||||||
|
if (!(lv = lv_from_lvid(cmd, lvid_s)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!_passes_activation_filter(cmd, lv)) {
|
||||||
|
log_verbose("Not activating %s/%s due to config file settings",
|
||||||
|
lv->vg->name, lv->name);
|
||||||
|
*activate_lv = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
activate:
|
||||||
|
*activate_lv = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, int filter)
|
||||||
|
{
|
||||||
|
struct logical_volume *lv;
|
||||||
|
struct lvinfo info;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!activation())
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!(lv = lv_from_lvid(cmd, lvid_s)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (filter && !_passes_activation_filter(cmd, lv)) {
|
||||||
|
log_verbose("Not activating %s/%s due to config file settings",
|
||||||
|
lv->vg->name, lv->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (test_mode()) {
|
||||||
|
_skip("Activating '%s'.", lv->name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lv_info(lv, &info)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.exists && !info.suspended)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
memlock_inc();
|
||||||
|
r = _lv_activate_lv(lv);
|
||||||
|
memlock_dec();
|
||||||
|
fs_unlock();
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Activate LV */
|
||||||
|
int lv_activate(struct cmd_context *cmd, const char *lvid_s)
|
||||||
|
{
|
||||||
|
return _lv_activate(cmd, lvid_s, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Activate LV only if it passes filter */
|
||||||
|
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s)
|
||||||
|
{
|
||||||
|
return _lv_activate(cmd, lvid_s, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||||
|
{
|
||||||
|
struct lvinfo info;
|
||||||
|
int r = 1;
|
||||||
|
|
||||||
|
if (!lv) {
|
||||||
|
r = dev_manager_mknodes();
|
||||||
|
fs_unlock();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_lv_info(lv, 1, &info)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.exists)
|
||||||
|
r = dev_manager_lv_mknodes(lv);
|
||||||
|
else
|
||||||
|
r = dev_manager_lv_rmnodes(lv);
|
||||||
|
|
||||||
|
fs_unlock();
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void activation_exit(void)
|
||||||
|
{
|
||||||
|
dev_manager_exit();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,39 +1,76 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef LVM_ACTIVATE_H
|
#ifndef LVM_ACTIVATE_H
|
||||||
#define LVM_ACTIVATE_H
|
#define LVM_ACTIVATE_H
|
||||||
|
|
||||||
#include <libdevmapper.h>
|
#include "metadata.h"
|
||||||
|
|
||||||
|
#ifdef DEVMAPPER_SUPPORT
|
||||||
|
# include <libdevmapper.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct lvinfo {
|
||||||
|
int exists;
|
||||||
|
int suspended;
|
||||||
|
unsigned int open_count;
|
||||||
|
int major;
|
||||||
|
int minor;
|
||||||
|
int read_only;
|
||||||
|
};
|
||||||
|
|
||||||
|
void set_activation(int activation);
|
||||||
|
int activation(void);
|
||||||
|
|
||||||
int driver_version(char *version, size_t size);
|
int driver_version(char *version, size_t size);
|
||||||
int library_version(char *version, size_t size);
|
int library_version(char *version, size_t size);
|
||||||
|
int lvm1_present(struct cmd_context *cmd);
|
||||||
|
|
||||||
|
int target_present(const char *target_name);
|
||||||
|
|
||||||
|
void activation_exit(void);
|
||||||
|
|
||||||
|
int lv_suspend(struct cmd_context *cmd, const char *lvid_s);
|
||||||
|
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s);
|
||||||
|
int lv_resume(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_activate_with_filter(struct cmd_context *cmd, const char *lvid_s);
|
||||||
|
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s);
|
||||||
|
|
||||||
|
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns 1 if info structure has been populated, else 0.
|
* Returns 1 if info structure has been populated, else 0.
|
||||||
*/
|
*/
|
||||||
int lv_info(struct logical_volume *lv, struct dm_info *info);
|
int lv_info(const struct logical_volume *lv, struct lvinfo *info);
|
||||||
|
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
|
||||||
|
struct lvinfo *info);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns 1 if activate_lv has been set: 1 = activate; 0 = don't.
|
||||||
|
*/
|
||||||
|
int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
|
||||||
|
int *activate_lv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns 1 if percent has been set, else 0.
|
* Returns 1 if percent has been set, else 0.
|
||||||
*/
|
*/
|
||||||
int lv_snapshot_percentage(struct logical_volume *lv, float *percent);
|
int lv_snapshot_percent(struct logical_volume *lv, float *percent);
|
||||||
|
int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
|
||||||
/*
|
uint32_t *event_nr);
|
||||||
* 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.
|
* Return number of LVs in the VG that are active.
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,34 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2002 Sistina Software (UK) Limited.
|
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_DEV_MANAGER_H
|
#ifndef _LVM_DEV_MANAGER_H
|
||||||
#define _LVM_DEV_MANAGER_H
|
#define _LVM_DEV_MANAGER_H
|
||||||
|
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
|
#include "config.h"
|
||||||
#include <libdevmapper.h>
|
|
||||||
|
|
||||||
struct dev_manager;
|
struct dev_manager;
|
||||||
|
struct dm_info;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Constructor and destructor.
|
* Constructor and destructor.
|
||||||
*/
|
*/
|
||||||
struct dev_manager *dev_manager_create(const char *vg_name);
|
struct dev_manager *dev_manager_create(const char *vg_name,
|
||||||
|
struct config_tree *cf);
|
||||||
void dev_manager_destroy(struct dev_manager *dm);
|
void dev_manager_destroy(struct dev_manager *dm);
|
||||||
|
void dev_manager_exit(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The device handler is responsible for creating all the layered
|
* The device handler is responsible for creating all the layered
|
||||||
@@ -25,14 +36,20 @@ void dev_manager_destroy(struct dev_manager *dm);
|
|||||||
* (eg, an origin is created before its snapshot, but is not
|
* (eg, an origin is created before its snapshot, but is not
|
||||||
* unsuspended until the snapshot is also created.)
|
* unsuspended until the snapshot is also created.)
|
||||||
*/
|
*/
|
||||||
int dev_manager_info(struct dev_manager *dm, struct logical_volume *lv,
|
int dev_manager_info(struct dev_manager *dm, const struct logical_volume *lv,
|
||||||
struct dm_info *info);
|
int mknodes, struct dm_info *info);
|
||||||
int dev_manager_get_snapshot_use(struct dev_manager *dm,
|
int dev_manager_snapshot_percent(struct dev_manager *dm,
|
||||||
struct logical_volume *lv, float *percent);
|
struct logical_volume *lv, float *percent);
|
||||||
|
int dev_manager_mirror_percent(struct dev_manager *dm,
|
||||||
|
struct logical_volume *lv, int wait,
|
||||||
|
float *percent, uint32_t *event_nr);
|
||||||
int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv);
|
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_activate(struct dev_manager *dm, struct logical_volume *lv);
|
||||||
int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv);
|
int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv);
|
||||||
|
|
||||||
|
int dev_manager_lv_mknodes(const struct logical_volume *lv);
|
||||||
|
int dev_manager_lv_rmnodes(const struct logical_volume *lv);
|
||||||
|
int dev_manager_mknodes(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Put the desired changes into effect.
|
* Put the desired changes into effect.
|
||||||
|
|||||||
@@ -1,31 +1,42 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "log.h"
|
|
||||||
#include "toolcontext.h"
|
#include "toolcontext.h"
|
||||||
#include "lvm-string.h"
|
#include "lvm-string.h"
|
||||||
#include "lvm-file.h"
|
#include "lvm-file.h"
|
||||||
|
#include "memlock.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_SELINUX
|
||||||
|
# include "selinux.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <dirent.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <libdevmapper.h>
|
#include <libdevmapper.h>
|
||||||
|
|
||||||
static int _mk_dir(struct volume_group *vg)
|
static int _mk_dir(const char *dev_dir, const char *vg_name)
|
||||||
{
|
{
|
||||||
char vg_path[PATH_MAX];
|
char vg_path[PATH_MAX];
|
||||||
|
|
||||||
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
|
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
|
||||||
vg->cmd->dev_dir, vg->name) == -1) {
|
dev_dir, vg_name) == -1) {
|
||||||
log_error("Couldn't construct name of volume "
|
log_error("Couldn't construct name of volume "
|
||||||
"group directory.");
|
"group directory.");
|
||||||
return 0;
|
return 0;
|
||||||
@@ -43,12 +54,12 @@ static int _mk_dir(struct volume_group *vg)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _rm_dir(struct volume_group *vg)
|
static int _rm_dir(const char *dev_dir, const char *vg_name)
|
||||||
{
|
{
|
||||||
char vg_path[PATH_MAX];
|
char vg_path[PATH_MAX];
|
||||||
|
|
||||||
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
|
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
|
||||||
vg->cmd->dev_dir, vg->name) == -1) {
|
dev_dir, vg_name) == -1) {
|
||||||
log_error("Couldn't construct name of volume "
|
log_error("Couldn't construct name of volume "
|
||||||
"group directory.");
|
"group directory.");
|
||||||
return 0;
|
return 0;
|
||||||
@@ -62,32 +73,100 @@ static int _rm_dir(struct volume_group *vg)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _mk_link(struct logical_volume *lv, const char *dev)
|
static void _rm_blks(const char *dir)
|
||||||
{
|
{
|
||||||
char lv_path[PATH_MAX], link_path[PATH_MAX];
|
const char *name;
|
||||||
|
char path[PATH_MAX];
|
||||||
|
struct dirent *dirent;
|
||||||
|
struct stat buf;
|
||||||
|
DIR *d;
|
||||||
|
|
||||||
|
if (!(d = opendir(dir))) {
|
||||||
|
log_sys_error("opendir", dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((dirent = readdir(d))) {
|
||||||
|
name = dirent->d_name;
|
||||||
|
|
||||||
|
if (!strcmp(name, ".") || !strcmp(name, ".."))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (lvm_snprintf(path, sizeof(path), "%s/%s", dir, name) == -1) {
|
||||||
|
log_error("Couldn't create path for %s", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lstat(path, &buf)) {
|
||||||
|
if (!S_ISBLK(buf.st_mode))
|
||||||
|
continue;
|
||||||
|
log_very_verbose("Removing %s", path);
|
||||||
|
if (unlink(path) < 0)
|
||||||
|
log_sys_error("unlink", path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _mk_link(const char *dev_dir, const char *vg_name,
|
||||||
|
const char *lv_name, const char *dev)
|
||||||
|
{
|
||||||
|
char lv_path[PATH_MAX], link_path[PATH_MAX], lvm1_group_path[PATH_MAX];
|
||||||
|
char vg_path[PATH_MAX];
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
|
|
||||||
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
|
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
|
||||||
lv->vg->cmd->dev_dir, lv->vg->name, lv->name) == -1) {
|
dev_dir, vg_name) == -1) {
|
||||||
|
log_error("Couldn't create path for volume group dir %s",
|
||||||
|
vg_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s/%s", vg_path,
|
||||||
|
lv_name) == -1) {
|
||||||
log_error("Couldn't create source pathname for "
|
log_error("Couldn't create source pathname for "
|
||||||
"logical volume link %s", lv->name);
|
"logical volume link %s", lv_name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lvm_snprintf(link_path, sizeof(link_path), "%s/%s",
|
if (lvm_snprintf(link_path, sizeof(link_path), "%s/%s",
|
||||||
dm_dir(), dev) == -1) {
|
dm_dir(), dev) == -1) {
|
||||||
log_error("Couldn't create destination pathname for "
|
log_error("Couldn't create destination pathname for "
|
||||||
"logical volume link for %s", lv->name);
|
"logical volume link for %s", lv_name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lvm_snprintf(lvm1_group_path, sizeof(lvm1_group_path), "%s/group",
|
||||||
|
vg_path) == -1) {
|
||||||
|
log_error("Couldn't create pathname for LVM1 group file for %s",
|
||||||
|
vg_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* To reach this point, the VG must have been locked.
|
||||||
|
* As locking fails if the VG is active under LVM1, it's
|
||||||
|
* now safe to remove any LVM1 devices we find here
|
||||||
|
* (as well as any existing LVM2 symlink). */
|
||||||
|
if (!lstat(lvm1_group_path, &buf)) {
|
||||||
|
if (!S_ISCHR(buf.st_mode)) {
|
||||||
|
log_error("Non-LVM1 character device found at %s",
|
||||||
|
lvm1_group_path);
|
||||||
|
} else {
|
||||||
|
_rm_blks(vg_path);
|
||||||
|
|
||||||
|
log_very_verbose("Removing %s", lvm1_group_path);
|
||||||
|
if (unlink(lvm1_group_path) < 0)
|
||||||
|
log_sys_error("unlink", lvm1_group_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!lstat(lv_path, &buf)) {
|
if (!lstat(lv_path, &buf)) {
|
||||||
if (!S_ISLNK(buf.st_mode)) {
|
if (!S_ISLNK(buf.st_mode) && !S_ISBLK(buf.st_mode)) {
|
||||||
log_error("Symbolic link %s not created: file exists",
|
log_error("Symbolic link %s not created: file exists",
|
||||||
link_path);
|
link_path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_very_verbose("Removing %s", lv_path);
|
||||||
if (unlink(lv_path) < 0) {
|
if (unlink(lv_path) < 0) {
|
||||||
log_sys_error("unlink", lv_path);
|
log_sys_error("unlink", lv_path);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -100,26 +179,36 @@ static int _mk_link(struct logical_volume *lv, const char *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_SELINUX
|
||||||
|
if (!set_selinux_context(lv_path)) {
|
||||||
|
log_sys_error("set_selinux_context", lv_path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _rm_link(struct logical_volume *lv, const char *lv_name)
|
static int _rm_link(const char *dev_dir, const char *vg_name,
|
||||||
|
const char *lv_name)
|
||||||
{
|
{
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
char lv_path[PATH_MAX];
|
char lv_path[PATH_MAX];
|
||||||
|
|
||||||
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
|
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
|
||||||
lv->vg->cmd->dev_dir, lv->vg->name, lv_name) == -1) {
|
dev_dir, vg_name, lv_name) == -1) {
|
||||||
log_error("Couldn't determine link pathname.");
|
log_error("Couldn't determine link pathname.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_very_verbose("Removing link %s", lv_path);
|
|
||||||
if (lstat(lv_path, &buf) || !S_ISLNK(buf.st_mode)) {
|
if (lstat(lv_path, &buf) || !S_ISLNK(buf.st_mode)) {
|
||||||
log_error("%s not symbolic link - not removing", lv_path);
|
if (errno != ENOENT)
|
||||||
|
log_error("%s not symbolic link - not removing",
|
||||||
|
lv_path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_very_verbose("Removing link %s", lv_path);
|
||||||
if (unlink(lv_path) < 0) {
|
if (unlink(lv_path) < 0) {
|
||||||
log_sys_error("unlink", lv_path);
|
log_sys_error("unlink", lv_path);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -128,35 +217,143 @@ static int _rm_link(struct logical_volume *lv, const char *lv_name)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fs_add_lv(struct logical_volume *lv, const char *dev)
|
typedef enum {
|
||||||
|
FS_ADD,
|
||||||
|
FS_DEL,
|
||||||
|
FS_RENAME
|
||||||
|
} fs_op_t;
|
||||||
|
|
||||||
|
static int _do_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
|
||||||
|
const char *lv_name, const char *dev,
|
||||||
|
const char *old_lv_name)
|
||||||
{
|
{
|
||||||
if (!_mk_dir(lv->vg) || !_mk_link(lv, dev)) {
|
switch (type) {
|
||||||
stack;
|
case FS_ADD:
|
||||||
return 0;
|
if (!_mk_dir(dev_dir, vg_name) ||
|
||||||
|
!_mk_link(dev_dir, vg_name, lv_name, dev)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FS_DEL:
|
||||||
|
if (!_rm_link(dev_dir, vg_name, lv_name) ||
|
||||||
|
!_rm_dir(dev_dir, vg_name)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
/* FIXME Use rename() */
|
||||||
|
case FS_RENAME:
|
||||||
|
if (old_lv_name && !_rm_link(dev_dir, vg_name, old_lv_name))
|
||||||
|
stack;
|
||||||
|
|
||||||
|
if (!_mk_link(dev_dir, vg_name, lv_name, dev))
|
||||||
|
stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fs_del_lv(struct logical_volume *lv)
|
static LIST_INIT(_fs_ops);
|
||||||
|
|
||||||
|
struct fs_op_parms {
|
||||||
|
struct list list;
|
||||||
|
fs_op_t type;
|
||||||
|
char *dev_dir;
|
||||||
|
char *vg_name;
|
||||||
|
char *lv_name;
|
||||||
|
char *dev;
|
||||||
|
char *old_lv_name;
|
||||||
|
char names[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
static void _store_str(char **pos, char **ptr, const char *str)
|
||||||
{
|
{
|
||||||
if (!_rm_link(lv, lv->name) || !_rm_dir(lv->vg)) {
|
strcpy(*pos, str);
|
||||||
stack;
|
*ptr = *pos;
|
||||||
|
*pos += strlen(*ptr) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _stack_fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
|
||||||
|
const char *lv_name, const char *dev,
|
||||||
|
const char *old_lv_name)
|
||||||
|
{
|
||||||
|
struct fs_op_parms *fsp;
|
||||||
|
size_t len = strlen(dev_dir) + strlen(vg_name) + strlen(lv_name) +
|
||||||
|
strlen(dev) + strlen(old_lv_name) + 5;
|
||||||
|
char *pos;
|
||||||
|
|
||||||
|
if (!(fsp = dbg_malloc(sizeof(*fsp) + len))) {
|
||||||
|
log_error("No space to stack fs operation");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pos = fsp->names;
|
||||||
|
fsp->type = type;
|
||||||
|
|
||||||
|
_store_str(&pos, &fsp->dev_dir, dev_dir);
|
||||||
|
_store_str(&pos, &fsp->vg_name, vg_name);
|
||||||
|
_store_str(&pos, &fsp->lv_name, lv_name);
|
||||||
|
_store_str(&pos, &fsp->dev, dev);
|
||||||
|
_store_str(&pos, &fsp->old_lv_name, old_lv_name);
|
||||||
|
|
||||||
|
list_add(&_fs_ops, &fsp->list);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME Use rename() */
|
static void _pop_fs_ops(void)
|
||||||
|
{
|
||||||
|
struct list *fsph, *fspht;
|
||||||
|
struct fs_op_parms *fsp;
|
||||||
|
|
||||||
|
list_iterate_safe(fsph, fspht, &_fs_ops) {
|
||||||
|
fsp = list_item(fsph, struct fs_op_parms);
|
||||||
|
_do_fs_op(fsp->type, fsp->dev_dir, fsp->vg_name, fsp->lv_name,
|
||||||
|
fsp->dev, fsp->old_lv_name);
|
||||||
|
list_del(&fsp->list);
|
||||||
|
dbg_free(fsp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _fs_op(fs_op_t type, const char *dev_dir, const char *vg_name,
|
||||||
|
const char *lv_name, const char *dev, const char *old_lv_name)
|
||||||
|
{
|
||||||
|
if (memlock()) {
|
||||||
|
if (!_stack_fs_op(type, dev_dir, vg_name, lv_name, dev,
|
||||||
|
old_lv_name)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _do_fs_op(type, dev_dir, vg_name, lv_name, dev, old_lv_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_add_lv(const struct logical_volume *lv, const char *dev)
|
||||||
|
{
|
||||||
|
return _fs_op(FS_ADD, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
|
||||||
|
dev, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_del_lv(const struct logical_volume *lv)
|
||||||
|
{
|
||||||
|
return _fs_op(FS_DEL, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
|
||||||
|
"", "");
|
||||||
|
}
|
||||||
|
|
||||||
int fs_rename_lv(struct logical_volume *lv,
|
int fs_rename_lv(struct logical_volume *lv,
|
||||||
const char *dev, const char *old_name)
|
const char *dev, const char *old_name)
|
||||||
{
|
{
|
||||||
if (old_name && !_rm_link(lv, old_name))
|
return _fs_op(FS_RENAME, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
|
||||||
stack;
|
dev, old_name);
|
||||||
|
}
|
||||||
if (!_mk_link(lv, dev))
|
|
||||||
stack;
|
void fs_unlock(void)
|
||||||
|
{
|
||||||
return 1;
|
if (!memlock()) {
|
||||||
|
dm_lib_release();
|
||||||
|
_pop_fs_ops();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_FS_H
|
#ifndef _LVM_FS_H
|
||||||
@@ -14,10 +23,10 @@
|
|||||||
* up the volume group directory in /dev and the
|
* up the volume group directory in /dev and the
|
||||||
* symbolic links to the dm device.
|
* symbolic links to the dm device.
|
||||||
*/
|
*/
|
||||||
int fs_add_lv(struct logical_volume *lv, const char *dev);
|
int fs_add_lv(const struct logical_volume *lv, const char *dev);
|
||||||
int fs_del_lv(struct logical_volume *lv);
|
int fs_del_lv(const struct logical_volume *lv);
|
||||||
int fs_rename_lv(struct logical_volume *lv,
|
int fs_rename_lv(struct logical_volume *lv,
|
||||||
const char *dev, const char *old_name);
|
const char *dev, const char *old_name);
|
||||||
|
void fs_unlock(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
581
lib/cache/lvmcache.c
vendored
Normal file
581
lib/cache/lvmcache.c
vendored
Normal file
@@ -0,0 +1,581 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
|
#include "lvmcache.h"
|
||||||
|
#include "hash.h"
|
||||||
|
#include "toolcontext.h"
|
||||||
|
#include "dev-cache.h"
|
||||||
|
#include "metadata.h"
|
||||||
|
#include "filter.h"
|
||||||
|
#include "memlock.h"
|
||||||
|
#include "str_list.h"
|
||||||
|
|
||||||
|
static struct hash_table *_pvid_hash = NULL;
|
||||||
|
static struct hash_table *_vgid_hash = NULL;
|
||||||
|
static struct hash_table *_vgname_hash = NULL;
|
||||||
|
static struct hash_table *_lock_hash = NULL;
|
||||||
|
static struct list _vginfos;
|
||||||
|
static int _has_scanned = 0;
|
||||||
|
static int _vgs_locked = 0;
|
||||||
|
|
||||||
|
int lvmcache_init(void)
|
||||||
|
{
|
||||||
|
list_init(&_vginfos);
|
||||||
|
|
||||||
|
if (!(_vgname_hash = hash_create(128)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!(_vgid_hash = hash_create(128)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!(_pvid_hash = hash_create(128)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!(_lock_hash = hash_create(128)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lvmcache_lock_vgname(const char *vgname, int read_only)
|
||||||
|
{
|
||||||
|
if (!_lock_hash && !lvmcache_init()) {
|
||||||
|
log_error("Internal cache initialisation failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hash_insert(_lock_hash, vgname, (void *) 1))
|
||||||
|
log_error("Cache locking failure for %s", vgname);
|
||||||
|
|
||||||
|
_vgs_locked++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _vgname_is_locked(const char *vgname) __attribute__ ((unused));
|
||||||
|
static int _vgname_is_locked(const char *vgname)
|
||||||
|
{
|
||||||
|
if (!_lock_hash)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return hash_lookup(_lock_hash, vgname) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lvmcache_unlock_vgname(const char *vgname)
|
||||||
|
{
|
||||||
|
/* FIXME: Clear all CACHE_LOCKED flags in this vg */
|
||||||
|
hash_remove(_lock_hash, vgname);
|
||||||
|
|
||||||
|
/* FIXME Do this per-VG */
|
||||||
|
if (!--_vgs_locked)
|
||||||
|
dev_close_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
int vgs_locked(void)
|
||||||
|
{
|
||||||
|
return _vgs_locked;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname)
|
||||||
|
{
|
||||||
|
struct lvmcache_vginfo *vginfo;
|
||||||
|
|
||||||
|
if (!_vgname_hash)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!(vginfo = hash_lookup(_vgname_hash, vgname)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return vginfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct format_type *fmt_from_vgname(const char *vgname)
|
||||||
|
{
|
||||||
|
struct lvmcache_vginfo *vginfo;
|
||||||
|
|
||||||
|
if (!(vginfo = vginfo_from_vgname(vgname)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return vginfo->fmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid)
|
||||||
|
{
|
||||||
|
struct lvmcache_vginfo *vginfo;
|
||||||
|
char id[ID_LEN + 1];
|
||||||
|
|
||||||
|
if (!_vgid_hash || !vgid)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* vgid not necessarily NULL-terminated */
|
||||||
|
strncpy(&id[0], vgid, ID_LEN);
|
||||||
|
id[ID_LEN] = '\0';
|
||||||
|
|
||||||
|
if (!(vginfo = hash_lookup(_vgid_hash, id)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return vginfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lvmcache_info *info_from_pvid(const char *pvid)
|
||||||
|
{
|
||||||
|
struct lvmcache_info *info;
|
||||||
|
char id[ID_LEN + 1];
|
||||||
|
|
||||||
|
if (!_pvid_hash || !pvid)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
strncpy(&id[0], pvid, ID_LEN);
|
||||||
|
id[ID_LEN] = '\0';
|
||||||
|
|
||||||
|
if (!(info = hash_lookup(_pvid_hash, id)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _rescan_entry(struct lvmcache_info *info)
|
||||||
|
{
|
||||||
|
struct label *label;
|
||||||
|
|
||||||
|
if (info->status & CACHE_INVALID)
|
||||||
|
label_read(info->dev, &label);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _scan_invalid(void)
|
||||||
|
{
|
||||||
|
hash_iter(_pvid_hash, (iterate_fn) _rescan_entry);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
|
||||||
|
{
|
||||||
|
struct label *label;
|
||||||
|
struct dev_iter *iter;
|
||||||
|
struct device *dev;
|
||||||
|
struct list *fmth;
|
||||||
|
struct format_type *fmt;
|
||||||
|
|
||||||
|
static int _scanning_in_progress = 0;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
/* Avoid recursion when a PVID can't be found! */
|
||||||
|
if (_scanning_in_progress)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
_scanning_in_progress = 1;
|
||||||
|
|
||||||
|
if (!_vgname_hash && !lvmcache_init()) {
|
||||||
|
log_error("Internal cache initialisation failed");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_has_scanned && !full_scan) {
|
||||||
|
r = _scan_invalid();
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(iter = dev_iter_create(cmd->filter))) {
|
||||||
|
log_error("dev_iter creation failed");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((dev = dev_iter_get(iter)))
|
||||||
|
label_read(dev, &label);
|
||||||
|
|
||||||
|
dev_iter_destroy(iter);
|
||||||
|
|
||||||
|
_has_scanned = 1;
|
||||||
|
|
||||||
|
/* Perform any format-specific scanning e.g. text files */
|
||||||
|
list_iterate(fmth, &cmd->formats) {
|
||||||
|
fmt = list_item(fmth, struct format_type);
|
||||||
|
if (fmt->ops->scan && !fmt->ops->scan(fmt))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = 1;
|
||||||
|
|
||||||
|
out:
|
||||||
|
_scanning_in_progress = 0;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan)
|
||||||
|
{
|
||||||
|
struct list *vgnames;
|
||||||
|
struct lvmcache_vginfo *vgi;
|
||||||
|
|
||||||
|
lvmcache_label_scan(cmd, full_scan);
|
||||||
|
|
||||||
|
if (!(vgnames = str_list_create(cmd->mem))) {
|
||||||
|
log_error("vgnames list allocation failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_iterate_items(vgi, &_vginfos) {
|
||||||
|
if (!str_list_add(cmd->mem, vgnames,
|
||||||
|
pool_strdup(cmd->mem, vgi->vgname))) {
|
||||||
|
log_error("strlist allocation failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vgnames;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
|
||||||
|
{
|
||||||
|
struct label *label;
|
||||||
|
struct lvmcache_info *info;
|
||||||
|
|
||||||
|
/* Already cached ? */
|
||||||
|
if ((info = info_from_pvid((char *) pvid))) {
|
||||||
|
if (label_read(info->dev, &label)) {
|
||||||
|
info = (struct lvmcache_info *) label->info;
|
||||||
|
if (id_equal(pvid, (struct id *) &info->dev->pvid))
|
||||||
|
return info->dev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lvmcache_label_scan(cmd, 0);
|
||||||
|
|
||||||
|
/* Try again */
|
||||||
|
if ((info = info_from_pvid((char *) pvid))) {
|
||||||
|
if (label_read(info->dev, &label)) {
|
||||||
|
info = (struct lvmcache_info *) label->info;
|
||||||
|
if (id_equal(pvid, (struct id *) &info->dev->pvid))
|
||||||
|
return info->dev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memlock())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
lvmcache_label_scan(cmd, 1);
|
||||||
|
|
||||||
|
/* Try again */
|
||||||
|
if ((info = info_from_pvid((char *) pvid))) {
|
||||||
|
if (label_read(info->dev, &label)) {
|
||||||
|
info = (struct lvmcache_info *) label->info;
|
||||||
|
if (id_equal(pvid, (struct id *) &info->dev->pvid))
|
||||||
|
return info->dev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _drop_vginfo(struct lvmcache_info *info)
|
||||||
|
{
|
||||||
|
if (!list_empty(&info->list)) {
|
||||||
|
list_del(&info->list);
|
||||||
|
list_init(&info->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->vginfo && list_empty(&info->vginfo->infos)) {
|
||||||
|
hash_remove(_vgname_hash, info->vginfo->vgname);
|
||||||
|
if (info->vginfo->vgname)
|
||||||
|
dbg_free(info->vginfo->vgname);
|
||||||
|
if (*info->vginfo->vgid)
|
||||||
|
hash_remove(_vgid_hash, info->vginfo->vgid);
|
||||||
|
list_del(&info->vginfo->list);
|
||||||
|
dbg_free(info->vginfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
info->vginfo = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unused
|
||||||
|
void lvmcache_del(struct lvmcache_info *info)
|
||||||
|
{
|
||||||
|
if (info->dev->pvid[0] && _pvid_hash)
|
||||||
|
hash_remove(_pvid_hash, info->dev->pvid);
|
||||||
|
|
||||||
|
_drop_vginfo(info);
|
||||||
|
|
||||||
|
info->label->labeller->ops->destroy_label(info->label->labeller,
|
||||||
|
info->label);
|
||||||
|
dbg_free(info);
|
||||||
|
|
||||||
|
return;
|
||||||
|
} */
|
||||||
|
|
||||||
|
static int _lvmcache_update_pvid(struct lvmcache_info *info, const char *pvid)
|
||||||
|
{
|
||||||
|
if (!strcmp(info->dev->pvid, pvid))
|
||||||
|
return 1;
|
||||||
|
if (*info->dev->pvid) {
|
||||||
|
hash_remove(_pvid_hash, info->dev->pvid);
|
||||||
|
}
|
||||||
|
strncpy(info->dev->pvid, pvid, sizeof(info->dev->pvid));
|
||||||
|
if (!hash_insert(_pvid_hash, pvid, info)) {
|
||||||
|
log_error("_lvmcache_update: pvid insertion failed: %s", pvid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _lvmcache_update_vgid(struct lvmcache_info *info, const char *vgid)
|
||||||
|
{
|
||||||
|
if (!vgid || !info->vginfo || !strncmp(info->vginfo->vgid, vgid,
|
||||||
|
sizeof(info->vginfo->vgid)))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (info->vginfo && *info->vginfo->vgid)
|
||||||
|
hash_remove(_vgid_hash, info->vginfo->vgid);
|
||||||
|
if (!vgid)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
strncpy(info->vginfo->vgid, vgid, sizeof(info->vginfo->vgid));
|
||||||
|
info->vginfo->vgid[sizeof(info->vginfo->vgid) - 1] = '\0';
|
||||||
|
if (!hash_insert(_vgid_hash, info->vginfo->vgid, info->vginfo)) {
|
||||||
|
log_error("_lvmcache_update: vgid hash insertion failed: %s",
|
||||||
|
info->vginfo->vgid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
|
||||||
|
{
|
||||||
|
struct lvmcache_vginfo *vginfo;
|
||||||
|
|
||||||
|
/* If vgname is NULL and we don't already have a vgname,
|
||||||
|
* assume ORPHAN - we want every entry to have a vginfo
|
||||||
|
* attached for scanning reasons.
|
||||||
|
*/
|
||||||
|
if (!vgname && !info->vginfo)
|
||||||
|
vgname = ORPHAN;
|
||||||
|
|
||||||
|
if (!vgname || (info->vginfo && !strcmp(info->vginfo->vgname, vgname)))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Remove existing vginfo entry */
|
||||||
|
_drop_vginfo(info);
|
||||||
|
|
||||||
|
/* Get existing vginfo or create new one */
|
||||||
|
if (!(vginfo = vginfo_from_vgname(vgname))) {
|
||||||
|
if (!(vginfo = dbg_malloc(sizeof(*vginfo)))) {
|
||||||
|
log_error("lvmcache_update_vgname: list alloc failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memset(vginfo, 0, sizeof(*vginfo));
|
||||||
|
if (!(vginfo->vgname = dbg_strdup(vgname))) {
|
||||||
|
dbg_free(vginfo);
|
||||||
|
log_error("cache vgname alloc failed for %s", vgname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
list_init(&vginfo->infos);
|
||||||
|
if (!hash_insert(_vgname_hash, vginfo->vgname, vginfo)) {
|
||||||
|
log_error("cache_update: vg hash insertion failed: %s",
|
||||||
|
vginfo->vgname);
|
||||||
|
dbg_free(vginfo->vgname);
|
||||||
|
dbg_free(vginfo);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Ensure orphans appear last on list_iterate */
|
||||||
|
if (!*vgname)
|
||||||
|
list_add(&_vginfos, &vginfo->list);
|
||||||
|
else
|
||||||
|
list_add_h(&_vginfos, &vginfo->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
info->vginfo = vginfo;
|
||||||
|
list_add(&vginfo->infos, &info->list);
|
||||||
|
|
||||||
|
/* FIXME Check consistency of list! */
|
||||||
|
vginfo->fmt = info->fmt;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lvmcache_update_vg(struct volume_group *vg)
|
||||||
|
{
|
||||||
|
struct list *pvh;
|
||||||
|
struct physical_volume *pv;
|
||||||
|
struct lvmcache_info *info;
|
||||||
|
char pvid_s[ID_LEN + 1];
|
||||||
|
int vgid_updated = 0;
|
||||||
|
|
||||||
|
pvid_s[sizeof(pvid_s) - 1] = '\0';
|
||||||
|
|
||||||
|
list_iterate(pvh, &vg->pvs) {
|
||||||
|
pv = list_item(pvh, struct pv_list)->pv;
|
||||||
|
strncpy(pvid_s, (char *) &pv->id, sizeof(pvid_s) - 1);
|
||||||
|
/* FIXME Could pv->dev->pvid ever be different? */
|
||||||
|
if ((info = info_from_pvid(pvid_s))) {
|
||||||
|
lvmcache_update_vgname(info, vg->name);
|
||||||
|
if (!vgid_updated) {
|
||||||
|
_lvmcache_update_vgid(info, (char *) &vg->id);
|
||||||
|
vgid_updated = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||||
|
struct device *dev,
|
||||||
|
const char *vgname, const char *vgid)
|
||||||
|
{
|
||||||
|
struct label *label;
|
||||||
|
struct lvmcache_info *existing, *info;
|
||||||
|
char pvid_s[ID_LEN + 1];
|
||||||
|
|
||||||
|
if (!_vgname_hash && !lvmcache_init()) {
|
||||||
|
log_error("Internal cache initialisation failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(pvid_s, pvid, sizeof(pvid_s));
|
||||||
|
pvid_s[sizeof(pvid_s) - 1] = '\0';
|
||||||
|
|
||||||
|
if (!(existing = info_from_pvid(pvid_s)) &&
|
||||||
|
!(existing = info_from_pvid(dev->pvid))) {
|
||||||
|
if (!(label = label_create(labeller))) {
|
||||||
|
stack;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!(info = dbg_malloc(sizeof(*info)))) {
|
||||||
|
log_error("lvmcache_info allocation failed");
|
||||||
|
label_destroy(label);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(info, 0, sizeof(*info));
|
||||||
|
|
||||||
|
label->info = info;
|
||||||
|
info->label = label;
|
||||||
|
list_init(&info->list);
|
||||||
|
info->dev = dev;
|
||||||
|
} else {
|
||||||
|
if (existing->dev != dev) {
|
||||||
|
/* Is the existing entry a duplicate pvid e.g. md ? */
|
||||||
|
if (MAJOR(existing->dev->dev) == md_major() &&
|
||||||
|
MAJOR(dev->dev) != md_major()) {
|
||||||
|
log_very_verbose("Ignoring duplicate PV %s on "
|
||||||
|
"%s - using md %s",
|
||||||
|
pvid, dev_name(dev),
|
||||||
|
dev_name(existing->dev));
|
||||||
|
return NULL;
|
||||||
|
} else if (MAJOR(existing->dev->dev) != md_major() &&
|
||||||
|
MAJOR(dev->dev) == md_major())
|
||||||
|
log_very_verbose("Duplicate PV %s on %s - "
|
||||||
|
"using md %s", pvid,
|
||||||
|
dev_name(existing->dev),
|
||||||
|
dev_name(dev));
|
||||||
|
else
|
||||||
|
log_error("Found duplicate PV %s: using %s not "
|
||||||
|
"%s", pvid, dev_name(dev),
|
||||||
|
dev_name(existing->dev));
|
||||||
|
}
|
||||||
|
info = existing;
|
||||||
|
/* Has labeller changed? */
|
||||||
|
if (info->label->labeller != labeller) {
|
||||||
|
label_destroy(info->label);
|
||||||
|
if (!(info->label = label_create(labeller))) {
|
||||||
|
/* FIXME leaves info without label! */
|
||||||
|
stack;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
info->label->info = info;
|
||||||
|
}
|
||||||
|
label = info->label;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->fmt = (const struct format_type *) labeller->private;
|
||||||
|
info->status |= CACHE_INVALID;
|
||||||
|
|
||||||
|
if (!_lvmcache_update_pvid(info, pvid_s)) {
|
||||||
|
if (!existing) {
|
||||||
|
dbg_free(info);
|
||||||
|
label_destroy(label);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lvmcache_update_vgname(info, vgname)) {
|
||||||
|
if (!existing) {
|
||||||
|
hash_remove(_pvid_hash, pvid_s);
|
||||||
|
strcpy(info->dev->pvid, "");
|
||||||
|
dbg_free(info);
|
||||||
|
label_destroy(label);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_lvmcache_update_vgid(info, vgid))
|
||||||
|
/* Non-critical */
|
||||||
|
stack;
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _lvmcache_destroy_entry(struct lvmcache_info *info)
|
||||||
|
{
|
||||||
|
if (!list_empty(&info->list))
|
||||||
|
list_del(&info->list);
|
||||||
|
strcpy(info->dev->pvid, "");
|
||||||
|
label_destroy(info->label);
|
||||||
|
dbg_free(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _lvmcache_destroy_vgnamelist(struct lvmcache_vginfo *vginfo)
|
||||||
|
{
|
||||||
|
if (vginfo->vgname)
|
||||||
|
dbg_free(vginfo->vgname);
|
||||||
|
dbg_free(vginfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _lvmcache_destroy_lockname(int present)
|
||||||
|
{
|
||||||
|
/* Nothing to do */
|
||||||
|
}
|
||||||
|
|
||||||
|
void lvmcache_destroy(void)
|
||||||
|
{
|
||||||
|
_has_scanned = 0;
|
||||||
|
|
||||||
|
if (_vgid_hash) {
|
||||||
|
hash_destroy(_vgid_hash);
|
||||||
|
_vgid_hash = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_pvid_hash) {
|
||||||
|
hash_iter(_pvid_hash, (iterate_fn) _lvmcache_destroy_entry);
|
||||||
|
hash_destroy(_pvid_hash);
|
||||||
|
_pvid_hash = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_vgname_hash) {
|
||||||
|
hash_iter(_vgname_hash,
|
||||||
|
(iterate_fn) _lvmcache_destroy_vgnamelist);
|
||||||
|
hash_destroy(_vgname_hash);
|
||||||
|
_vgname_hash = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_lock_hash) {
|
||||||
|
hash_iter(_lock_hash, (iterate_fn) _lvmcache_destroy_lockname);
|
||||||
|
hash_destroy(_lock_hash);
|
||||||
|
_lock_hash = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_init(&_vginfos);
|
||||||
|
}
|
||||||
84
lib/cache/lvmcache.h
vendored
Normal file
84
lib/cache/lvmcache.h
vendored
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LVM_CACHE_H
|
||||||
|
#define _LVM_CACHE_H
|
||||||
|
|
||||||
|
#include "dev-cache.h"
|
||||||
|
#include "uuid.h"
|
||||||
|
#include "label.h"
|
||||||
|
#include "metadata.h"
|
||||||
|
|
||||||
|
#define ORPHAN ""
|
||||||
|
|
||||||
|
#define CACHE_INVALID 0x00000001
|
||||||
|
#define CACHE_LOCKED 0x00000002
|
||||||
|
|
||||||
|
/* LVM specific per-volume info */
|
||||||
|
/* Eventual replacement for struct physical_volume perhaps? */
|
||||||
|
|
||||||
|
struct lvmcache_vginfo {
|
||||||
|
struct list list; /* Join these vginfos together */
|
||||||
|
struct list infos; /* List head for lvmcache_infos */
|
||||||
|
char *vgname; /* "" == orphan */
|
||||||
|
char vgid[ID_LEN + 1];
|
||||||
|
const struct format_type *fmt;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lvmcache_info {
|
||||||
|
struct list list; /* Join VG members together */
|
||||||
|
struct list mdas; /* list head for metadata areas */
|
||||||
|
struct list das; /* list head for data areas */
|
||||||
|
struct lvmcache_vginfo *vginfo; /* NULL == unknown */
|
||||||
|
struct label *label;
|
||||||
|
const struct format_type *fmt;
|
||||||
|
struct device *dev;
|
||||||
|
uint64_t device_size; /* Bytes */
|
||||||
|
uint32_t status;
|
||||||
|
};
|
||||||
|
|
||||||
|
int lvmcache_init(void);
|
||||||
|
void lvmcache_destroy(void);
|
||||||
|
|
||||||
|
/* Set full_scan to 1 to reread every filtered device label */
|
||||||
|
int lvmcache_label_scan(struct cmd_context *cmd, int full_scan);
|
||||||
|
|
||||||
|
/* Add/delete a device */
|
||||||
|
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
|
||||||
|
struct device *dev,
|
||||||
|
const char *vgname, const char *vgid);
|
||||||
|
void lvmcache_del(struct lvmcache_info *info);
|
||||||
|
|
||||||
|
/* Update things */
|
||||||
|
int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname);
|
||||||
|
int lvmcache_update_vg(struct volume_group *vg);
|
||||||
|
|
||||||
|
void lvmcache_lock_vgname(const char *vgname, int read_only);
|
||||||
|
void lvmcache_unlock_vgname(const char *vgname);
|
||||||
|
|
||||||
|
/* Queries */
|
||||||
|
const struct format_type *fmt_from_vgname(const char *vgname);
|
||||||
|
struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname);
|
||||||
|
struct lvmcache_vginfo *vginfo_from_vgid(const char *vgid);
|
||||||
|
struct lvmcache_info *info_from_pvid(const char *pvid);
|
||||||
|
struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid);
|
||||||
|
int vgs_locked(void);
|
||||||
|
|
||||||
|
/* Returns list of struct str_lists containing pool-allocated copy of vgnames */
|
||||||
|
/* Set full_scan to 1 to reread every filtered device label */
|
||||||
|
struct list *lvmcache_get_vgnames(struct cmd_context *cmd, int full_scan);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,16 +1,24 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_ERRORS_H
|
#ifndef _LVM_ERRORS_H
|
||||||
#define _LVM_ERRORS_H
|
#define _LVM_ERRORS_H
|
||||||
|
|
||||||
#define EINVALID_CMD_LINE 1
|
#define ECMD_PROCESSED 1
|
||||||
#define ENO_SUCH_CMD 3
|
#define ENO_SUCH_CMD 2
|
||||||
#define ECMD_PROCESSED 4
|
#define EINVALID_CMD_LINE 3
|
||||||
#define ECMD_FAILED 5
|
#define ECMD_FAILED 5
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
691
lib/commands/toolcontext.c
Normal file
691
lib/commands/toolcontext.c
Normal file
@@ -0,0 +1,691 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
|
#include "toolcontext.h"
|
||||||
|
#include "pool.h"
|
||||||
|
#include "metadata.h"
|
||||||
|
#include "defaults.h"
|
||||||
|
#include "lvm-string.h"
|
||||||
|
#include "activate.h"
|
||||||
|
#include "filter.h"
|
||||||
|
#include "filter-composite.h"
|
||||||
|
#include "filter-persistent.h"
|
||||||
|
#include "filter-regex.h"
|
||||||
|
#include "filter-sysfs.h"
|
||||||
|
#include "label.h"
|
||||||
|
#include "lvm-file.h"
|
||||||
|
#include "format-text.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "memlock.h"
|
||||||
|
#include "str_list.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBDL
|
||||||
|
#include "sharedlib.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LVM1_INTERNAL
|
||||||
|
#include "format1.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <locale.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#ifdef linux
|
||||||
|
# include <malloc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static FILE *_log;
|
||||||
|
|
||||||
|
static int _get_env_vars(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
const char *e;
|
||||||
|
|
||||||
|
/* Set to "" to avoid using any system directory */
|
||||||
|
if ((e = getenv("LVM_SYSTEM_DIR"))) {
|
||||||
|
if (lvm_snprintf(cmd->sys_dir, sizeof(cmd->sys_dir),
|
||||||
|
"%s", e) < 0) {
|
||||||
|
log_error("LVM_SYSTEM_DIR environment variable "
|
||||||
|
"is too long.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _init_logging(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
int append = 1;
|
||||||
|
time_t t;
|
||||||
|
|
||||||
|
const char *log_file;
|
||||||
|
|
||||||
|
/* Syslog */
|
||||||
|
cmd->default_settings.syslog =
|
||||||
|
find_config_int(cmd->cft->root, "log/syslog", DEFAULT_SYSLOG);
|
||||||
|
if (cmd->default_settings.syslog != 1)
|
||||||
|
fin_syslog();
|
||||||
|
|
||||||
|
if (cmd->default_settings.syslog > 1)
|
||||||
|
init_syslog(cmd->default_settings.syslog);
|
||||||
|
|
||||||
|
/* Debug level for log file output */
|
||||||
|
cmd->default_settings.debug =
|
||||||
|
find_config_int(cmd->cft->root, "log/level", DEFAULT_LOGLEVEL);
|
||||||
|
init_debug(cmd->default_settings.debug);
|
||||||
|
|
||||||
|
/* Verbose level for tty output */
|
||||||
|
cmd->default_settings.verbose =
|
||||||
|
find_config_int(cmd->cft->root, "log/verbose", DEFAULT_VERBOSE);
|
||||||
|
init_verbose(cmd->default_settings.verbose + VERBOSE_BASE_LEVEL);
|
||||||
|
|
||||||
|
/* Log message formatting */
|
||||||
|
init_indent(find_config_int(cmd->cft->root, "log/indent",
|
||||||
|
DEFAULT_INDENT));
|
||||||
|
|
||||||
|
cmd->default_settings.msg_prefix = find_config_str(cmd->cft->root,
|
||||||
|
"log/prefix",
|
||||||
|
DEFAULT_MSG_PREFIX);
|
||||||
|
init_msg_prefix(cmd->default_settings.msg_prefix);
|
||||||
|
|
||||||
|
cmd->default_settings.cmd_name = find_config_int(cmd->cft->root,
|
||||||
|
"log/command_names",
|
||||||
|
DEFAULT_CMD_NAME);
|
||||||
|
init_cmd_name(cmd->default_settings.cmd_name);
|
||||||
|
|
||||||
|
/* Test mode */
|
||||||
|
cmd->default_settings.test =
|
||||||
|
find_config_int(cmd->cft->root, "global/test", 0);
|
||||||
|
|
||||||
|
/* Settings for logging to file */
|
||||||
|
if (find_config_int(cmd->cft->root, "log/overwrite",
|
||||||
|
DEFAULT_OVERWRITE))
|
||||||
|
append = 0;
|
||||||
|
|
||||||
|
log_file = find_config_str(cmd->cft->root, "log/file", 0);
|
||||||
|
|
||||||
|
if (log_file) {
|
||||||
|
release_log_memory();
|
||||||
|
fin_log();
|
||||||
|
init_log_file(log_file, append);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_file = find_config_str(cmd->cft->root, "log/activate_file", 0);
|
||||||
|
if (log_file)
|
||||||
|
init_log_direct(log_file, append);
|
||||||
|
|
||||||
|
init_log_while_suspended(find_config_int(cmd->cft->root,
|
||||||
|
"log/activation", 0));
|
||||||
|
|
||||||
|
t = time(NULL);
|
||||||
|
log_verbose("Logging initialised at %s", ctime(&t));
|
||||||
|
|
||||||
|
/* Tell device-mapper about our logging */
|
||||||
|
#ifdef DEVMAPPER_SUPPORT
|
||||||
|
dm_log_init(print_log);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _process_config(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
mode_t old_umask;
|
||||||
|
|
||||||
|
/* umask */
|
||||||
|
cmd->default_settings.umask = find_config_int(cmd->cft->root,
|
||||||
|
"global/umask",
|
||||||
|
DEFAULT_UMASK);
|
||||||
|
|
||||||
|
if ((old_umask = umask((mode_t) cmd->default_settings.umask)) !=
|
||||||
|
(mode_t) cmd->default_settings.umask)
|
||||||
|
log_verbose("Set umask to %04o", cmd->default_settings.umask);
|
||||||
|
|
||||||
|
/* dev dir */
|
||||||
|
if (lvm_snprintf(cmd->dev_dir, sizeof(cmd->dev_dir), "%s/",
|
||||||
|
find_config_str(cmd->cft->root, "devices/dir",
|
||||||
|
DEFAULT_DEV_DIR)) < 0) {
|
||||||
|
log_error("Device directory given in config file too long");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#ifdef DEVMAPPER_SUPPORT
|
||||||
|
dm_set_dev_dir(cmd->dev_dir);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* proc dir */
|
||||||
|
if (lvm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
|
||||||
|
find_config_str(cmd->cft->root, "global/proc",
|
||||||
|
DEFAULT_PROC_DIR)) < 0) {
|
||||||
|
log_error("Device directory given in config file too long");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* activation? */
|
||||||
|
cmd->default_settings.activation = find_config_int(cmd->cft->root,
|
||||||
|
"global/activation",
|
||||||
|
DEFAULT_ACTIVATION);
|
||||||
|
set_activation(cmd->default_settings.activation);
|
||||||
|
|
||||||
|
cmd->default_settings.suffix = find_config_int(cmd->cft->root,
|
||||||
|
"global/suffix",
|
||||||
|
DEFAULT_SUFFIX);
|
||||||
|
|
||||||
|
if (!(cmd->default_settings.unit_factor =
|
||||||
|
units_to_bytes(find_config_str(cmd->cft->root,
|
||||||
|
"global/units",
|
||||||
|
DEFAULT_UNITS),
|
||||||
|
&cmd->default_settings.unit_type))) {
|
||||||
|
log_error("Invalid units specification");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find and read config file */
|
||||||
|
static int _init_config(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
struct stat info;
|
||||||
|
char config_file[PATH_MAX] = "";
|
||||||
|
|
||||||
|
if (!(cmd->cft = create_config_tree())) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No config file if LVM_SYSTEM_DIR is empty */
|
||||||
|
if (!*cmd->sys_dir)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (lvm_snprintf(config_file, sizeof(config_file),
|
||||||
|
"%s/lvm.conf", cmd->sys_dir) < 0) {
|
||||||
|
log_error("LVM_SYSTEM_DIR was too long");
|
||||||
|
destroy_config_tree(cmd->cft);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is there a config file? */
|
||||||
|
if (stat(config_file, &info) == -1) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
return 1;
|
||||||
|
log_sys_error("stat", config_file);
|
||||||
|
destroy_config_tree(cmd->cft);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!read_config_file(cmd->cft, config_file)) {
|
||||||
|
log_error("Failed to load config file %s", config_file);
|
||||||
|
destroy_config_tree(cmd->cft);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _init_dev_cache(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
struct config_node *cn;
|
||||||
|
struct config_value *cv;
|
||||||
|
|
||||||
|
if (!dev_cache_init()) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(cn = find_config_node(cmd->cft->root, "devices/scan"))) {
|
||||||
|
if (!dev_cache_add_dir("/dev")) {
|
||||||
|
log_error("Failed to add /dev to internal "
|
||||||
|
"device cache");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
log_verbose("device/scan not in config file: "
|
||||||
|
"Defaulting to /dev");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cv = cn->v; cv; cv = cv->next) {
|
||||||
|
if (cv->type != CFG_STRING) {
|
||||||
|
log_error("Invalid string in config file: "
|
||||||
|
"devices/scan");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dev_cache_add_dir(cv->v.str)) {
|
||||||
|
log_error("Failed to add %s to internal device cache",
|
||||||
|
cv->v.str);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_FILTERS 3
|
||||||
|
|
||||||
|
static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
unsigned nr_filt = 0;
|
||||||
|
struct config_node *cn;
|
||||||
|
struct dev_filter *filters[MAX_FILTERS];
|
||||||
|
|
||||||
|
memset(filters, 0, sizeof(filters));
|
||||||
|
|
||||||
|
/* sysfs filter */
|
||||||
|
if (find_config_bool(cmd->cft->root, "devices/sysfs_scan",
|
||||||
|
DEFAULT_SYSFS_SCAN)) {
|
||||||
|
if ((filters[nr_filt] = sysfs_filter_create(cmd->proc_dir)))
|
||||||
|
nr_filt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* regex filter */
|
||||||
|
if (!(cn = find_config_node(cmd->cft->root, "devices/filter")))
|
||||||
|
log_debug("devices/filter not found in config file: no regex "
|
||||||
|
"filter installed");
|
||||||
|
|
||||||
|
else if (!(filters[nr_filt++] = regex_filter_create(cn->v))) {
|
||||||
|
log_error("Failed to create regex device filter");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* device type filter */
|
||||||
|
cn = find_config_node(cmd->cft->root, "devices/types");
|
||||||
|
if (!(filters[nr_filt++] = lvm_type_filter_create(cmd->proc_dir, cn))) {
|
||||||
|
log_error("Failed to create lvm type filter");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* only build a composite filter if we really need it */
|
||||||
|
return (nr_filt == 1) ?
|
||||||
|
filters[0] : composite_filter_create(nr_filt, filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _init_filters(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
const char *dev_cache;
|
||||||
|
struct dev_filter *f3, *f4;
|
||||||
|
struct stat st;
|
||||||
|
char cache_file[PATH_MAX];
|
||||||
|
|
||||||
|
cmd->dump_filter = 0;
|
||||||
|
|
||||||
|
if (!(f3 = _init_filter_components(cmd)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (lvm_snprintf(cache_file, sizeof(cache_file),
|
||||||
|
"%s/.cache", cmd->sys_dir) < 0) {
|
||||||
|
log_error("Persistent cache filename too long ('%s/.cache').",
|
||||||
|
cmd->sys_dir);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_cache =
|
||||||
|
find_config_str(cmd->cft->root, "devices/cache", cache_file);
|
||||||
|
if (!(f4 = persistent_filter_create(f3, dev_cache))) {
|
||||||
|
log_error("Failed to create persistent device filter");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Should we ever dump persistent filter state? */
|
||||||
|
if (find_config_int(cmd->cft->root, "devices/write_cache_state", 1))
|
||||||
|
cmd->dump_filter = 1;
|
||||||
|
|
||||||
|
if (!*cmd->sys_dir)
|
||||||
|
cmd->dump_filter = 0;
|
||||||
|
|
||||||
|
if (!stat(dev_cache, &st) &&
|
||||||
|
(st.st_mtime > config_file_timestamp(cmd->cft)) &&
|
||||||
|
!persistent_filter_load(f4))
|
||||||
|
log_verbose("Failed to load existing device cache from %s",
|
||||||
|
dev_cache);
|
||||||
|
|
||||||
|
cmd->filter = f4;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _init_formats(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
const char *format;
|
||||||
|
|
||||||
|
struct format_type *fmt;
|
||||||
|
struct list *fmth;
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBDL
|
||||||
|
struct config_node *cn;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
label_init();
|
||||||
|
|
||||||
|
#ifdef LVM1_INTERNAL
|
||||||
|
if (!(fmt = init_lvm1_format(cmd)))
|
||||||
|
return 0;
|
||||||
|
fmt->library = NULL;
|
||||||
|
list_add(&cmd->formats, &fmt->list);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBDL
|
||||||
|
/* Load any formats in shared libs */
|
||||||
|
if ((cn = find_config_node(cmd->cft->root, "global/format_libraries"))) {
|
||||||
|
|
||||||
|
struct config_value *cv;
|
||||||
|
struct format_type *(*init_format_fn) (struct cmd_context *);
|
||||||
|
void *lib;
|
||||||
|
|
||||||
|
for (cv = cn->v; cv; cv = cv->next) {
|
||||||
|
if (cv->type != CFG_STRING) {
|
||||||
|
log_error("Invalid string in config file: "
|
||||||
|
"global/format_libraries");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!(lib = load_shared_library(cmd->cft, cv->v.str,
|
||||||
|
"format"))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(init_format_fn = dlsym(lib, "init_format"))) {
|
||||||
|
log_error("Shared library %s does not contain "
|
||||||
|
"format functions", cv->v.str);
|
||||||
|
dlclose(lib);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(fmt = init_format_fn(cmd)))
|
||||||
|
return 0;
|
||||||
|
fmt->library = lib;
|
||||||
|
list_add(&cmd->formats, &fmt->list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!(fmt = create_text_format(cmd)))
|
||||||
|
return 0;
|
||||||
|
fmt->library = NULL;
|
||||||
|
list_add(&cmd->formats, &fmt->list);
|
||||||
|
|
||||||
|
cmd->fmt_backup = fmt;
|
||||||
|
|
||||||
|
format = find_config_str(cmd->cft->root, "global/format",
|
||||||
|
DEFAULT_FORMAT);
|
||||||
|
|
||||||
|
list_iterate(fmth, &cmd->formats) {
|
||||||
|
fmt = list_item(fmth, struct format_type);
|
||||||
|
if (!strcasecmp(fmt->name, format) ||
|
||||||
|
(fmt->alias && !strcasecmp(fmt->alias, format))) {
|
||||||
|
cmd->default_settings.fmt = fmt;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error("_init_formats: Default format (%s) not found", format);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _init_hostname(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
struct utsname uts;
|
||||||
|
|
||||||
|
if (uname(&uts)) {
|
||||||
|
log_sys_error("uname", "_init_hostname");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(cmd->hostname = pool_strdup(cmd->libmem, uts.nodename))) {
|
||||||
|
log_error("_init_hostname: pool_strdup failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(cmd->kernel_vsn = pool_strdup(cmd->libmem, uts.release))) {
|
||||||
|
log_error("_init_hostname: pool_strdup kernel_vsn failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _set_tag(struct cmd_context *cmd, const char *tag)
|
||||||
|
{
|
||||||
|
log_very_verbose("Setting host tag: %s", pool_strdup(cmd->libmem, tag));
|
||||||
|
|
||||||
|
if (!str_list_add(cmd->libmem, &cmd->tags, tag)) {
|
||||||
|
log_error("_init_tags: str_list_add %s failed", tag);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _check_host_filters(struct cmd_context *cmd, struct config_node *hn,
|
||||||
|
int *passes)
|
||||||
|
{
|
||||||
|
struct config_node *cn;
|
||||||
|
struct config_value *cv;
|
||||||
|
|
||||||
|
*passes = 1;
|
||||||
|
|
||||||
|
for (cn = hn; cn; cn = cn->sib) {
|
||||||
|
if (!cn->v)
|
||||||
|
continue;
|
||||||
|
if (!strcmp(cn->key, "host_list")) {
|
||||||
|
*passes = 0;
|
||||||
|
if (cn->v->type == CFG_EMPTY_ARRAY)
|
||||||
|
continue;
|
||||||
|
for (cv = cn->v; cv; cv = cv->next) {
|
||||||
|
if (cv->type != CFG_STRING) {
|
||||||
|
log_error("Invalid hostname string "
|
||||||
|
"for tag %s", cn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!strcmp(cv->v.str, cmd->hostname)) {
|
||||||
|
*passes = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!strcmp(cn->key, "host_filter")) {
|
||||||
|
log_error("host_filter not supported yet");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _init_tags(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
struct config_node *tn, *cn;
|
||||||
|
const char *tag;
|
||||||
|
int passes;
|
||||||
|
|
||||||
|
list_init(&cmd->tags);
|
||||||
|
|
||||||
|
if (!(tn = find_config_node(cmd->cft->root, "tags")) ||
|
||||||
|
!tn->child) {
|
||||||
|
log_very_verbose("No tags defined in config file");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (find_config_int(cmd->cft->root, "tags/hosttags",
|
||||||
|
DEFAULT_HOSTTAGS)) {
|
||||||
|
/* FIXME Strip out invalid chars: only A-Za-z0-9_+.- */
|
||||||
|
if (!_set_tag(cmd, cmd->hostname)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cn = tn->child; cn; cn = cn->sib) {
|
||||||
|
if (cn->v)
|
||||||
|
continue;
|
||||||
|
tag = cn->key;
|
||||||
|
if (*tag == '@')
|
||||||
|
tag++;
|
||||||
|
if (!validate_name(tag)) {
|
||||||
|
log_error("Invalid tag in config file: %s", cn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (cn->child) {
|
||||||
|
passes = 0;
|
||||||
|
if (!_check_host_filters(cmd, cn->child, &passes)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!passes)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!_set_tag(cmd, tag)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Entry point */
|
||||||
|
struct cmd_context *create_toolcontext(struct arg *the_args)
|
||||||
|
{
|
||||||
|
struct cmd_context *cmd;
|
||||||
|
|
||||||
|
#ifdef M_MMAP_MAX
|
||||||
|
mallopt(M_MMAP_MAX, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!setlocale(LC_ALL, ""))
|
||||||
|
log_error("setlocale failed");
|
||||||
|
|
||||||
|
#ifdef INTL_PACKAGE
|
||||||
|
bindtextdomain(INTL_PACKAGE, LOCALEDIR);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
init_syslog(DEFAULT_LOG_FACILITY);
|
||||||
|
|
||||||
|
if (!(cmd = dbg_malloc(sizeof(*cmd)))) {
|
||||||
|
log_error("Failed to allocate command context");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(cmd, 0, sizeof(*cmd));
|
||||||
|
cmd->args = the_args;
|
||||||
|
list_init(&cmd->formats);
|
||||||
|
|
||||||
|
strcpy(cmd->sys_dir, DEFAULT_SYS_DIR);
|
||||||
|
|
||||||
|
if (!_get_env_vars(cmd))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Create system directory if it doesn't already exist */
|
||||||
|
if (*cmd->sys_dir && !create_dir(cmd->sys_dir))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!_init_config(cmd))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
_init_logging(cmd);
|
||||||
|
|
||||||
|
if (!(cmd->libmem = pool_create(4 * 1024))) {
|
||||||
|
log_error("Library memory pool creation failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_process_config(cmd))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!_init_dev_cache(cmd))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!_init_filters(cmd))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!(cmd->mem = pool_create(4 * 1024))) {
|
||||||
|
log_error("Command memory pool creation failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memlock_init(cmd);
|
||||||
|
|
||||||
|
if (!_init_formats(cmd))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!_init_hostname(cmd))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!_init_tags(cmd))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
cmd->current_settings = cmd->default_settings;
|
||||||
|
|
||||||
|
return cmd;
|
||||||
|
|
||||||
|
error:
|
||||||
|
dbg_free(cmd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int refresh_toolcontext(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
_init_logging(cmd);
|
||||||
|
_init_tags(cmd);
|
||||||
|
|
||||||
|
/* FIXME Reset filters and dev_cache */
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _destroy_formats(struct list *formats)
|
||||||
|
{
|
||||||
|
struct list *fmtl, *tmp;
|
||||||
|
struct format_type *fmt;
|
||||||
|
void *lib;
|
||||||
|
|
||||||
|
list_iterate_safe(fmtl, tmp, formats) {
|
||||||
|
fmt = list_item(fmtl, struct format_type);
|
||||||
|
list_del(&fmt->list);
|
||||||
|
lib = fmt->library;
|
||||||
|
fmt->ops->destroy(fmt);
|
||||||
|
#ifdef HAVE_LIBDL
|
||||||
|
if (lib)
|
||||||
|
dlclose(lib);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_toolcontext(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
if (cmd->dump_filter)
|
||||||
|
persistent_filter_dump(cmd->filter);
|
||||||
|
|
||||||
|
activation_exit();
|
||||||
|
lvmcache_destroy();
|
||||||
|
label_exit();
|
||||||
|
_destroy_formats(&cmd->formats);
|
||||||
|
cmd->filter->destroy(cmd->filter);
|
||||||
|
pool_destroy(cmd->mem);
|
||||||
|
dev_cache_exit();
|
||||||
|
destroy_config_tree(cmd->cft);
|
||||||
|
pool_destroy(cmd->libmem);
|
||||||
|
dbg_free(cmd);
|
||||||
|
|
||||||
|
release_log_memory();
|
||||||
|
dump_memory();
|
||||||
|
fin_log();
|
||||||
|
fin_syslog();
|
||||||
|
|
||||||
|
if (_log)
|
||||||
|
fclose(_log);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,8 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_TOOLCONTEXT_H
|
#ifndef _LVM_TOOLCONTEXT_H
|
||||||
@@ -13,25 +21,67 @@
|
|||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
|
|
||||||
/* command-instance-related variables needed by library */
|
#include <stdio.h>
|
||||||
struct cmd_context {
|
#include <limits.h>
|
||||||
/* format handler allocates all objects from here */
|
|
||||||
struct pool *mem;
|
|
||||||
|
|
||||||
struct format_type *fmt; /* Current format to use by default */
|
/*
|
||||||
|
* Config options that can be changed while commands are processed
|
||||||
|
*/
|
||||||
|
struct config_info {
|
||||||
|
int debug;
|
||||||
|
int verbose;
|
||||||
|
int test;
|
||||||
|
int syslog;
|
||||||
|
int activation;
|
||||||
|
int suffix;
|
||||||
|
uint64_t unit_factor;
|
||||||
|
char unit_type;
|
||||||
|
const char *msg_prefix;
|
||||||
|
int cmd_name; /* Show command name? */
|
||||||
|
|
||||||
/* FIXME Move into dynamic list */
|
int archive; /* should we archive ? */
|
||||||
struct format_type *fmt1; /* Format1 */
|
int backup; /* should we backup ? */
|
||||||
struct format_type *fmtt; /* Format_text */
|
|
||||||
|
|
||||||
char *cmd_line;
|
struct format_type *fmt;
|
||||||
char *dev_dir;
|
|
||||||
struct dev_filter *filter;
|
|
||||||
struct config_file *cf;
|
|
||||||
|
|
||||||
struct command *command;
|
mode_t umask;
|
||||||
struct uuid_map *um;
|
|
||||||
struct arg *args;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* FIXME Split into tool & library contexts */
|
||||||
|
/* command-instance-related variables needed by library */
|
||||||
|
struct cmd_context {
|
||||||
|
struct pool *libmem; /* For permanent config data */
|
||||||
|
struct pool *mem; /* Transient: Cleared between each command */
|
||||||
|
|
||||||
|
const struct format_type *fmt; /* Current format to use by default */
|
||||||
|
struct format_type *fmt_backup; /* Format to use for backups */
|
||||||
|
|
||||||
|
struct list formats; /* Available formats */
|
||||||
|
const char *hostname;
|
||||||
|
const char *kernel_vsn;
|
||||||
|
|
||||||
|
char *cmd_line;
|
||||||
|
struct command *command;
|
||||||
|
struct arg *args;
|
||||||
|
char **argv;
|
||||||
|
|
||||||
|
struct dev_filter *filter;
|
||||||
|
int dump_filter; /* Dump filter when exiting? */
|
||||||
|
|
||||||
|
struct config_tree *cft;
|
||||||
|
struct config_info default_settings;
|
||||||
|
struct config_info current_settings;
|
||||||
|
|
||||||
|
/* List of defined tags */
|
||||||
|
struct list tags;
|
||||||
|
|
||||||
|
char sys_dir[PATH_MAX];
|
||||||
|
char dev_dir[PATH_MAX];
|
||||||
|
char proc_dir[PATH_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cmd_context *create_toolcontext(struct arg *the_args);
|
||||||
|
void destroy_toolcontext(struct cmd_context *cmd);
|
||||||
|
int refresh_toolcontext(struct cmd_context *cmd);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,21 +1,29 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include "lib.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "crc.h"
|
||||||
|
#include "pool.h"
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "pool.h"
|
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
TOK_INT,
|
TOK_INT,
|
||||||
@@ -32,10 +40,10 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct parser {
|
struct parser {
|
||||||
const char *fb, *fe; /* file limits */
|
char *fb, *fe; /* file limits */
|
||||||
|
|
||||||
int t; /* token limits and type */
|
int t; /* token limits and type */
|
||||||
const char *tb, *te;
|
char *tb, *te;
|
||||||
|
|
||||||
int fd; /* descriptor for file being parsed */
|
int fd; /* descriptor for file being parsed */
|
||||||
int line; /* line number we are on */
|
int line; /* line number we are on */
|
||||||
@@ -44,11 +52,13 @@ struct parser {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct cs {
|
struct cs {
|
||||||
struct config_file cf;
|
struct config_tree cft;
|
||||||
struct pool *mem;
|
struct pool *mem;
|
||||||
|
time_t timestamp;
|
||||||
|
char *filename;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void _get_token(struct parser *p);
|
static void _get_token(struct parser *p, int tok_prev);
|
||||||
static void _eat_space(struct parser *p);
|
static void _eat_space(struct parser *p);
|
||||||
static struct config_node *_file(struct parser *p);
|
static struct config_node *_file(struct parser *p);
|
||||||
static struct config_node *_section(struct parser *p);
|
static struct config_node *_section(struct parser *p);
|
||||||
@@ -59,6 +69,8 @@ static struct config_value *_create_value(struct parser *p);
|
|||||||
static struct config_node *_create_node(struct parser *p);
|
static struct config_node *_create_node(struct parser *p);
|
||||||
static char *_dup_tok(struct parser *p);
|
static char *_dup_tok(struct parser *p);
|
||||||
|
|
||||||
|
static const int sep = '/';
|
||||||
|
|
||||||
#define MAX_INDENT 32
|
#define MAX_INDENT 32
|
||||||
|
|
||||||
#define match(t) do {\
|
#define match(t) do {\
|
||||||
@@ -81,7 +93,7 @@ static int _tok_match(const char *str, const char *b, const char *e)
|
|||||||
/*
|
/*
|
||||||
* public interface
|
* public interface
|
||||||
*/
|
*/
|
||||||
struct config_file *create_config_file(void)
|
struct config_tree *create_config_tree(void)
|
||||||
{
|
{
|
||||||
struct cs *c;
|
struct cs *c;
|
||||||
struct pool *mem = pool_create(10 * 1024);
|
struct pool *mem = pool_create(10 * 1024);
|
||||||
@@ -98,21 +110,26 @@ struct config_file *create_config_file(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
c->mem = mem;
|
c->mem = mem;
|
||||||
c->cf.root = (struct config_node *) NULL;
|
c->cft.root = (struct config_node *) NULL;
|
||||||
return &c->cf;
|
c->timestamp = 0;
|
||||||
|
c->filename = NULL;
|
||||||
|
return &c->cft;
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy_config_file(struct config_file *cf)
|
void destroy_config_tree(struct config_tree *cft)
|
||||||
{
|
{
|
||||||
pool_destroy(((struct cs *) cf)->mem);
|
pool_destroy(((struct cs *) cft)->mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_config(struct config_file *cf, const char *file)
|
int read_config_fd(struct config_tree *cft, struct device *dev,
|
||||||
|
off_t offset, size_t size, off_t offset2, size_t size2,
|
||||||
|
checksum_fn_t checksum_fn, uint32_t checksum)
|
||||||
{
|
{
|
||||||
struct cs *c = (struct cs *) cf;
|
struct cs *c = (struct cs *) cft;
|
||||||
struct parser *p;
|
struct parser *p;
|
||||||
struct stat info;
|
int r = 0;
|
||||||
int r = 1, fd;
|
int use_mmap = 1;
|
||||||
|
off_t mmap_offset = 0;
|
||||||
|
|
||||||
if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
|
if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
|
||||||
stack;
|
stack;
|
||||||
@@ -120,50 +137,195 @@ int read_config(struct config_file *cf, const char *file)
|
|||||||
}
|
}
|
||||||
p->mem = c->mem;
|
p->mem = c->mem;
|
||||||
|
|
||||||
/* memory map the file */
|
/* Only use mmap with regular files */
|
||||||
if (stat(file, &info) || S_ISDIR(info.st_mode)) {
|
if (!(dev->flags & DEV_REGULAR) || size2)
|
||||||
|
use_mmap = 0;
|
||||||
|
|
||||||
|
if (use_mmap) {
|
||||||
|
mmap_offset = offset % getpagesize();
|
||||||
|
/* memory map the file */
|
||||||
|
p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
|
||||||
|
MAP_PRIVATE, dev_fd(dev), offset - mmap_offset);
|
||||||
|
if (p->fb == (caddr_t) (-1)) {
|
||||||
|
log_sys_error("mmap", dev_name(dev));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
p->fb = p->fb + mmap_offset;
|
||||||
|
} else {
|
||||||
|
if (!(p->fb = dbg_malloc(size + size2))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!dev_read(dev, (uint64_t) offset, size, p->fb)) {
|
||||||
|
log_error("Read from %s failed", dev_name(dev));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (size2) {
|
||||||
|
if (!dev_read(dev, (uint64_t) offset2, size2,
|
||||||
|
p->fb + size)) {
|
||||||
|
log_error("Circular read from %s failed",
|
||||||
|
dev_name(dev));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checksum_fn && checksum !=
|
||||||
|
(checksum_fn(checksum_fn(INITIAL_CRC, p->fb, size),
|
||||||
|
p->fb + size, size2))) {
|
||||||
|
log_error("%s: Checksum error", dev_name(dev));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->fe = p->fb + size + size2;
|
||||||
|
|
||||||
|
/* parse */
|
||||||
|
p->tb = p->te = p->fb;
|
||||||
|
p->line = 1;
|
||||||
|
_get_token(p, TOK_SECTION_E);
|
||||||
|
if (!(cft->root = _file(p))) {
|
||||||
|
stack;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = 1;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (!use_mmap)
|
||||||
|
dbg_free(p->fb);
|
||||||
|
else {
|
||||||
|
/* unmap the file */
|
||||||
|
if (munmap((char *) (p->fb - mmap_offset), size + mmap_offset)) {
|
||||||
|
log_sys_error("munmap", dev_name(dev));
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_config_file(struct config_tree *cft, const char *file)
|
||||||
|
{
|
||||||
|
struct cs *c = (struct cs *) cft;
|
||||||
|
struct stat info;
|
||||||
|
struct device *dev;
|
||||||
|
int r = 1;
|
||||||
|
|
||||||
|
if (stat(file, &info)) {
|
||||||
log_sys_error("stat", file);
|
log_sys_error("stat", file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!S_ISREG(info.st_mode)) {
|
||||||
|
log_error("%s is not a regular file", file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (info.st_size == 0) {
|
if (info.st_size == 0) {
|
||||||
log_verbose("%s is empty", file);
|
log_verbose("%s is empty", file);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fd = open(file, O_RDONLY)) < 0) {
|
if (!(dev = dev_create_file(file, NULL, NULL))) {
|
||||||
log_sys_error("open", file);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
p->fb = mmap((caddr_t) 0, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
|
||||||
if (p->fb == (caddr_t) (-1)) {
|
|
||||||
log_sys_error("mmap", file);
|
|
||||||
close(fd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
p->fe = p->fb + info.st_size;
|
|
||||||
|
|
||||||
/* parse */
|
|
||||||
p->tb = p->te = p->fb;
|
|
||||||
p->line = 1;
|
|
||||||
_get_token(p);
|
|
||||||
if (!(cf->root = _file(p))) {
|
|
||||||
stack;
|
stack;
|
||||||
r = 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unmap the file */
|
if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
|
||||||
if (munmap((char *) p->fb, info.st_size)) {
|
stack;
|
||||||
log_sys_error("munmap", file);
|
return 0;
|
||||||
r = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
r = read_config_fd(cft, dev, 0, (size_t) info.st_size, 0, 0,
|
||||||
|
(checksum_fn_t) NULL, 0);
|
||||||
|
|
||||||
|
dev_close(dev);
|
||||||
|
|
||||||
|
c->timestamp = info.st_mtime;
|
||||||
|
c->filename = pool_strdup(c->mem, file);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _write_value(FILE * fp, struct config_value *v)
|
time_t config_file_timestamp(struct config_tree *cft)
|
||||||
|
{
|
||||||
|
struct cs *c = (struct cs *) cft;
|
||||||
|
|
||||||
|
return c->timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns 1 if config file reloaded
|
||||||
|
*/
|
||||||
|
int reload_config_file(struct config_tree **cft)
|
||||||
|
{
|
||||||
|
struct config_tree *new_cft;
|
||||||
|
struct cs *c = (struct cs *) *cft;
|
||||||
|
struct cs *new_cs;
|
||||||
|
struct stat info;
|
||||||
|
struct device *dev;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!c->filename)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (stat(c->filename, &info) == -1) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
return 1;
|
||||||
|
log_sys_error("stat", c->filename);
|
||||||
|
log_error("Failed to reload configuration file");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!S_ISREG(info.st_mode)) {
|
||||||
|
log_error("Configuration file %s is not a regular file",
|
||||||
|
c->filename);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unchanged? */
|
||||||
|
if (c->timestamp == info.st_mtime)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
log_verbose("Detected config file change: Reloading %s", c->filename);
|
||||||
|
|
||||||
|
if (info.st_size == 0) {
|
||||||
|
log_verbose("Config file reload: %s is empty", c->filename);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(new_cft = create_config_tree())) {
|
||||||
|
log_error("Allocation of new config_tree failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(dev = dev_create_file(c->filename, NULL, NULL))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = read_config_fd(new_cft, dev, 0, (size_t) info.st_size,
|
||||||
|
0, 0, (checksum_fn_t) NULL, 0);
|
||||||
|
|
||||||
|
dev_close(dev);
|
||||||
|
|
||||||
|
if (r) {
|
||||||
|
new_cs = (struct cs *) new_cft;
|
||||||
|
new_cs->filename = pool_strdup(new_cs->mem, c->filename);
|
||||||
|
new_cs->timestamp = info.st_mtime;
|
||||||
|
destroy_config_tree(*cft);
|
||||||
|
*cft = new_cft;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _write_value(FILE *fp, struct config_value *v)
|
||||||
{
|
{
|
||||||
switch (v->type) {
|
switch (v->type) {
|
||||||
case CFG_STRING:
|
case CFG_STRING:
|
||||||
@@ -177,10 +339,18 @@ static void _write_value(FILE * fp, struct config_value *v)
|
|||||||
case CFG_INT:
|
case CFG_INT:
|
||||||
fprintf(fp, "%d", v->v.i);
|
fprintf(fp, "%d", v->v.i);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CFG_EMPTY_ARRAY:
|
||||||
|
fprintf(fp, "[]");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log_error("_write_value: Unknown value type: %d", v->type);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _write_config(struct config_node *n, FILE * fp, int level)
|
static int _write_config(struct config_node *n, FILE *fp, int level)
|
||||||
{
|
{
|
||||||
char space[MAX_INDENT + 1];
|
char space[MAX_INDENT + 1];
|
||||||
int l = (level < MAX_INDENT) ? level : MAX_INDENT;
|
int l = (level < MAX_INDENT) ? level : MAX_INDENT;
|
||||||
@@ -190,7 +360,7 @@ static int _write_config(struct config_node *n, FILE * fp, int level)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
for (i = 0; i < l; i++)
|
for (i = 0; i < l; i++)
|
||||||
space[i] = ' ';
|
space[i] = '\t';
|
||||||
space[i] = '\0';
|
space[i] = '\0';
|
||||||
|
|
||||||
while (n) {
|
while (n) {
|
||||||
@@ -223,20 +393,28 @@ static int _write_config(struct config_node *n, FILE * fp, int level)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int write_config(struct config_file *cf, const char *file)
|
int write_config_file(struct config_tree *cft, const char *file)
|
||||||
{
|
{
|
||||||
int r = 1;
|
int r = 1;
|
||||||
FILE *fp = fopen(file, "w");
|
FILE *fp;
|
||||||
if (!fp) {
|
|
||||||
|
if (!file) {
|
||||||
|
fp = stdout;
|
||||||
|
file = "stdout";
|
||||||
|
} else if (!(fp = fopen(file, "w"))) {
|
||||||
log_sys_error("open", file);
|
log_sys_error("open", file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_write_config(cf->root, fp, 0)) {
|
log_verbose("Dumping configuration to %s", file);
|
||||||
stack;
|
if (!_write_config(cft->root, fp, 0)) {
|
||||||
|
log_error("Failure while writing configuration");
|
||||||
r = 0;
|
r = 0;
|
||||||
}
|
}
|
||||||
fclose(fp);
|
|
||||||
|
if (fp != stdout)
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,7 +484,7 @@ static struct config_node *_section(struct parser *p)
|
|||||||
static struct config_value *_value(struct parser *p)
|
static struct config_value *_value(struct parser *p)
|
||||||
{
|
{
|
||||||
/* '[' TYPE* ']' | TYPE */
|
/* '[' TYPE* ']' | TYPE */
|
||||||
struct config_value *h = 0, *l, *ll = 0;
|
struct config_value *h = NULL, *l, *ll = NULL;
|
||||||
if (p->t == TOK_ARRAY_B) {
|
if (p->t == TOK_ARRAY_B) {
|
||||||
match(TOK_ARRAY_B);
|
match(TOK_ARRAY_B);
|
||||||
while (p->t != TOK_ARRAY_E) {
|
while (p->t != TOK_ARRAY_E) {
|
||||||
@@ -325,6 +503,16 @@ static struct config_value *_value(struct parser *p)
|
|||||||
match(TOK_COMMA);
|
match(TOK_COMMA);
|
||||||
}
|
}
|
||||||
match(TOK_ARRAY_E);
|
match(TOK_ARRAY_E);
|
||||||
|
/*
|
||||||
|
* Special case for an empty array.
|
||||||
|
*/
|
||||||
|
if (!h) {
|
||||||
|
if (!(h = _create_value(p)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
h->type = CFG_EMPTY_ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
} else
|
} else
|
||||||
h = _type(p);
|
h = _type(p);
|
||||||
|
|
||||||
@@ -333,19 +521,22 @@ static struct config_value *_value(struct parser *p)
|
|||||||
|
|
||||||
static struct config_value *_type(struct parser *p)
|
static struct config_value *_type(struct parser *p)
|
||||||
{
|
{
|
||||||
/* [0-9]+ | [0-9]*\.[0-9]* | ".*" */
|
/* [+-]{0,1}[0-9]+ | [0-9]*\.[0-9]* | ".*" */
|
||||||
struct config_value *v = _create_value(p);
|
struct config_value *v = _create_value(p);
|
||||||
|
|
||||||
|
if (!v)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
switch (p->t) {
|
switch (p->t) {
|
||||||
case TOK_INT:
|
case TOK_INT:
|
||||||
v->type = CFG_INT;
|
v->type = CFG_INT;
|
||||||
v->v.i = strtol(p->tb, 0, 0); /* FIXME: check error */
|
v->v.i = strtol(p->tb, NULL, 0); /* FIXME: check error */
|
||||||
match(TOK_INT);
|
match(TOK_INT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_FLOAT:
|
case TOK_FLOAT:
|
||||||
v->type = CFG_FLOAT;
|
v->type = CFG_FLOAT;
|
||||||
v->v.r = strtod(p->tb, 0); /* FIXME: check error */
|
v->v.r = strtod(p->tb, NULL); /* FIXME: check error */
|
||||||
match(TOK_FLOAT);
|
match(TOK_FLOAT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -373,22 +564,29 @@ static int _match_aux(struct parser *p, int t)
|
|||||||
if (p->t != t)
|
if (p->t != t)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
_get_token(p);
|
_get_token(p, t);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tokeniser
|
* tokeniser
|
||||||
*/
|
*/
|
||||||
static void _get_token(struct parser *p)
|
static void _get_token(struct parser *p, int tok_prev)
|
||||||
{
|
{
|
||||||
|
int values_allowed = 0;
|
||||||
|
|
||||||
p->tb = p->te;
|
p->tb = p->te;
|
||||||
_eat_space(p);
|
_eat_space(p);
|
||||||
if (p->tb == p->fe) {
|
if (p->tb == p->fe || !*p->tb) {
|
||||||
p->t = TOK_EOF;
|
p->t = TOK_EOF;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Should next token be interpreted as value instead of identifier? */
|
||||||
|
if (tok_prev == TOK_EQ || tok_prev == TOK_ARRAY_B ||
|
||||||
|
tok_prev == TOK_COMMA)
|
||||||
|
values_allowed = 1;
|
||||||
|
|
||||||
p->t = TOK_INT; /* fudge so the fall through for
|
p->t = TOK_INT; /* fudge so the fall through for
|
||||||
floats works */
|
floats works */
|
||||||
switch (*p->te) {
|
switch (*p->te) {
|
||||||
@@ -425,13 +623,24 @@ static void _get_token(struct parser *p)
|
|||||||
case '"':
|
case '"':
|
||||||
p->t = TOK_STRING;
|
p->t = TOK_STRING;
|
||||||
p->te++;
|
p->te++;
|
||||||
while ((p->te != p->fe) && (*p->te != '"')) {
|
while ((p->te != p->fe) && (*p->te) && (*p->te != '"')) {
|
||||||
if ((*p->te == '\\') && (p->te + 1 != p->fe))
|
if ((*p->te == '\\') && (p->te + 1 != p->fe) &&
|
||||||
|
*(p->te + 1))
|
||||||
p->te++;
|
p->te++;
|
||||||
p->te++;
|
p->te++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p->te != p->fe)
|
if ((p->te != p->fe) && (*p->te))
|
||||||
|
p->te++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\'':
|
||||||
|
p->t = TOK_STRING;
|
||||||
|
p->te++;
|
||||||
|
while ((p->te != p->fe) && (*p->te) && (*p->te != '\''))
|
||||||
|
p->te++;
|
||||||
|
|
||||||
|
if ((p->te != p->fe) && (*p->te))
|
||||||
p->te++;
|
p->te++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -447,22 +656,27 @@ static void _get_token(struct parser *p)
|
|||||||
case '7':
|
case '7':
|
||||||
case '8':
|
case '8':
|
||||||
case '9':
|
case '9':
|
||||||
p->te++;
|
case '+':
|
||||||
while (p->te != p->fe) {
|
case '-':
|
||||||
if (*p->te == '.') {
|
if (values_allowed) {
|
||||||
if (p->t == TOK_FLOAT)
|
|
||||||
break;
|
|
||||||
p->t = TOK_FLOAT;
|
|
||||||
} else if (!isdigit((int) *p->te))
|
|
||||||
break;
|
|
||||||
p->te++;
|
p->te++;
|
||||||
|
while ((p->te != p->fe) && (*p->te)) {
|
||||||
|
if (*p->te == '.') {
|
||||||
|
if (p->t == TOK_FLOAT)
|
||||||
|
break;
|
||||||
|
p->t = TOK_FLOAT;
|
||||||
|
} else if (!isdigit((int) *p->te))
|
||||||
|
break;
|
||||||
|
p->te++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
p->t = TOK_IDENTIFIER;
|
p->t = TOK_IDENTIFIER;
|
||||||
while ((p->te != p->fe) && !isspace(*p->te) &&
|
while ((p->te != p->fe) && (*p->te) && !isspace(*p->te) &&
|
||||||
(*p->te != '#') && (*p->te != '='))
|
(*p->te != '#') && (*p->te != '=') && (*p->te != '{') &&
|
||||||
|
(*p->te != '}'))
|
||||||
p->te++;
|
p->te++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -470,15 +684,15 @@ static void _get_token(struct parser *p)
|
|||||||
|
|
||||||
static void _eat_space(struct parser *p)
|
static void _eat_space(struct parser *p)
|
||||||
{
|
{
|
||||||
while (p->tb != p->fe) {
|
while ((p->tb != p->fe) && (*p->tb)) {
|
||||||
if (*p->te == '#') {
|
if (*p->te == '#') {
|
||||||
while ((p->te != p->fe) && (*p->te != '\n'))
|
while ((p->te != p->fe) && (*p->te) && (*p->te != '\n'))
|
||||||
p->te++;
|
p->te++;
|
||||||
p->line++;
|
p->line++;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isspace(*p->te)) {
|
else if (isspace(*p->te)) {
|
||||||
while ((p->te != p->fe) && isspace(*p->te)) {
|
while ((p->te != p->fe) && (*p->te) && isspace(*p->te)) {
|
||||||
if (*p->te == '\n')
|
if (*p->te == '\n')
|
||||||
p->line++;
|
p->line++;
|
||||||
p->te++;
|
p->te++;
|
||||||
@@ -511,7 +725,7 @@ static struct config_node *_create_node(struct parser *p)
|
|||||||
|
|
||||||
static char *_dup_tok(struct parser *p)
|
static char *_dup_tok(struct parser *p)
|
||||||
{
|
{
|
||||||
int len = p->te - p->tb;
|
size_t len = p->te - p->tb;
|
||||||
char *str = pool_alloc(p->mem, len + 1);
|
char *str = pool_alloc(p->mem, len + 1);
|
||||||
if (!str) {
|
if (!str) {
|
||||||
stack;
|
stack;
|
||||||
@@ -525,8 +739,7 @@ static char *_dup_tok(struct parser *p)
|
|||||||
/*
|
/*
|
||||||
* utility functions
|
* utility functions
|
||||||
*/
|
*/
|
||||||
struct config_node *find_config_node(struct config_node *cn,
|
struct config_node *find_config_node(struct config_node *cn, const char *path)
|
||||||
const char *path, char sep)
|
|
||||||
{
|
{
|
||||||
const char *e;
|
const char *e;
|
||||||
|
|
||||||
@@ -558,9 +771,9 @@ struct config_node *find_config_node(struct config_node *cn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *find_config_str(struct config_node *cn,
|
const char *find_config_str(struct config_node *cn,
|
||||||
const char *path, char sep, const char *fail)
|
const char *path, const char *fail)
|
||||||
{
|
{
|
||||||
struct config_node *n = find_config_node(cn, path, sep);
|
struct config_node *n = find_config_node(cn, path);
|
||||||
|
|
||||||
if (n && n->v->type == CFG_STRING) {
|
if (n && n->v->type == CFG_STRING) {
|
||||||
if (*n->v->v.str)
|
if (*n->v->v.str)
|
||||||
@@ -574,10 +787,9 @@ const char *find_config_str(struct config_node *cn,
|
|||||||
return fail;
|
return fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
int find_config_int(struct config_node *cn, const char *path,
|
int find_config_int(struct config_node *cn, const char *path, int fail)
|
||||||
char sep, int fail)
|
|
||||||
{
|
{
|
||||||
struct config_node *n = find_config_node(cn, path, sep);
|
struct config_node *n = find_config_node(cn, path);
|
||||||
|
|
||||||
if (n && n->v->type == CFG_INT) {
|
if (n && n->v->type == CFG_INT) {
|
||||||
log_very_verbose("Setting %s to %d", path, n->v->v.i);
|
log_very_verbose("Setting %s to %d", path, n->v->v.i);
|
||||||
@@ -589,10 +801,9 @@ int find_config_int(struct config_node *cn, const char *path,
|
|||||||
return fail;
|
return fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
float find_config_float(struct config_node *cn, const char *path,
|
float find_config_float(struct config_node *cn, const char *path, float fail)
|
||||||
char sep, float fail)
|
|
||||||
{
|
{
|
||||||
struct config_node *n = find_config_node(cn, path, sep);
|
struct config_node *n = find_config_node(cn, path);
|
||||||
|
|
||||||
if (n && n->v->type == CFG_FLOAT) {
|
if (n && n->v->type == CFG_FLOAT) {
|
||||||
log_very_verbose("Setting %s to %f", path, n->v->v.r);
|
log_very_verbose("Setting %s to %f", path, n->v->v.r);
|
||||||
@@ -632,10 +843,9 @@ static int _str_to_bool(const char *str, int fail)
|
|||||||
return fail;
|
return fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
int find_config_bool(struct config_node *cn, const char *path,
|
int find_config_bool(struct config_node *cn, const char *path, int fail)
|
||||||
char sep, int fail)
|
|
||||||
{
|
{
|
||||||
struct config_node *n = find_config_node(cn, path, sep);
|
struct config_node *n = find_config_node(cn, path);
|
||||||
struct config_value *v;
|
struct config_value *v;
|
||||||
|
|
||||||
if (!n)
|
if (!n)
|
||||||
@@ -655,11 +865,11 @@ int find_config_bool(struct config_node *cn, const char *path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int get_config_uint32(struct config_node *cn, const char *path,
|
int get_config_uint32(struct config_node *cn, const char *path,
|
||||||
char sep, uint32_t * result)
|
uint32_t *result)
|
||||||
{
|
{
|
||||||
struct config_node *n;
|
struct config_node *n;
|
||||||
|
|
||||||
n = find_config_node(cn, path, sep);
|
n = find_config_node(cn, path);
|
||||||
|
|
||||||
if (!n || !n->v || n->v->type != CFG_INT)
|
if (!n || !n->v || n->v->type != CFG_INT)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -669,11 +879,11 @@ int get_config_uint32(struct config_node *cn, const char *path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int get_config_uint64(struct config_node *cn, const char *path,
|
int get_config_uint64(struct config_node *cn, const char *path,
|
||||||
char sep, uint64_t * result)
|
uint64_t *result)
|
||||||
{
|
{
|
||||||
struct config_node *n;
|
struct config_node *n;
|
||||||
|
|
||||||
n = find_config_node(cn, path, sep);
|
n = find_config_node(cn, path);
|
||||||
|
|
||||||
if (!n || !n->v || n->v->type != CFG_INT)
|
if (!n || !n->v || n->v->type != CFG_INT)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -682,3 +892,16 @@ int get_config_uint64(struct config_node *cn, const char *path,
|
|||||||
*result = (uint64_t) n->v->v.i;
|
*result = (uint64_t) n->v->v.i;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int get_config_str(struct config_node *cn, const char *path, char **result)
|
||||||
|
{
|
||||||
|
struct config_node *n;
|
||||||
|
|
||||||
|
n = find_config_node(cn, path);
|
||||||
|
|
||||||
|
if (!n || !n->v || n->v->type != CFG_STRING)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*result = n->v->v.str;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,72 +1,86 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_CONFIG_H
|
#ifndef _LVM_CONFIG_H
|
||||||
#define _LVM_CONFIG_H
|
#define _LVM_CONFIG_H
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include "device.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
CFG_STRING,
|
CFG_STRING,
|
||||||
CFG_FLOAT,
|
CFG_FLOAT,
|
||||||
CFG_INT,
|
CFG_INT,
|
||||||
|
CFG_EMPTY_ARRAY
|
||||||
};
|
};
|
||||||
|
|
||||||
struct config_value {
|
struct config_value {
|
||||||
int type;
|
int type;
|
||||||
union {
|
union {
|
||||||
int i;
|
int i;
|
||||||
float r;
|
float r;
|
||||||
char *str;
|
char *str;
|
||||||
} v;
|
} v;
|
||||||
struct config_value *next; /* for arrays */
|
struct config_value *next; /* for arrays */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct config_node {
|
struct config_node {
|
||||||
char *key;
|
char *key;
|
||||||
struct config_node *sib, *child;
|
struct config_node *sib, *child;
|
||||||
struct config_value *v;
|
struct config_value *v;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct config_file {
|
struct config_tree {
|
||||||
struct config_node *root;
|
struct config_node *root;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct config_file *create_config_file(void);
|
struct config_tree *create_config_tree(void);
|
||||||
void destroy_config_file(struct config_file *cf);
|
void destroy_config_tree(struct config_tree *cf);
|
||||||
|
|
||||||
int read_config(struct config_file *cf, const char *file);
|
typedef uint32_t (*checksum_fn_t) (uint32_t initial, void *buf, uint32_t size);
|
||||||
int write_config(struct config_file *cf, const char *file);
|
|
||||||
|
int read_config_fd(struct config_tree *cf, struct device *dev,
|
||||||
|
off_t offset, size_t size, off_t offset2, size_t size2,
|
||||||
|
checksum_fn_t checksum_fn, uint32_t checksum);
|
||||||
|
|
||||||
|
int read_config_file(struct config_tree *cf, const char *file);
|
||||||
|
int write_config_file(struct config_tree *cf, const char *file);
|
||||||
|
int reload_config_file(struct config_tree **cf);
|
||||||
|
time_t config_file_timestamp(struct config_tree *cf);
|
||||||
|
|
||||||
struct config_node *find_config_node(struct config_node *cn,
|
struct config_node *find_config_node(struct config_node *cn,
|
||||||
const char *path, char seperator);
|
const char *path);
|
||||||
|
|
||||||
const char *find_config_str(struct config_node *cn,
|
const char *find_config_str(struct config_node *cn, const char *path,
|
||||||
const char *path, char sep, const char *fail);
|
const char *fail);
|
||||||
|
|
||||||
int find_config_int(struct config_node *cn, const char *path,
|
int find_config_int(struct config_node *cn, const char *path, int fail);
|
||||||
char sep, int fail);
|
|
||||||
|
|
||||||
float find_config_float(struct config_node *cn, const char *path,
|
float find_config_float(struct config_node *cn, const char *path, float fail);
|
||||||
char sep, float fail);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Understands (0, ~0), (y, n), (yes, no), (on,
|
* Understands (0, ~0), (y, n), (yes, no), (on,
|
||||||
* off), (true, false).
|
* off), (true, false).
|
||||||
*/
|
*/
|
||||||
int find_config_bool(struct config_node *cn, const char *path,
|
int find_config_bool(struct config_node *cn, const char *path, int fail);
|
||||||
char sep, int fail);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int get_config_uint32(struct config_node *cn, const char *path,
|
int get_config_uint32(struct config_node *cn, const char *path,
|
||||||
char sep, uint32_t *result);
|
uint32_t *result);
|
||||||
|
|
||||||
int get_config_uint64(struct config_node *cn, const char *path,
|
int get_config_uint64(struct config_node *cn, const char *path,
|
||||||
char sep, uint64_t *result);
|
uint64_t *result);
|
||||||
|
|
||||||
|
int get_config_str(struct config_node *cn, const char *path, char **result);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the GPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_DEFAULTS_H
|
#ifndef _LVM_DEFAULTS_H
|
||||||
#define _LVM_DEFAULTS_H
|
#define _LVM_DEFAULTS_H
|
||||||
|
|
||||||
|
|
||||||
#define DEFAULT_SYS_DIR "/etc/lvm"
|
|
||||||
|
|
||||||
#define DEFAULT_ARCHIVE_ENABLED 1
|
#define DEFAULT_ARCHIVE_ENABLED 1
|
||||||
#define DEFAULT_BACKUP_ENABLED 1
|
#define DEFAULT_BACKUP_ENABLED 1
|
||||||
|
|
||||||
@@ -19,22 +25,84 @@
|
|||||||
#define DEFAULT_ARCHIVE_DAYS 30
|
#define DEFAULT_ARCHIVE_DAYS 30
|
||||||
#define DEFAULT_ARCHIVE_NUMBER 10
|
#define DEFAULT_ARCHIVE_NUMBER 10
|
||||||
|
|
||||||
|
#define DEFAULT_SYS_DIR "/etc/lvm"
|
||||||
#define DEFAULT_DEV_DIR "/dev"
|
#define DEFAULT_DEV_DIR "/dev"
|
||||||
#define DEFAULT_PROC_DIR "/proc"
|
#define DEFAULT_PROC_DIR "/proc"
|
||||||
|
#define DEFAULT_SYSFS_SCAN 1
|
||||||
|
|
||||||
#define DEFAULT_LOCK_DIR "/var/lock/lvm"
|
#define DEFAULT_LOCK_DIR "/var/lock/lvm"
|
||||||
|
#define DEFAULT_LOCKING_LIB "lvm2_locking.so"
|
||||||
|
|
||||||
#define DEFAULT_UMASK 0077
|
#define DEFAULT_UMASK 0077
|
||||||
|
|
||||||
#define DEFAULT_FORMAT "lvm1"
|
#ifdef LVM1_FALLBACK
|
||||||
|
# define DEFAULT_FALLBACK_TO_LVM1 1
|
||||||
#define DEFAULT_MSG_PREFIX " "
|
#else
|
||||||
|
# define DEFAULT_FALLBACK_TO_LVM1 0
|
||||||
#define DEFAULT_CMD_NAME 0
|
|
||||||
|
|
||||||
#ifdef READLINE_SUPPORT
|
|
||||||
#define DEFAULT_MAX_HISTORY 100
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef LVM1_SUPPORT
|
||||||
|
# define DEFAULT_FORMAT "lvm1"
|
||||||
|
#else
|
||||||
|
# define DEFAULT_FORMAT "lvm2"
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _LVM_DEFAULTS_H */
|
#define DEFAULT_STRIPESIZE 64 /* KB */
|
||||||
|
#define DEFAULT_PVMETADATASIZE 255
|
||||||
|
#define DEFAULT_PVMETADATACOPIES 1
|
||||||
|
#define DEFAULT_LABELSECTOR UINT64_C(1)
|
||||||
|
|
||||||
|
#define DEFAULT_MSG_PREFIX " "
|
||||||
|
#define DEFAULT_CMD_NAME 0
|
||||||
|
#define DEFAULT_OVERWRITE 0
|
||||||
|
|
||||||
|
#ifndef DEFAULT_LOG_FACILITY
|
||||||
|
# define DEFAULT_LOG_FACILITY LOG_USER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEFAULT_SYSLOG 1
|
||||||
|
#define DEFAULT_VERBOSE 0
|
||||||
|
#define DEFAULT_LOGLEVEL 0
|
||||||
|
#define DEFAULT_INDENT 1
|
||||||
|
#define DEFAULT_UNITS "h"
|
||||||
|
#define DEFAULT_SUFFIX 1
|
||||||
|
#define DEFAULT_HOSTTAGS 0
|
||||||
|
|
||||||
|
#ifdef DEVMAPPER_SUPPORT
|
||||||
|
# define DEFAULT_ACTIVATION 1
|
||||||
|
# define DEFAULT_RESERVED_MEMORY 8192
|
||||||
|
# define DEFAULT_RESERVED_STACK 256
|
||||||
|
# define DEFAULT_PROCESS_PRIORITY -18
|
||||||
|
#else
|
||||||
|
# define DEFAULT_ACTIVATION 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEFAULT_STRIPE_FILLER "/dev/ioerror"
|
||||||
|
#define DEFAULT_MIRROR_REGION_SIZE 512 /* KB */
|
||||||
|
#define DEFAULT_INTERVAL 15
|
||||||
|
|
||||||
|
#ifdef READLINE_SUPPORT
|
||||||
|
# define DEFAULT_MAX_HISTORY 100
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEFAULT_REP_ALIGNED 1
|
||||||
|
#define DEFAULT_REP_BUFFERED 1
|
||||||
|
#define DEFAULT_REP_HEADINGS 1
|
||||||
|
#define DEFAULT_REP_SEPARATOR " "
|
||||||
|
|
||||||
|
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,move_percent"
|
||||||
|
#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
|
||||||
|
#define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"
|
||||||
|
#define DEFAULT_SEGS_COLS "lv_name,vg_name,lv_attr,stripes,segtype,seg_size"
|
||||||
|
|
||||||
|
#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,origin,snap_percent,move_pv,move_percent,lv_uuid"
|
||||||
|
#define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid"
|
||||||
|
#define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pv_uuid"
|
||||||
|
#define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize"
|
||||||
|
|
||||||
|
#define DEFAULT_LVS_SORT "vg_name,lv_name"
|
||||||
|
#define DEFAULT_VGS_SORT "vg_name"
|
||||||
|
#define DEFAULT_PVS_SORT "pv_name"
|
||||||
|
#define DEFAULT_SEGS_SORT "vg_name,lv_name,seg_start"
|
||||||
|
|
||||||
|
#endif /* _LVM_DEFAULTS_H */
|
||||||
|
|||||||
@@ -1,21 +1,28 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
#include "bitset.h"
|
#include "bitset.h"
|
||||||
#include "dbg_malloc.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
/* FIXME: calculate this. */
|
/* FIXME: calculate this. */
|
||||||
#define INT_SHIFT 5
|
#define INT_SHIFT 5
|
||||||
|
|
||||||
bitset_t bitset_create(struct pool * mem, unsigned num_bits)
|
bitset_t bitset_create(struct pool *mem, unsigned num_bits)
|
||||||
{
|
{
|
||||||
int n = (num_bits / BITS_PER_INT) + 2;
|
unsigned n = (num_bits / BITS_PER_INT) + 2;
|
||||||
int size = sizeof(int) * n;
|
size_t size = sizeof(int) * n;
|
||||||
unsigned *bs = pool_zalloc(mem, size);
|
unsigned *bs = pool_zalloc(mem, size);
|
||||||
|
|
||||||
if (!bs)
|
if (!bs)
|
||||||
|
|||||||
@@ -1,28 +1,34 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the GPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_BITSET_H
|
#ifndef _LVM_BITSET_H
|
||||||
#define _LVM_BITSET_H
|
#define _LVM_BITSET_H
|
||||||
|
|
||||||
#include "lvm-types.h"
|
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
typedef uint32_t *bitset_t;
|
typedef uint32_t *bitset_t;
|
||||||
|
|
||||||
bitset_t bitset_create(struct pool *mem, unsigned num_bits);
|
bitset_t bitset_create(struct pool *mem, unsigned num_bits);
|
||||||
|
void bitset_destroy(bitset_t bs);
|
||||||
|
|
||||||
void bit_union(bitset_t out, bitset_t in1, bitset_t in2);
|
void bit_union(bitset_t out, bitset_t in1, bitset_t in2);
|
||||||
int bit_get_first(bitset_t bs);
|
int bit_get_first(bitset_t bs);
|
||||||
int bit_get_next(bitset_t bs, int last_bit);
|
int bit_get_next(bitset_t bs, int last_bit);
|
||||||
|
|
||||||
|
|
||||||
#define BITS_PER_INT (sizeof(int) * CHAR_BIT)
|
#define BITS_PER_INT (sizeof(int) * CHAR_BIT)
|
||||||
|
|
||||||
#define bit(bs, i) \
|
#define bit(bs, i) \
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
#include "btree.h"
|
#include "btree.h"
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
struct node {
|
struct node {
|
||||||
uint32_t key;
|
uint32_t key;
|
||||||
@@ -46,7 +55,7 @@ static uint32_t _shuffle(uint32_t k)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct node **_lookup(struct node **c, uint32_t key, struct node **p)
|
static struct node **_lookup(struct node **c, uint32_t key, struct node **p)
|
||||||
{
|
{
|
||||||
*p = NULL;
|
*p = NULL;
|
||||||
while (*c) {
|
while (*c) {
|
||||||
|
|||||||
@@ -1,13 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the GPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_BTREE_H
|
#ifndef _LVM_BTREE_H
|
||||||
#define _LVM_BTREE_H
|
#define _LVM_BTREE_H
|
||||||
|
|
||||||
#include "lvm-types.h"
|
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
|
|
||||||
struct btree;
|
struct btree;
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dbg_malloc.h"
|
#include "lib.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
struct hash_node {
|
struct hash_node {
|
||||||
struct hash_node *next;
|
struct hash_node *next;
|
||||||
@@ -26,26 +34,26 @@ static unsigned char _nums[] = {
|
|||||||
87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65,
|
87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65,
|
||||||
49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28,
|
49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28,
|
||||||
12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172,
|
12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172,
|
||||||
144,
|
144,
|
||||||
176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79, 46, 168, 198, 41, 254,
|
176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79, 46, 168, 198, 41, 254,
|
||||||
178, 85, 253, 237, 250, 154, 133, 88, 35, 206, 95, 116, 252, 192, 54,
|
178, 85, 253, 237, 250, 154, 133, 88, 35, 206, 95, 116, 252, 192, 54,
|
||||||
221,
|
221,
|
||||||
102, 218, 255, 240, 82, 106, 158, 201, 61, 3, 89, 9, 42, 155, 159, 93,
|
102, 218, 255, 240, 82, 106, 158, 201, 61, 3, 89, 9, 42, 155, 159, 93,
|
||||||
166, 80, 50, 34, 175, 195, 100, 99, 26, 150, 16, 145, 4, 33, 8, 189,
|
166, 80, 50, 34, 175, 195, 100, 99, 26, 150, 16, 145, 4, 33, 8, 189,
|
||||||
121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185,
|
121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185,
|
||||||
194,
|
194,
|
||||||
193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232,
|
193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232,
|
||||||
139,
|
139,
|
||||||
6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112,
|
6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112,
|
||||||
84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196,
|
84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196,
|
||||||
43,
|
43,
|
||||||
249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231,
|
249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231,
|
||||||
71,
|
71,
|
||||||
230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47,
|
230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47,
|
||||||
109,
|
109,
|
||||||
44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184,
|
44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184,
|
||||||
163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120,
|
163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120,
|
||||||
209
|
209
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct hash_node *_create_node(const char *str)
|
static struct hash_node *_create_node(const char *str)
|
||||||
@@ -62,7 +70,7 @@ static struct hash_node *_create_node(const char *str)
|
|||||||
|
|
||||||
static unsigned _hash(const char *str)
|
static unsigned _hash(const char *str)
|
||||||
{
|
{
|
||||||
unsigned long int h = 0, g;
|
unsigned long h = 0, g;
|
||||||
while (*str) {
|
while (*str) {
|
||||||
h <<= 4;
|
h <<= 4;
|
||||||
h += _nums[(int) *str++];
|
h += _nums[(int) *str++];
|
||||||
@@ -126,7 +134,7 @@ void hash_destroy(struct hash_table *t)
|
|||||||
dbg_free(t);
|
dbg_free(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct hash_node **_find(struct hash_table *t, const char *key)
|
static struct hash_node **_find(struct hash_table *t, const char *key)
|
||||||
{
|
{
|
||||||
unsigned h = _hash(key) & (t->num_slots - 1);
|
unsigned h = _hash(key) & (t->num_slots - 1);
|
||||||
struct hash_node **c;
|
struct hash_node **c;
|
||||||
@@ -209,7 +217,7 @@ void *hash_get_data(struct hash_table *t, struct hash_node *n)
|
|||||||
return n->data;
|
return n->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct hash_node *_next_slot(struct hash_table *t, unsigned int s)
|
static struct hash_node *_next_slot(struct hash_table *t, unsigned s)
|
||||||
{
|
{
|
||||||
struct hash_node *c = NULL;
|
struct hash_node *c = NULL;
|
||||||
int i;
|
int i;
|
||||||
@@ -227,6 +235,6 @@ struct hash_node *hash_get_first(struct hash_table *t)
|
|||||||
|
|
||||||
struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n)
|
struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n)
|
||||||
{
|
{
|
||||||
unsigned int h = _hash(n->key) & (t->num_slots - 1);
|
unsigned h = _hash(n->key) & (t->num_slots - 1);
|
||||||
return n->next ? n->next : _next_slot(t, h + 1);
|
return n->next ? n->next : _next_slot(t, h + 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the GPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_HASH_H
|
#ifndef _LVM_HASH_H
|
||||||
@@ -10,13 +19,14 @@
|
|||||||
struct hash_table;
|
struct hash_table;
|
||||||
struct hash_node;
|
struct hash_node;
|
||||||
|
|
||||||
typedef void (*iterate_fn)(void *data);
|
typedef void (*iterate_fn) (void *data);
|
||||||
|
|
||||||
struct hash_table *hash_create(unsigned size_hint);
|
struct hash_table *hash_create(unsigned size_hint);
|
||||||
void hash_destroy(struct hash_table *t);
|
void hash_destroy(struct hash_table *t);
|
||||||
void hash_wipe(struct hash_table *t);
|
void hash_wipe(struct hash_table *t);
|
||||||
|
|
||||||
void *hash_lookup(struct hash_table *t, const char *key);
|
void *hash_lookup(struct hash_table *t, const char *key);
|
||||||
|
void *hash_lookup_fixed(struct hash_table *t, const char *key, uint32_t len);
|
||||||
int hash_insert(struct hash_table *t, const char *key, void *data);
|
int hash_insert(struct hash_table *t, const char *key, void *data);
|
||||||
void hash_remove(struct hash_table *t, const char *key);
|
void hash_remove(struct hash_table *t, const char *key);
|
||||||
|
|
||||||
@@ -33,4 +43,3 @@ struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n);
|
|||||||
v = hash_get_next(h, v))
|
v = hash_get_next(h, v))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_LIST_H
|
#ifndef _LVM_LIST_H
|
||||||
@@ -13,11 +22,15 @@ struct list {
|
|||||||
struct list *n, *p;
|
struct list *n, *p;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void list_init(struct list *head) {
|
#define LIST_INIT(name) struct list name = { &(name), &(name) }
|
||||||
|
|
||||||
|
static inline void list_init(struct list *head)
|
||||||
|
{
|
||||||
head->n = head->p = head;
|
head->n = head->p = head;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void list_add(struct list *head, struct list *elem) {
|
static inline void list_add(struct list *head, struct list *elem)
|
||||||
|
{
|
||||||
assert(head->n);
|
assert(head->n);
|
||||||
|
|
||||||
elem->n = head;
|
elem->n = head;
|
||||||
@@ -27,7 +40,8 @@ static inline void list_add(struct list *head, struct list *elem) {
|
|||||||
head->p = elem;
|
head->p = elem;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void list_add_h(struct list *head, struct list *elem) {
|
static inline void list_add_h(struct list *head, struct list *elem)
|
||||||
|
{
|
||||||
assert(head->n);
|
assert(head->n);
|
||||||
|
|
||||||
elem->n = head->n;
|
elem->n = head->n;
|
||||||
@@ -37,36 +51,62 @@ static inline void list_add_h(struct list *head, struct list *elem) {
|
|||||||
head->n = elem;
|
head->n = elem;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void list_del(struct list *elem) {
|
static inline void list_del(struct list *elem)
|
||||||
|
{
|
||||||
elem->n->p = elem->p;
|
elem->n->p = elem->p;
|
||||||
elem->p->n = elem->n;
|
elem->p->n = elem->n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int list_empty(struct list *head) {
|
static inline int list_empty(struct list *head)
|
||||||
|
{
|
||||||
return head->n == head;
|
return head->n == head;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define list_iterate(v, head) \
|
static inline int list_end(struct list *head, struct list *elem)
|
||||||
for (v = (head)->n; v != head; v = v->n)
|
{
|
||||||
|
return elem->n == head;
|
||||||
|
}
|
||||||
|
|
||||||
#define list_iterate_safe(v, t, head) \
|
static inline struct list *list_next(struct list *head, struct list *elem)
|
||||||
for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
|
{
|
||||||
|
return (list_end(head, elem) ? NULL : elem->n);
|
||||||
static inline int list_size(struct list *head) {
|
|
||||||
int s = 0;
|
|
||||||
struct list *v;
|
|
||||||
|
|
||||||
list_iterate(v, head)
|
|
||||||
s++;
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define list_item(v, t) \
|
#define list_item(v, t) \
|
||||||
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list))
|
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list))
|
||||||
|
|
||||||
/* Given a known element in a known structure, locate the struct list */
|
#define list_struct_base(v, t, h) \
|
||||||
#define list_head(v, t, e) \
|
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->h))
|
||||||
(((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->list)
|
|
||||||
|
/* Given a known element in a known structure, locate another */
|
||||||
|
#define struct_field(v, t, e, f) \
|
||||||
|
(((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->f)
|
||||||
|
|
||||||
|
/* Given a known element in a known structure, locate the list head */
|
||||||
|
#define list_head(v, t, e) struct_field(v, t, e, list)
|
||||||
|
|
||||||
|
#define list_iterate(v, head) \
|
||||||
|
for (v = (head)->n; v != head; v = v->n)
|
||||||
|
|
||||||
|
#define list_uniterate(v, head, start) \
|
||||||
|
for (v = (start)->p; v != head; v = v->p)
|
||||||
|
|
||||||
|
#define list_iterate_safe(v, t, head) \
|
||||||
|
for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
|
||||||
|
|
||||||
|
#define list_iterate_items(v, head) \
|
||||||
|
for (v = list_item((head)->n, typeof(*v)); &v->list != (head); \
|
||||||
|
v = list_item(v->list.n, typeof(*v)))
|
||||||
|
|
||||||
|
static inline unsigned int list_size(const struct list *head)
|
||||||
|
{
|
||||||
|
unsigned int s = 0;
|
||||||
|
const struct list *v;
|
||||||
|
|
||||||
|
list_iterate(v, head)
|
||||||
|
s++;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the GPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_TYPES_H
|
#ifndef _LVM_TYPES_H
|
||||||
@@ -12,9 +21,12 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
/* Define some portable printing types */
|
||||||
|
#define PRIsize_t "Zu"
|
||||||
|
|
||||||
struct str_list {
|
struct str_list {
|
||||||
struct list list;
|
struct list list;
|
||||||
char *str;
|
const char *str;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
128
lib/datastruct/str_list.c
Normal file
128
lib/datastruct/str_list.c
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
|
#include "str_list.h"
|
||||||
|
|
||||||
|
struct list *str_list_create(struct pool *mem)
|
||||||
|
{
|
||||||
|
struct list *sl;
|
||||||
|
|
||||||
|
if (!(sl = pool_alloc(mem, sizeof(struct list)))) {
|
||||||
|
stack;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_init(sl);
|
||||||
|
|
||||||
|
return sl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str_list_add(struct pool *mem, struct list *sll, const char *str)
|
||||||
|
{
|
||||||
|
struct str_list *sln;
|
||||||
|
|
||||||
|
if (!str) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Already in list? */
|
||||||
|
if (str_list_match_item(sll, str))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!(sln = pool_alloc(mem, sizeof(*sln)))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sln->str = str;
|
||||||
|
list_add(sll, &sln->list);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str_list_del(struct list *sll, const char *str)
|
||||||
|
{
|
||||||
|
struct list *slh, *slht;
|
||||||
|
|
||||||
|
list_iterate_safe(slh, slht, sll) {
|
||||||
|
if (!strcmp(str, list_item(slh, struct str_list)->str))
|
||||||
|
list_del(slh);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str_list_dup(struct pool *mem, struct list *sllnew, struct list *sllold)
|
||||||
|
{
|
||||||
|
struct str_list *sl;
|
||||||
|
|
||||||
|
list_init(sllnew);
|
||||||
|
|
||||||
|
list_iterate_items(sl, sllold) {
|
||||||
|
if (!str_list_add(mem, sllnew, strdup(sl->str))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Is item on list?
|
||||||
|
*/
|
||||||
|
int str_list_match_item(struct list *sll, const char *str)
|
||||||
|
{
|
||||||
|
struct str_list *sl;
|
||||||
|
|
||||||
|
list_iterate_items(sl, sll)
|
||||||
|
if (!strcmp(str, sl->str))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Is at least one item on both lists?
|
||||||
|
*/
|
||||||
|
int str_list_match_list(struct list *sll, struct list *sll2)
|
||||||
|
{
|
||||||
|
struct str_list *sl;
|
||||||
|
|
||||||
|
list_iterate_items(sl, sll)
|
||||||
|
if (str_list_match_item(sll2, sl->str))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do both lists contain the same set of items?
|
||||||
|
*/
|
||||||
|
int str_list_lists_equal(struct list *sll, struct list *sll2)
|
||||||
|
{
|
||||||
|
struct str_list *sl;
|
||||||
|
|
||||||
|
if (list_size(sll) != list_size(sll2))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
list_iterate_items(sl, sll)
|
||||||
|
if (!str_list_match_item(sll2, sl->str))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
29
lib/datastruct/str_list.h
Normal file
29
lib/datastruct/str_list.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LVM_STR_LIST_H
|
||||||
|
#define _LVM_STR_LIST_H
|
||||||
|
|
||||||
|
#include "pool.h"
|
||||||
|
|
||||||
|
struct list *str_list_create(struct pool *mem);
|
||||||
|
int str_list_add(struct pool *mem, struct list *sll, const char *str);
|
||||||
|
int str_list_del(struct list *sll, const char *str);
|
||||||
|
int str_list_match_item(struct list *sll, const char *str);
|
||||||
|
int str_list_match_list(struct list *sll, struct list *sll2);
|
||||||
|
int str_list_lists_equal(struct list *sll, struct list *sll2);
|
||||||
|
int str_list_dup(struct pool *mem, struct list *sllnew, struct list *sllold);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,30 +1,30 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
#include "dev-cache.h"
|
#include "dev-cache.h"
|
||||||
#include "log.h"
|
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "lvm-types.h"
|
#include "lvm-types.h"
|
||||||
#include "btree.h"
|
#include "btree.h"
|
||||||
#include "dbg_malloc.h"
|
#include "filter.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <linux/kdev_t.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* FIXME: really need to seperate names from the devices since
|
|
||||||
* multiple names can point to the same device.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct dev_iter {
|
struct dev_iter {
|
||||||
struct btree_iter *current;
|
struct btree_iter *current;
|
||||||
@@ -51,36 +51,163 @@ static struct {
|
|||||||
|
|
||||||
static int _insert(const char *path, int rec);
|
static int _insert(const char *path, int rec);
|
||||||
|
|
||||||
static struct device *_create_dev(dev_t d)
|
struct device *dev_create_file(const char *filename, struct device *dev,
|
||||||
|
struct str_list *alias)
|
||||||
|
{
|
||||||
|
int allocate = !dev;
|
||||||
|
|
||||||
|
if (allocate && !(dev = dbg_malloc(sizeof(*dev)))) {
|
||||||
|
log_error("struct device allocation failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (allocate && !(alias = dbg_malloc(sizeof(*alias)))) {
|
||||||
|
log_error("struct str_list allocation failed");
|
||||||
|
dbg_free(dev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!(alias->str = dbg_strdup(filename))) {
|
||||||
|
log_error("filename strdup failed");
|
||||||
|
if (allocate) {
|
||||||
|
dbg_free(dev);
|
||||||
|
dbg_free(alias);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
dev->flags = DEV_REGULAR;
|
||||||
|
if (allocate)
|
||||||
|
dev->flags |= DEV_ALLOCED;
|
||||||
|
list_init(&dev->aliases);
|
||||||
|
list_add(&dev->aliases, &alias->list);
|
||||||
|
dev->end = UINT64_C(0);
|
||||||
|
dev->dev = 0;
|
||||||
|
dev->fd = -1;
|
||||||
|
dev->open_count = 0;
|
||||||
|
memset(dev->pvid, 0, sizeof(dev->pvid));
|
||||||
|
list_init(&dev->open_list);
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct device *_dev_create(dev_t d)
|
||||||
{
|
{
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
|
||||||
if (!(dev = _alloc(sizeof(*dev)))) {
|
if (!(dev = _alloc(sizeof(*dev)))) {
|
||||||
stack;
|
log_error("struct device allocation failed");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
dev->flags = 0;
|
||||||
list_init(&dev->aliases);
|
list_init(&dev->aliases);
|
||||||
dev->dev = d;
|
dev->dev = d;
|
||||||
dev->fd = -1;
|
dev->fd = -1;
|
||||||
|
dev->open_count = 0;
|
||||||
|
dev->end = UINT64_C(0);
|
||||||
|
memset(dev->pvid, 0, sizeof(dev->pvid));
|
||||||
|
list_init(&dev->open_list);
|
||||||
|
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return 1 if we prefer path1 else return 0 */
|
||||||
|
static int _compare_paths(const char *path0, const char *path1)
|
||||||
|
{
|
||||||
|
int slash0 = 0, slash1 = 0;
|
||||||
|
const char *p;
|
||||||
|
char p0[PATH_MAX], p1[PATH_MAX];
|
||||||
|
char *s0, *s1;
|
||||||
|
struct stat stat0, stat1;
|
||||||
|
|
||||||
|
/* Return the path with fewer slashes */
|
||||||
|
for (p = path0; p++; p = (const char *) strchr(p, '/'))
|
||||||
|
slash0++;
|
||||||
|
|
||||||
|
for (p = path1; p++; p = (const char *) strchr(p, '/'))
|
||||||
|
slash1++;
|
||||||
|
|
||||||
|
if (slash0 < slash1)
|
||||||
|
return 0;
|
||||||
|
if (slash1 < slash0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
strncpy(p0, path0, PATH_MAX);
|
||||||
|
strncpy(p1, path1, PATH_MAX);
|
||||||
|
s0 = &p0[0] + 1;
|
||||||
|
s1 = &p1[0] + 1;
|
||||||
|
|
||||||
|
/* We prefer symlinks - they exist for a reason!
|
||||||
|
* So we prefer a shorter path before the first symlink in the name.
|
||||||
|
* FIXME Configuration option to invert this? */
|
||||||
|
while (s0) {
|
||||||
|
s0 = strchr(s0, '/');
|
||||||
|
s1 = strchr(s1, '/');
|
||||||
|
if (s0) {
|
||||||
|
*s0 = '\0';
|
||||||
|
*s1 = '\0';
|
||||||
|
}
|
||||||
|
if (lstat(p0, &stat0)) {
|
||||||
|
log_sys_error("lstat", p0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (lstat(p1, &stat1)) {
|
||||||
|
log_sys_error("lstat", p1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (S_ISLNK(stat0.st_mode) && !S_ISLNK(stat1.st_mode))
|
||||||
|
return 0;
|
||||||
|
if (!S_ISLNK(stat0.st_mode) && S_ISLNK(stat1.st_mode))
|
||||||
|
return 1;
|
||||||
|
if (s0) {
|
||||||
|
*s0++ = '/';
|
||||||
|
*s1++ = '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ASCII comparison */
|
||||||
|
if (strcmp(path0, path1) < 0)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int _add_alias(struct device *dev, const char *path)
|
static int _add_alias(struct device *dev, const char *path)
|
||||||
{
|
{
|
||||||
struct str_list *sl = _alloc(sizeof(*sl));
|
struct str_list *sl = _alloc(sizeof(*sl));
|
||||||
|
struct list *ah;
|
||||||
|
const char *oldpath;
|
||||||
|
int prefer_old = 1;
|
||||||
|
|
||||||
if (!sl) {
|
if (!sl) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Is name already there? */
|
||||||
|
list_iterate(ah, &dev->aliases) {
|
||||||
|
if (!strcmp(list_item(ah, struct str_list)->str, path)) {
|
||||||
|
stack;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!(sl->str = pool_strdup(_cache.mem, path))) {
|
if (!(sl->str = pool_strdup(_cache.mem, path))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_add(&dev->aliases, &sl->list);
|
if (!list_empty(&dev->aliases)) {
|
||||||
|
oldpath = list_item(dev->aliases.n, struct str_list)->str;
|
||||||
|
prefer_old = _compare_paths(path, oldpath);
|
||||||
|
log_debug("%s: Aliased to %s in device cache%s",
|
||||||
|
path, oldpath, prefer_old ? "" : " (preferred name)");
|
||||||
|
|
||||||
|
} else
|
||||||
|
log_debug("%s: Added to device cache", path);
|
||||||
|
|
||||||
|
if (prefer_old)
|
||||||
|
list_add(&dev->aliases, &sl->list);
|
||||||
|
else
|
||||||
|
list_add_h(&dev->aliases, &sl->list);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,14 +220,15 @@ static int _insert_dev(const char *path, dev_t d)
|
|||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
|
||||||
/* is this device already registered ? */
|
/* is this device already registered ? */
|
||||||
if (!(dev = (struct device *) btree_lookup(_cache.devices, d))) {
|
if (!(dev = (struct device *) btree_lookup(_cache.devices,
|
||||||
|
(uint32_t) d))) {
|
||||||
/* create new device */
|
/* create new device */
|
||||||
if (!(dev = _create_dev(d))) {
|
if (!(dev = _dev_create(d))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(btree_insert(_cache.devices, d, dev))) {
|
if (!(btree_insert(_cache.devices, (uint32_t) d, dev))) {
|
||||||
log_err("Couldn't insert device into binary tree.");
|
log_err("Couldn't insert device into binary tree.");
|
||||||
_free(dev);
|
_free(dev);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -122,7 +250,7 @@ static int _insert_dev(const char *path, dev_t d)
|
|||||||
|
|
||||||
static char *_join(const char *dir, const char *name)
|
static char *_join(const char *dir, const char *name)
|
||||||
{
|
{
|
||||||
int len = strlen(dir) + strlen(name) + 2;
|
size_t len = strlen(dir) + strlen(name) + 2;
|
||||||
char *r = dbg_malloc(len);
|
char *r = dbg_malloc(len);
|
||||||
if (r)
|
if (r)
|
||||||
snprintf(r, len, "%s/%s", dir, name);
|
snprintf(r, len, "%s/%s", dir, name);
|
||||||
@@ -194,6 +322,17 @@ static int _insert(const char *path, int rec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (S_ISDIR(info.st_mode)) { /* add a directory */
|
if (S_ISDIR(info.st_mode)) { /* add a directory */
|
||||||
|
/* check it's not a symbolic link */
|
||||||
|
if (lstat(path, &info) < 0) {
|
||||||
|
log_sys_very_verbose("lstat", path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISLNK(info.st_mode)) {
|
||||||
|
log_debug("%s: Symbolic link to directory", path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (rec)
|
if (rec)
|
||||||
r = _insert_dir(path);
|
r = _insert_dir(path);
|
||||||
|
|
||||||
@@ -229,6 +368,21 @@ static void _full_scan(void)
|
|||||||
_cache.has_scanned = 1;
|
_cache.has_scanned = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dev_cache_has_scanned(void)
|
||||||
|
{
|
||||||
|
return _cache.has_scanned;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dev_cache_scan(int do_scan)
|
||||||
|
{
|
||||||
|
if (!do_scan)
|
||||||
|
_cache.has_scanned = 1;
|
||||||
|
else {
|
||||||
|
_cache.has_scanned = 0;
|
||||||
|
_full_scan();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int dev_cache_init(void)
|
int dev_cache_init(void)
|
||||||
{
|
{
|
||||||
_cache.names = NULL;
|
_cache.names = NULL;
|
||||||
@@ -259,7 +413,7 @@ int dev_cache_init(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _check_closed(struct device *dev)
|
static void _check_closed(struct device *dev)
|
||||||
{
|
{
|
||||||
if (dev->fd >= 0)
|
if (dev->fd >= 0)
|
||||||
log_err("Device '%s' has been left open.", dev_name(dev));
|
log_err("Device '%s' has been left open.", dev_name(dev));
|
||||||
@@ -272,11 +426,22 @@ static inline void _check_for_open_devices(void)
|
|||||||
|
|
||||||
void dev_cache_exit(void)
|
void dev_cache_exit(void)
|
||||||
{
|
{
|
||||||
_check_for_open_devices();
|
|
||||||
|
|
||||||
pool_destroy(_cache.mem);
|
|
||||||
if (_cache.names)
|
if (_cache.names)
|
||||||
|
_check_for_open_devices();
|
||||||
|
|
||||||
|
if (_cache.mem) {
|
||||||
|
pool_destroy(_cache.mem);
|
||||||
|
_cache.mem = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cache.names) {
|
||||||
hash_destroy(_cache.names);
|
hash_destroy(_cache.names);
|
||||||
|
_cache.names = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cache.devices = NULL;
|
||||||
|
_cache.has_scanned = 0;
|
||||||
|
list_init(&_cache.dirs);
|
||||||
}
|
}
|
||||||
|
|
||||||
int dev_cache_add_dir(const char *path)
|
int dev_cache_add_dir(const char *path)
|
||||||
@@ -295,8 +460,10 @@ int dev_cache_add_dir(const char *path)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1)))
|
if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) {
|
||||||
|
log_error("dir_list allocation failed");
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
strcpy(dl->dir, path);
|
strcpy(dl->dir, path);
|
||||||
list_add(&_cache.dirs, &dl->list);
|
list_add(&_cache.dirs, &dl->list);
|
||||||
@@ -305,20 +472,31 @@ int dev_cache_add_dir(const char *path)
|
|||||||
|
|
||||||
/* Check cached device name is still valid before returning it */
|
/* Check cached device name is still valid before returning it */
|
||||||
/* This should be a rare occurrence */
|
/* This should be a rare occurrence */
|
||||||
|
/* set quiet if the cache is expected to be out-of-date */
|
||||||
/* FIXME Make rest of code pass/cache struct device instead of dev_name */
|
/* FIXME Make rest of code pass/cache struct device instead of dev_name */
|
||||||
const char *dev_name_confirmed(struct device *dev)
|
const char *dev_name_confirmed(struct device *dev, int quiet)
|
||||||
{
|
{
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
char *name;
|
const char *name;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
while ((r = stat(name = list_item(dev->aliases.n,
|
while ((r = stat(name = list_item(dev->aliases.n,
|
||||||
struct str_list)->str, &buf)) ||
|
struct str_list)->str, &buf)) ||
|
||||||
(buf.st_rdev != dev->dev)) {
|
(buf.st_rdev != dev->dev)) {
|
||||||
if (r < 0)
|
if (r < 0) {
|
||||||
log_sys_error("stat", name);
|
if (quiet)
|
||||||
log_error("Path %s no longer valid for device(%d,%d)",
|
log_sys_debug("stat", name);
|
||||||
name, (int) MAJOR(dev->dev), (int) MINOR(dev->dev));
|
else
|
||||||
|
log_sys_error("stat", name);
|
||||||
|
}
|
||||||
|
if (quiet)
|
||||||
|
log_debug("Path %s no longer valid for device(%d,%d)",
|
||||||
|
name, (int) MAJOR(dev->dev),
|
||||||
|
(int) MINOR(dev->dev));
|
||||||
|
else
|
||||||
|
log_error("Path %s no longer valid for device(%d,%d)",
|
||||||
|
name, (int) MAJOR(dev->dev),
|
||||||
|
(int) MINOR(dev->dev));
|
||||||
|
|
||||||
/* Remove the incorrect hash entry */
|
/* Remove the incorrect hash entry */
|
||||||
hash_remove(_cache.names, name);
|
hash_remove(_cache.names, name);
|
||||||
@@ -364,8 +542,10 @@ struct dev_iter *dev_iter_create(struct dev_filter *f)
|
|||||||
{
|
{
|
||||||
struct dev_iter *di = dbg_malloc(sizeof(*di));
|
struct dev_iter *di = dbg_malloc(sizeof(*di));
|
||||||
|
|
||||||
if (!di)
|
if (!di) {
|
||||||
|
log_error("dev_iter allocation failed");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
_full_scan();
|
_full_scan();
|
||||||
di->current = btree_first(_cache.devices);
|
di->current = btree_first(_cache.devices);
|
||||||
|
|||||||
@@ -1,13 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the GPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_DEV_CACHE_H
|
#ifndef _LVM_DEV_CACHE_H
|
||||||
#define _LVM_DEV_CACHE_H
|
#define _LVM_DEV_CACHE_H
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include "lvm-types.h"
|
#include "lvm-types.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
|
||||||
@@ -15,22 +23,24 @@
|
|||||||
* predicate for devices.
|
* predicate for devices.
|
||||||
*/
|
*/
|
||||||
struct dev_filter {
|
struct dev_filter {
|
||||||
int (*passes_filter)(struct dev_filter *f, struct device *dev);
|
int (*passes_filter) (struct dev_filter * f, struct device * dev);
|
||||||
void (*destroy)(struct dev_filter *f);
|
void (*destroy) (struct dev_filter * f);
|
||||||
void *private;
|
void *private;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The global device cache.
|
* The global device cache.
|
||||||
*/
|
*/
|
||||||
int dev_cache_init(void);
|
int dev_cache_init(void);
|
||||||
void dev_cache_exit(void);
|
void dev_cache_exit(void);
|
||||||
|
|
||||||
|
/* Trigger(1) or avoid(0) a scan */
|
||||||
|
void dev_cache_scan(int do_scan);
|
||||||
|
int dev_cache_has_scanned(void);
|
||||||
|
|
||||||
int dev_cache_add_dir(const char *path);
|
int dev_cache_add_dir(const char *path);
|
||||||
struct device *dev_cache_get(const char *name, struct dev_filter *f);
|
struct device *dev_cache_get(const char *name, struct dev_filter *f);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Object for iterating through the cache.
|
* Object for iterating through the cache.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,24 +1,226 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "device.h"
|
#include "lib.h"
|
||||||
#include "lvm-types.h"
|
#include "lvm-types.h"
|
||||||
#include "log.h"
|
#include "device.h"
|
||||||
|
#include "metadata.h"
|
||||||
|
#include "lvmcache.h"
|
||||||
|
#include "memlock.h"
|
||||||
|
#include "locking.h"
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <limits.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <linux/fs.h> // UGH!!! for BLKSSZGET
|
|
||||||
|
|
||||||
int dev_get_size(struct device *dev, uint64_t * size)
|
#ifdef linux
|
||||||
|
# define u64 uint64_t /* Missing without __KERNEL__ */
|
||||||
|
# undef WNOHANG /* Avoid redefinition */
|
||||||
|
# undef WUNTRACED /* Avoid redefinition */
|
||||||
|
# include <linux/fs.h> /* For block ioctl definitions */
|
||||||
|
# define BLKSIZE_SHIFT SECTOR_SHIFT
|
||||||
|
# ifndef BLKGETSIZE64 /* fs.h out-of-date */
|
||||||
|
# define BLKGETSIZE64 _IOR(0x12, 114, size_t)
|
||||||
|
# endif /* BLKGETSIZE64 */
|
||||||
|
#else
|
||||||
|
# include <sys/disk.h>
|
||||||
|
# define BLKBSZGET DKIOCGETBLOCKSIZE
|
||||||
|
# define BLKSSZGET DKIOCGETBLOCKSIZE
|
||||||
|
# define BLKGETSIZE64 DKIOCGETBLOCKCOUNT
|
||||||
|
# define BLKFLSBUF DKIOCSYNCHRONIZECACHE
|
||||||
|
# define BLKSIZE_SHIFT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef O_DIRECT_SUPPORT
|
||||||
|
# ifndef O_DIRECT
|
||||||
|
# error O_DIRECT support configured but O_DIRECT definition not found in headers
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* FIXME Use _llseek for 64-bit
|
||||||
|
_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh);
|
||||||
|
if (_llseek((unsigned) fd, (ulong) (offset >> 32), (ulong) (offset & 0xFFFFFFFF), &pos, SEEK_SET) < 0) {
|
||||||
|
*/
|
||||||
|
|
||||||
|
static LIST_INIT(_open_devices);
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------
|
||||||
|
* The standard io loop that keeps submitting an io until it's
|
||||||
|
* all gone.
|
||||||
|
*---------------------------------------------------------------*/
|
||||||
|
static int _io(struct device_area *where, void *buffer, int should_write)
|
||||||
|
{
|
||||||
|
int fd = dev_fd(where->dev);
|
||||||
|
ssize_t n = 0;
|
||||||
|
size_t total = 0;
|
||||||
|
|
||||||
|
if (fd < 0) {
|
||||||
|
log_error("Attempt to read an unopened device (%s).",
|
||||||
|
dev_name(where->dev));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip all writes in test mode.
|
||||||
|
*/
|
||||||
|
if (should_write && test_mode())
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (where->size > SSIZE_MAX) {
|
||||||
|
log_error("Read size too large: %" PRIu64, where->size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lseek(fd, (off_t) where->start, SEEK_SET) < 0) {
|
||||||
|
log_sys_error("lseek", dev_name(where->dev));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (total < (size_t) where->size) {
|
||||||
|
do
|
||||||
|
n = should_write ?
|
||||||
|
write(fd, buffer, (size_t) where->size - total) :
|
||||||
|
read(fd, buffer, (size_t) where->size - total);
|
||||||
|
while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
|
||||||
|
|
||||||
|
if (n <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
total += n;
|
||||||
|
buffer += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (total == (size_t) where->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------
|
||||||
|
* LVM2 uses O_DIRECT when performing metadata io, which requires
|
||||||
|
* block size aligned accesses. If any io is not aligned we have
|
||||||
|
* to perform the io via a bounce buffer, obviously this is quite
|
||||||
|
* inefficient.
|
||||||
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the sector size from an _open_ device.
|
||||||
|
*/
|
||||||
|
static int _get_block_size(struct device *dev, unsigned int *size)
|
||||||
|
{
|
||||||
|
int s;
|
||||||
|
|
||||||
|
if (ioctl(dev_fd(dev), BLKBSZGET, &s) < 0) {
|
||||||
|
log_sys_error("ioctl BLKBSZGET", dev_name(dev));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*size = (unsigned int) s;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Widens a region to be an aligned region.
|
||||||
|
*/
|
||||||
|
static void _widen_region(unsigned int block_size, struct device_area *region,
|
||||||
|
struct device_area *result)
|
||||||
|
{
|
||||||
|
uint64_t mask = block_size - 1, delta;
|
||||||
|
memcpy(result, region, sizeof(*result));
|
||||||
|
|
||||||
|
/* adjust the start */
|
||||||
|
delta = result->start & mask;
|
||||||
|
if (delta) {
|
||||||
|
result->start -= delta;
|
||||||
|
result->size += delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* adjust the end */
|
||||||
|
delta = (result->start + result->size) & mask;
|
||||||
|
if (delta)
|
||||||
|
result->size += block_size - delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _aligned_io(struct device_area *where, void *buffer,
|
||||||
|
int should_write)
|
||||||
|
{
|
||||||
|
void *bounce;
|
||||||
|
unsigned int block_size = 0;
|
||||||
|
uintptr_t mask;
|
||||||
|
struct device_area widened;
|
||||||
|
|
||||||
|
if (!(where->dev->flags & DEV_REGULAR) &&
|
||||||
|
!_get_block_size(where->dev, &block_size)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!block_size)
|
||||||
|
block_size = getpagesize();
|
||||||
|
|
||||||
|
_widen_region(block_size, where, &widened);
|
||||||
|
|
||||||
|
/* Do we need to use a bounce buffer? */
|
||||||
|
mask = block_size - 1;
|
||||||
|
if (!memcmp(where, &widened, sizeof(widened)) &&
|
||||||
|
!((uintptr_t) buffer & mask))
|
||||||
|
return _io(where, buffer, should_write);
|
||||||
|
|
||||||
|
/* Allocate a bounce buffer with an extra block */
|
||||||
|
if (!(bounce = alloca((size_t) widened.size + block_size))) {
|
||||||
|
log_error("Bounce buffer alloca failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Realign start of bounce buffer (using the extra sector)
|
||||||
|
*/
|
||||||
|
if (((uintptr_t) bounce) & mask)
|
||||||
|
bounce = (void *) ((((uintptr_t) bounce) + mask) & ~mask);
|
||||||
|
|
||||||
|
/* channel the io through the bounce buffer */
|
||||||
|
if (!_io(&widened, bounce, 0)) {
|
||||||
|
if (!should_write) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* FIXME pre-extend the file */
|
||||||
|
memset(bounce, '\n', widened.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (should_write) {
|
||||||
|
memcpy(bounce + (where->start - widened.start), buffer,
|
||||||
|
(size_t) where->size);
|
||||||
|
|
||||||
|
/* ... then we write */
|
||||||
|
return _io(&widened, bounce, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buffer, bounce + (where->start - widened.start),
|
||||||
|
(size_t) where->size);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------
|
||||||
|
* Public functions
|
||||||
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
|
int dev_get_size(struct device *dev, uint64_t *size)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
long s;
|
|
||||||
const char *name = dev_name(dev);
|
const char *name = dev_name(dev);
|
||||||
|
|
||||||
log_very_verbose("Getting size of %s", name);
|
log_very_verbose("Getting size of %s", name);
|
||||||
@@ -27,19 +229,18 @@ int dev_get_size(struct device *dev, uint64_t * size)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: add 64 bit ioctl */
|
if (ioctl(fd, BLKGETSIZE64, size) < 0) {
|
||||||
if (ioctl(fd, BLKGETSIZE, &s) < 0) {
|
log_sys_error("ioctl BLKGETSIZE64", name);
|
||||||
log_sys_error("ioctl BLKGETSIZE", name);
|
|
||||||
close(fd);
|
close(fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*size >>= BLKSIZE_SHIFT; /* Convert to sectors */
|
||||||
close(fd);
|
close(fd);
|
||||||
*size = (uint64_t) s;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dev_get_sectsize(struct device *dev, uint32_t * size)
|
int dev_get_sectsize(struct device *dev, uint32_t *size)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
int s;
|
int s;
|
||||||
@@ -62,48 +263,116 @@ int dev_get_sectsize(struct device *dev, uint32_t * size)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dev_open(struct device *dev, int flags)
|
void dev_flush(struct device *dev)
|
||||||
|
{
|
||||||
|
if (!(dev->flags & DEV_REGULAR) && ioctl(dev->fd, BLKFLSBUF, 0) >= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (fsync(dev->fd) >= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
|
||||||
{
|
{
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
const char *name = dev_name_confirmed(dev);
|
const char *name;
|
||||||
|
|
||||||
if (!name) {
|
if (dev->fd >= 0) {
|
||||||
|
dev->open_count++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memlock())
|
||||||
|
log_error("WARNING: dev_open(%s) called while suspended",
|
||||||
|
dev_name(dev));
|
||||||
|
|
||||||
|
if (dev->flags & DEV_REGULAR)
|
||||||
|
name = dev_name(dev);
|
||||||
|
else if (!(name = dev_name_confirmed(dev, quiet))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev->fd >= 0) {
|
if (!(dev->flags & DEV_REGULAR) &&
|
||||||
log_error("Device '%s' has already been opened", name);
|
((stat(name, &buf) < 0) || (buf.st_rdev != dev->dev))) {
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((stat(name, &buf) < 0) || (buf.st_rdev != dev->dev)) {
|
|
||||||
log_error("%s: stat failed: Has device name changed?", name);
|
log_error("%s: stat failed: Has device name changed?", name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((dev->fd = open(name, flags)) < 0) {
|
#ifdef O_DIRECT_SUPPORT
|
||||||
|
if (direct)
|
||||||
|
flags |= O_DIRECT;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((dev->fd = open(name, flags, 0777)) < 0) {
|
||||||
log_sys_error("open", name);
|
log_sys_error("open", name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fstat(dev->fd, &buf) < 0) || (buf.st_rdev != dev->dev)) {
|
dev->open_count = 1;
|
||||||
|
dev->flags &= ~DEV_ACCESSED_W;
|
||||||
|
|
||||||
|
if (!(dev->flags & DEV_REGULAR) &&
|
||||||
|
((fstat(dev->fd, &buf) < 0) || (buf.st_rdev != dev->dev))) {
|
||||||
log_error("%s: fstat failed: Has device name changed?", name);
|
log_error("%s: fstat failed: Has device name changed?", name);
|
||||||
dev_close(dev);
|
dev_close(dev);
|
||||||
|
dev->fd = -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->flags = 0;
|
#ifndef O_DIRECT_SUPPORT
|
||||||
|
if (!(dev->flags & DEV_REGULAR))
|
||||||
|
dev_flush(dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((flags & O_CREAT) && !(flags & O_TRUNC)) {
|
||||||
|
dev->end = lseek(dev->fd, (off_t) 0, SEEK_END);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add(&_open_devices, &dev->open_list);
|
||||||
|
log_debug("Opened %s", dev_name(dev));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _flush(int fd)
|
int dev_open_quiet(struct device *dev)
|
||||||
{
|
{
|
||||||
ioctl(fd, BLKFLSBUF, 0);
|
int flags;
|
||||||
|
|
||||||
|
flags = vg_write_lock_held() ? O_RDWR : O_RDONLY;
|
||||||
|
|
||||||
|
return dev_open_flags(dev, flags, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int dev_close(struct device *dev)
|
int dev_open(struct device *dev)
|
||||||
|
{
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
flags = vg_write_lock_held() ? O_RDWR : O_RDONLY;
|
||||||
|
|
||||||
|
return dev_open_flags(dev, flags, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _close(struct device *dev)
|
||||||
|
{
|
||||||
|
if (close(dev->fd))
|
||||||
|
log_sys_error("close", dev_name(dev));
|
||||||
|
dev->fd = -1;
|
||||||
|
list_del(&dev->open_list);
|
||||||
|
|
||||||
|
log_debug("Closed %s", dev_name(dev));
|
||||||
|
|
||||||
|
if (dev->flags & DEV_ALLOCED) {
|
||||||
|
dbg_free((void *) list_item(dev->aliases.n, struct str_list)->
|
||||||
|
str);
|
||||||
|
dbg_free(dev->aliases.n);
|
||||||
|
dbg_free(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _dev_close(struct device *dev, int immediate)
|
||||||
{
|
{
|
||||||
if (dev->fd < 0) {
|
if (dev->fd < 0) {
|
||||||
log_error("Attempt to close device '%s' "
|
log_error("Attempt to close device '%s' "
|
||||||
@@ -111,139 +380,127 @@ int dev_close(struct device *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef O_DIRECT_SUPPORT
|
||||||
if (dev->flags & DEV_ACCESSED_W)
|
if (dev->flags & DEV_ACCESSED_W)
|
||||||
_flush(dev->fd);
|
dev_flush(dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (close(dev->fd))
|
/* FIXME lookup device in cache to get vgname and see if it's locked? */
|
||||||
log_sys_error("close", dev_name(dev));
|
if (--dev->open_count < 1 && (immediate || !vgs_locked()))
|
||||||
|
_close(dev);
|
||||||
dev->fd = -1;
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
int dev_close(struct device *dev)
|
||||||
* FIXME: factor common code out.
|
{
|
||||||
|
return _dev_close(dev, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dev_close_immediate(struct device *dev)
|
||||||
|
{
|
||||||
|
return _dev_close(dev, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dev_close_all(void)
|
||||||
|
{
|
||||||
|
struct list *doh, *doht;
|
||||||
|
struct device *dev;
|
||||||
|
|
||||||
|
list_iterate_safe(doh, doht, &_open_devices) {
|
||||||
|
dev = list_struct_base(doh, struct device, open_list);
|
||||||
|
if (dev->open_count < 1)
|
||||||
|
_close(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer)
|
||||||
|
{
|
||||||
|
struct device_area where;
|
||||||
|
|
||||||
|
if (!dev->open_count)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
where.dev = dev;
|
||||||
|
where.start = offset;
|
||||||
|
where.size = len;
|
||||||
|
|
||||||
|
return _aligned_io(&where, buffer, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME If O_DIRECT can't extend file, dev_extend first; dev_truncate after.
|
||||||
|
* But fails if concurrent processes writing
|
||||||
*/
|
*/
|
||||||
int _read(int fd, void *buf, size_t count)
|
|
||||||
|
/* FIXME pre-extend the file */
|
||||||
|
int dev_append(struct device *dev, size_t len, void *buffer)
|
||||||
{
|
{
|
||||||
size_t n = 0;
|
int r;
|
||||||
int tot = 0;
|
|
||||||
|
|
||||||
while (tot < count) {
|
if (!dev->open_count)
|
||||||
do
|
return 0;
|
||||||
n = read(fd, buf, count - tot);
|
|
||||||
while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
|
|
||||||
|
|
||||||
if (n <= 0)
|
r = dev_write(dev, dev->end, len, buffer);
|
||||||
return tot ? tot : n;
|
dev->end += (uint64_t) len;
|
||||||
|
|
||||||
tot += n;
|
#ifndef O_DIRECT_SUPPORT
|
||||||
buf += n;
|
dev_flush(dev);
|
||||||
}
|
#endif
|
||||||
|
return r;
|
||||||
return tot;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t dev_read(struct device * dev, uint64_t offset,
|
int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer)
|
||||||
int64_t len, void *buffer)
|
|
||||||
{
|
{
|
||||||
const char *name = dev_name(dev);
|
struct device_area where;
|
||||||
int fd = dev->fd;
|
|
||||||
|
|
||||||
if (fd < 0) {
|
if (!dev->open_count)
|
||||||
log_err("Attempt to read an unopened device (%s).", name);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
if (lseek(fd, offset, SEEK_SET) < 0) {
|
where.dev = dev;
|
||||||
log_sys_error("lseek", name);
|
where.start = offset;
|
||||||
return 0;
|
where.size = len;
|
||||||
}
|
|
||||||
|
|
||||||
return _read(fd, buffer, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
int _write(int fd, const void *buf, size_t count)
|
|
||||||
{
|
|
||||||
size_t n = 0;
|
|
||||||
int tot = 0;
|
|
||||||
|
|
||||||
/* Skip all writes */
|
|
||||||
if (test_mode())
|
|
||||||
return count;
|
|
||||||
|
|
||||||
while (tot < count) {
|
|
||||||
do
|
|
||||||
n = write(fd, buf, count - tot);
|
|
||||||
while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
|
|
||||||
|
|
||||||
if (n <= 0)
|
|
||||||
return tot ? tot : n;
|
|
||||||
|
|
||||||
tot += n;
|
|
||||||
buf += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tot;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t dev_write(struct device * dev, uint64_t offset,
|
|
||||||
int64_t len, void *buffer)
|
|
||||||
{
|
|
||||||
const char *name = dev_name(dev);
|
|
||||||
int fd = dev->fd;
|
|
||||||
|
|
||||||
if (fd < 0) {
|
|
||||||
log_error("Attempt to write to unopened device %s", name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lseek(fd, offset, SEEK_SET) < 0) {
|
|
||||||
log_sys_error("lseek", name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->flags |= DEV_ACCESSED_W;
|
dev->flags |= DEV_ACCESSED_W;
|
||||||
|
|
||||||
return _write(fd, buffer, len);
|
return _aligned_io(&where, buffer, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int dev_zero(struct device *dev, uint64_t offset, int64_t len)
|
int dev_zero(struct device *dev, uint64_t offset, size_t len)
|
||||||
{
|
{
|
||||||
int64_t r, s;
|
size_t s;
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
const char *name = dev_name(dev);
|
|
||||||
int fd = dev->fd;
|
|
||||||
|
|
||||||
if (fd < 0) {
|
if (!dev_open(dev)) {
|
||||||
log_error("Attempt to zero part of an unopened device %s",
|
stack;
|
||||||
name);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lseek(fd, offset, SEEK_SET) < 0) {
|
if ((offset % SECTOR_SIZE) || (len % SECTOR_SIZE))
|
||||||
log_sys_error("lseek", name);
|
log_debug("Wiping %s at %" PRIu64 " length %" PRIsize_t,
|
||||||
return 0;
|
dev_name(dev), offset, len);
|
||||||
}
|
else
|
||||||
|
log_debug("Wiping %s at sector %" PRIu64 " length %" PRIsize_t
|
||||||
|
" sectors", dev_name(dev), offset >> SECTOR_SHIFT,
|
||||||
|
len >> SECTOR_SHIFT);
|
||||||
|
|
||||||
memset(buffer, 0, sizeof(buffer));
|
memset(buffer, 0, sizeof(buffer));
|
||||||
while (1) {
|
while (1) {
|
||||||
s = len > sizeof(buffer) ? sizeof(buffer) : len;
|
s = len > sizeof(buffer) ? sizeof(buffer) : len;
|
||||||
r = _write(fd, buffer, s);
|
if (!dev_write(dev, offset, s, buffer))
|
||||||
|
|
||||||
if (r <= 0)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
len -= r;
|
len -= s;
|
||||||
if (!len) {
|
if (!len)
|
||||||
r = 1;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
offset += s;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->flags |= DEV_ACCESSED_W;
|
dev->flags |= DEV_ACCESSED_W;
|
||||||
|
|
||||||
|
if (!dev_close(dev))
|
||||||
|
stack;
|
||||||
|
|
||||||
/* FIXME: Always display error */
|
/* FIXME: Always display error */
|
||||||
return (len == 0);
|
return (len == 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,31 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This LVM library is free software; you can redistribute it and/or
|
* This file is part of LVM2.
|
||||||
* modify it under the terms of the GNU Library General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
*
|
||||||
* This LVM library is distributed in the hope that it will be useful,
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* of the GNU General Public License v.2.
|
||||||
* Library General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Library General Public
|
* You should have received a copy of the GNU General Public License
|
||||||
* License along with this LVM library; if not, write to the Free
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
* MA 02111-1307, USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/types.h>
|
#if 0
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/major.h>
|
||||||
|
#include <linux/genhd.h>
|
||||||
|
|
||||||
#include "dbg_malloc.h"
|
#include "dbg_malloc.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@@ -34,11 +33,6 @@
|
|||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/major.h>
|
|
||||||
#include <linux/genhd.h>
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
int _get_partition_type(struct dev_filter *filter, struct device *d);
|
int _get_partition_type(struct dev_filter *filter, struct device *d);
|
||||||
|
|
||||||
#define MINOR_PART(dm, d) (MINOR((d)->dev) % dev_max_partitions(dm, (d)->dev))
|
#define MINOR_PART(dm, d) (MINOR((d)->dev) % dev_max_partitions(dm, (d)->dev))
|
||||||
|
|||||||
@@ -1,28 +1,44 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the GPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_DEVICE_H
|
#ifndef _LVM_DEVICE_H
|
||||||
#define _LVM_DEVICE_H
|
#define _LVM_DEVICE_H
|
||||||
|
|
||||||
#include "lvm-types.h"
|
#include "uuid.h"
|
||||||
#include "list.h"
|
#include <fcntl.h>
|
||||||
|
|
||||||
#define DEV_ACCESSED_W 0x00000001 /* Device written to? */
|
#define DEV_ACCESSED_W 0x00000001 /* Device written to? */
|
||||||
|
#define DEV_REGULAR 0x00000002 /* Regular file? */
|
||||||
|
#define DEV_ALLOCED 0x00000004 /* dbg_malloc used */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All devices in LVM will be represented by one of these.
|
* All devices in LVM will be represented by one of these.
|
||||||
* pointer comparisons are valid.
|
* pointer comparisons are valid.
|
||||||
*/
|
*/
|
||||||
struct device {
|
struct device {
|
||||||
struct list aliases; /* struct str_list from lvm-types.h */
|
struct list aliases; /* struct str_list from lvm-types.h */
|
||||||
dev_t dev;
|
dev_t dev;
|
||||||
|
|
||||||
/* private */
|
/* private */
|
||||||
int fd;
|
int fd;
|
||||||
|
int open_count;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
|
uint64_t end;
|
||||||
|
struct list open_list;
|
||||||
|
|
||||||
|
char pvid[ID_LEN + 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct device_list {
|
struct device_list {
|
||||||
@@ -30,33 +46,58 @@ struct device_list {
|
|||||||
struct device *dev;
|
struct device *dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct device_area {
|
||||||
|
struct device *dev;
|
||||||
|
uint64_t start; /* Bytes */
|
||||||
|
uint64_t size; /* Bytes */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All io should use these routines.
|
* All io should use these routines.
|
||||||
*/
|
*/
|
||||||
int dev_get_size(struct device *dev, uint64_t *size);
|
int dev_get_size(struct device *dev, uint64_t *size);
|
||||||
int dev_get_sectsize(struct device *dev, uint32_t *size);
|
int dev_get_sectsize(struct device *dev, uint32_t *size);
|
||||||
|
|
||||||
int dev_open(struct device *dev, int flags);
|
/* Use quiet version if device number could change e.g. when opening LV */
|
||||||
|
int dev_open(struct device *dev);
|
||||||
|
int dev_open_quiet(struct device *dev);
|
||||||
|
int dev_open_flags(struct device *dev, int flags, int append, int quiet);
|
||||||
int dev_close(struct device *dev);
|
int dev_close(struct device *dev);
|
||||||
|
int dev_close_immediate(struct device *dev);
|
||||||
|
void dev_close_all(void);
|
||||||
|
|
||||||
int64_t dev_read(struct device *dev,
|
static inline int dev_fd(struct device *dev)
|
||||||
uint64_t offset, int64_t len, void *buffer);
|
{
|
||||||
int64_t dev_write(struct device *dev,
|
return dev->fd;
|
||||||
uint64_t offset, int64_t len, void *buffer);
|
}
|
||||||
int dev_zero(struct device *dev, uint64_t offset, int64_t len);
|
|
||||||
|
|
||||||
|
int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer);
|
||||||
|
int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer);
|
||||||
|
int dev_append(struct device *dev, size_t len, void *buffer);
|
||||||
|
int dev_zero(struct device *dev, uint64_t offset, size_t len);
|
||||||
|
void dev_flush(struct device *dev);
|
||||||
|
|
||||||
static inline const char *dev_name(struct device *dev) {
|
struct device *dev_create_file(const char *filename, struct device *dev,
|
||||||
|
struct str_list *alias);
|
||||||
|
|
||||||
|
static inline const char *dev_name(const struct device *dev)
|
||||||
|
{
|
||||||
return (dev) ? list_item(dev->aliases.n, struct str_list)->str :
|
return (dev) ? list_item(dev->aliases.n, struct str_list)->str :
|
||||||
"unknown device";
|
"unknown device";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return a valid device name from the alias list; NULL otherwise */
|
/* Return a valid device name from the alias list; NULL otherwise */
|
||||||
const char *dev_name_confirmed(struct device *dev);
|
const char *dev_name_confirmed(struct device *dev, int quiet);
|
||||||
|
|
||||||
static inline int is_lvm_partition(const char *name) {
|
/* FIXME Check partition type if appropriate */
|
||||||
|
|
||||||
|
#define is_lvm_partition(a) 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
static inline int is_lvm_partition(const char *name)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,65 +1,218 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This LVM library is free software; you can redistribute it and/or
|
* This file is part of LVM2.
|
||||||
* modify it under the terms of the GNU Library General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
*
|
||||||
* This LVM library is distributed in the hope that it will be useful,
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* of the GNU General Public License v.2.
|
||||||
* Library General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Library General Public
|
|
||||||
* License along with this LVM library; if not, write to the Free
|
|
||||||
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
||||||
* MA 02111-1307, USA
|
|
||||||
*
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
#include "dbg_malloc.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "activate.h"
|
#include "activate.h"
|
||||||
#include "uuid.h"
|
|
||||||
#include "toolcontext.h"
|
#include "toolcontext.h"
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define SIZE_BUF 128
|
#define SIZE_BUF 128
|
||||||
|
|
||||||
char *display_size(uint64_t size, size_len_t sl)
|
static struct {
|
||||||
|
alloc_policy_t alloc;
|
||||||
|
const char *str;
|
||||||
|
} _policies[] = {
|
||||||
|
{
|
||||||
|
ALLOC_NEXT_FREE, "next free"}, {
|
||||||
|
ALLOC_CONTIGUOUS, "contiguous"}, {
|
||||||
|
ALLOC_DEFAULT, "next free (default)"}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
segment_type_t segtype;
|
||||||
|
const char *str;
|
||||||
|
} _segtypes[] = {
|
||||||
|
{
|
||||||
|
SEG_STRIPED, "striped"}, {
|
||||||
|
SEG_MIRRORED, "mirror"}, {
|
||||||
|
SEG_SNAPSHOT, "snapshot"}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int _num_policies = sizeof(_policies) / sizeof(*_policies);
|
||||||
|
static int _num_segtypes = sizeof(_segtypes) / sizeof(*_segtypes);
|
||||||
|
|
||||||
|
uint64_t units_to_bytes(const char *units, char *unit_type)
|
||||||
|
{
|
||||||
|
char *ptr = NULL;
|
||||||
|
uint64_t v;
|
||||||
|
|
||||||
|
if (isdigit(*units)) {
|
||||||
|
v = (uint64_t) strtod(units, &ptr);
|
||||||
|
if (ptr == units)
|
||||||
|
return 0;
|
||||||
|
units = ptr;
|
||||||
|
} else
|
||||||
|
v = 1;
|
||||||
|
|
||||||
|
if (v == 1)
|
||||||
|
*unit_type = *units;
|
||||||
|
else
|
||||||
|
*unit_type = 'U';
|
||||||
|
|
||||||
|
switch (*units) {
|
||||||
|
case 'h':
|
||||||
|
case 'H':
|
||||||
|
v = UINT64_C(1);
|
||||||
|
*unit_type = *units;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
v *= SECTOR_SIZE;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
case 'B':
|
||||||
|
v *= UINT64_C(1);
|
||||||
|
break;
|
||||||
|
#define KILO UINT64_C(1024)
|
||||||
|
case 'k':
|
||||||
|
v *= KILO;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
v *= KILO * KILO;
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
v *= KILO * KILO * KILO;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
v *= KILO * KILO * KILO * KILO;
|
||||||
|
break;
|
||||||
|
#undef KILO
|
||||||
|
#define KILO UINT64_C(1000)
|
||||||
|
case 'K':
|
||||||
|
v *= KILO;
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
v *= KILO * KILO;
|
||||||
|
break;
|
||||||
|
case 'G':
|
||||||
|
v *= KILO * KILO * KILO;
|
||||||
|
break;
|
||||||
|
case 'T':
|
||||||
|
v *= KILO * KILO * KILO * KILO;
|
||||||
|
break;
|
||||||
|
#undef KILO
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*(units + 1))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *get_alloc_string(alloc_policy_t alloc)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < _num_policies; i++)
|
||||||
|
if (_policies[i].alloc == alloc)
|
||||||
|
return _policies[i].str;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *get_segtype_string(segment_type_t segtype)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < _num_segtypes; i++)
|
||||||
|
if (_segtypes[i].segtype == segtype)
|
||||||
|
return _segtypes[i].str;
|
||||||
|
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
alloc_policy_t get_alloc_from_string(const char *str)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < _num_policies; i++)
|
||||||
|
if (!strcmp(_policies[i].str, str))
|
||||||
|
return _policies[i].alloc;
|
||||||
|
|
||||||
|
log_error("Unrecognised allocation policy - using default");
|
||||||
|
return ALLOC_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
segment_type_t get_segtype_from_string(const char *str)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < _num_segtypes; i++)
|
||||||
|
if (!strcmp(_segtypes[i].str, str))
|
||||||
|
return _segtypes[i].segtype;
|
||||||
|
|
||||||
|
log_error("Unrecognised segment type - using default (striped)");
|
||||||
|
return SEG_STRIPED;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
|
||||||
{
|
{
|
||||||
int s;
|
int s;
|
||||||
ulong byte = 1024 * 1024 * 1024;
|
int suffix = 1;
|
||||||
|
uint64_t byte = UINT64_C(0);
|
||||||
|
uint64_t units = UINT64_C(1024);
|
||||||
char *size_buf = NULL;
|
char *size_buf = NULL;
|
||||||
char *size_str[][2] = {
|
const char *size_str[][3] = {
|
||||||
{"Terabyte", "TB"},
|
{" Terabyte", " TB", "T"},
|
||||||
{"Gigabyte", "GB"},
|
{" Gigabyte", " GB", "G"},
|
||||||
{"Megabyte", "MB"},
|
{" Megabyte", " MB", "M"},
|
||||||
{"Kilobyte", "KB"},
|
{" Kilobyte", " KB", "K"},
|
||||||
{"", ""}
|
{"", "", ""},
|
||||||
|
{" Byte ", " B ", "B"},
|
||||||
|
{" Units ", " Un", "U"},
|
||||||
|
{" Sectors ", " Se", "S"},
|
||||||
|
{" ", " ", " "},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!(size_buf = dbg_malloc(SIZE_BUF))) {
|
if (!(size_buf = pool_alloc(cmd->mem, SIZE_BUF))) {
|
||||||
log_error("no memory for size display buffer");
|
log_error("no memory for size display buffer");
|
||||||
return NULL;
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size == 0LL)
|
suffix = cmd->current_settings.suffix;
|
||||||
sprintf(size_buf, "0");
|
|
||||||
else {
|
for (s = 0; s < 8; s++)
|
||||||
|
if (toupper((int) cmd->current_settings.unit_type) ==
|
||||||
|
*size_str[s][2])
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (size == UINT64_C(0)) {
|
||||||
|
sprintf(size_buf, "0%s", suffix ? size_str[s][sl] : "");
|
||||||
|
return size_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s < 8) {
|
||||||
|
byte = cmd->current_settings.unit_factor;
|
||||||
|
size *= UINT64_C(1024);
|
||||||
|
} else {
|
||||||
|
suffix = 1;
|
||||||
|
if (cmd->current_settings.unit_type == 'H')
|
||||||
|
units = UINT64_C(1000);
|
||||||
|
else
|
||||||
|
units = UINT64_C(1024);
|
||||||
|
byte = units * units * units;
|
||||||
s = 0;
|
s = 0;
|
||||||
while (size_str[s] && size < byte)
|
while (size_str[s] && size < byte)
|
||||||
s++, byte /= 1024;
|
s++, byte /= units;
|
||||||
snprintf(size_buf, SIZE_BUF - 1,
|
|
||||||
"%.2f %s", (float) size / byte, size_str[s][sl]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Caller to deallocate */
|
snprintf(size_buf, SIZE_BUF - 1, "%.2f%s", (float) size / byte,
|
||||||
|
suffix ? size_str[s][sl] : "");
|
||||||
|
|
||||||
return size_buf;
|
return size_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +228,7 @@ void pvdisplay_colons(struct physical_volume *pv)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_print("%s:%s:%" PRIu64 ":-1:%u:%u:-1:%" PRIu64 ":%u:%u:%u:%s",
|
log_print("%s:%s:%" PRIu64 ":-1:%u:%u:-1:%" PRIu32 ":%u:%u:%u:%s",
|
||||||
dev_name(pv->dev), pv->vg_name, pv->size,
|
dev_name(pv->dev), pv->vg_name, pv->size,
|
||||||
/* FIXME pv->pv_number, Derive or remove? */
|
/* FIXME pv->pv_number, Derive or remove? */
|
||||||
pv->status, /* FIXME Support old or new format here? */
|
pv->status, /* FIXME Support old or new format here? */
|
||||||
@@ -89,12 +242,14 @@ void pvdisplay_colons(struct physical_volume *pv)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pvdisplay_full(struct physical_volume *pv)
|
/* FIXME Include label fields */
|
||||||
|
void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
|
||||||
|
void *handle)
|
||||||
{
|
{
|
||||||
char uuid[64];
|
char uuid[64];
|
||||||
char *size, *size1; /*, *size2; */
|
const char *size;
|
||||||
|
|
||||||
uint64_t pe_free;
|
uint32_t pe_free;
|
||||||
|
|
||||||
if (!pv)
|
if (!pv)
|
||||||
return;
|
return;
|
||||||
@@ -104,49 +259,30 @@ void pvdisplay_full(struct physical_volume *pv)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compat */
|
|
||||||
if(!pv->pe_size) {
|
|
||||||
size = display_size((uint64_t) pv->size / 2, SIZE_SHORT);
|
|
||||||
log_print("\"%s\" is a new physical volume of %s", dev_name(pv->dev), size);
|
|
||||||
dbg_free(size);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_cmd_name("");
|
|
||||||
init_msg_prefix("");
|
|
||||||
|
|
||||||
/****** FIXME Do we really need this conditional here? */
|
|
||||||
log_print("--- %sPhysical volume ---", pv->pe_size ? "" : "NEW ");
|
log_print("--- %sPhysical volume ---", pv->pe_size ? "" : "NEW ");
|
||||||
log_print("PV Name %s", dev_name(pv->dev));
|
log_print("PV Name %s", dev_name(pv->dev));
|
||||||
log_print("VG Name %s%s", pv->vg_name,
|
log_print("VG Name %s%s", pv->vg_name,
|
||||||
pv->status & EXPORTED_VG ? " (exported)" : "");
|
pv->status & EXPORTED_VG ? " (exported)" : "");
|
||||||
|
|
||||||
size = display_size((uint64_t) pv->size / 2, SIZE_SHORT);
|
size = display_size(cmd, (uint64_t) pv->size / 2, SIZE_SHORT);
|
||||||
if (pv->pe_size && pv->pe_count) {
|
if (pv->pe_size && pv->pe_count) {
|
||||||
size1 = display_size((pv->size - pv->pe_count * pv->pe_size)
|
|
||||||
/ 2, SIZE_SHORT);
|
|
||||||
|
|
||||||
/******** FIXME display LVM on-disk data size - static for now...
|
/******** FIXME display LVM on-disk data size
|
||||||
size2 = display_size(pv->size / 2, SIZE_SHORT);
|
size2 = display_size(pv->size / 2, SIZE_SHORT);
|
||||||
********/
|
********/
|
||||||
|
|
||||||
log_print("PV Size %s [%llu secs]" " / not "
|
log_print("PV Size %s" " / not usable %s", /* [LVM: %s]", */
|
||||||
"usable %s [LVM: %s]",
|
size, display_size(cmd,
|
||||||
size, (uint64_t) pv->size, size1, "151 KB");
|
(pv->size -
|
||||||
/* , size2); */
|
pv->pe_count * pv->pe_size) / 2,
|
||||||
|
SIZE_SHORT));
|
||||||
|
|
||||||
dbg_free(size1);
|
|
||||||
/* dbg_free(size2); */
|
|
||||||
} else
|
} else
|
||||||
log_print("PV Size %s", size);
|
log_print("PV Size %s", size);
|
||||||
dbg_free(size);
|
|
||||||
|
|
||||||
/******** FIXME anytime this *isn't* available? */
|
/* PV number not part of LVM2 design
|
||||||
log_print("PV Status available");
|
log_print("PV# %u", pv->pv_number);
|
||||||
|
*/
|
||||||
/*********FIXME Anything use this?
|
|
||||||
log_print("PV# %u", pv->pv_number);
|
|
||||||
**********/
|
|
||||||
|
|
||||||
pe_free = pv->pe_count - pv->pe_alloc_count;
|
pe_free = pv->pe_count - pv->pe_alloc_count;
|
||||||
if (pv->pe_count && (pv->status & ALLOCATABLE_PV))
|
if (pv->pe_count && (pv->status & ALLOCATABLE_PV))
|
||||||
@@ -155,18 +291,13 @@ void pvdisplay_full(struct physical_volume *pv)
|
|||||||
else
|
else
|
||||||
log_print("Allocatable NO");
|
log_print("Allocatable NO");
|
||||||
|
|
||||||
/*********FIXME Erm...where is this stored?
|
/* LV count is no longer available when displaying PV
|
||||||
log_print("Cur LV %u", vg->lv_count);
|
log_print("Cur LV %u", vg->lv_count);
|
||||||
*/
|
*/
|
||||||
log_print("PE Size (KByte) %" PRIu64, pv->pe_size / 2);
|
log_print("PE Size (KByte) %" PRIu32, pv->pe_size / 2);
|
||||||
log_print("Total PE %u", pv->pe_count);
|
log_print("Total PE %u", pv->pe_count);
|
||||||
log_print("Free PE %" PRIu64, pe_free);
|
log_print("Free PE %" PRIu32, pe_free);
|
||||||
log_print("Allocated PE %u", pv->pe_alloc_count);
|
log_print("Allocated PE %u", pv->pe_alloc_count);
|
||||||
|
|
||||||
#ifdef LVM_FUTURE
|
|
||||||
printf("Stale PE %u", pv->pe_stale);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
log_print("PV UUID %s", *uuid ? uuid : "none");
|
log_print("PV UUID %s", *uuid ? uuid : "none");
|
||||||
log_print(" ");
|
log_print(" ");
|
||||||
|
|
||||||
@@ -174,13 +305,21 @@ void pvdisplay_full(struct physical_volume *pv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
|
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
|
||||||
struct physical_volume *pv)
|
struct physical_volume *pv, void *handle)
|
||||||
{
|
{
|
||||||
|
char uuid[64];
|
||||||
|
|
||||||
if (!pv)
|
if (!pv)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (!id_write_format(&pv->id, uuid, sizeof(uuid))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
log_print("PV Name %s ", dev_name(pv->dev));
|
log_print("PV Name %s ", dev_name(pv->dev));
|
||||||
/* FIXME pv->pv_number); */
|
/* FIXME pv->pv_number); */
|
||||||
|
log_print("PV UUID %s", *uuid ? uuid : "none");
|
||||||
log_print("PV Status %sallocatable",
|
log_print("PV Status %sallocatable",
|
||||||
(pv->status & ALLOCATABLE_PV) ? "" : "NOT ");
|
(pv->status & ALLOCATABLE_PV) ? "" : "NOT ");
|
||||||
log_print("Total PE / Free PE %u / %u",
|
log_print("Total PE / Free PE %u / %u",
|
||||||
@@ -190,12 +329,10 @@ int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void lvdisplay_colons(struct logical_volume *lv)
|
void lvdisplay_colons(struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
int inkernel;
|
int inkernel;
|
||||||
struct dm_info info;
|
struct lvinfo info;
|
||||||
inkernel = lv_info(lv, &info) && info.exists;
|
inkernel = lv_info(lv, &info) && info.exists;
|
||||||
|
|
||||||
log_print("%s%s/%s:%s:%d:%d:-1:%d:%" PRIu64 ":%d:-1:%d:%d:%d:%d",
|
log_print("%s%s/%s:%s:%d:%d:-1:%d:%" PRIu64 ":%d:-1:%d:%d:%d:%d",
|
||||||
@@ -207,25 +344,20 @@ void lvdisplay_colons(struct logical_volume *lv)
|
|||||||
/* FIXME lv->lv_number, */
|
/* FIXME lv->lv_number, */
|
||||||
inkernel ? info.open_count : 0, lv->size, lv->le_count,
|
inkernel ? info.open_count : 0, lv->size, lv->le_count,
|
||||||
/* FIXME Add num allocated to struct! lv->lv_allocated_le, */
|
/* FIXME Add num allocated to struct! lv->lv_allocated_le, */
|
||||||
((lv->status & ALLOC_STRICT) +
|
(lv->alloc == ALLOC_CONTIGUOUS ? 2 : 0), lv->read_ahead,
|
||||||
(lv->status & ALLOC_CONTIGUOUS) * 2), lv->read_ahead,
|
|
||||||
inkernel ? info.major : -1, inkernel ? info.minor : -1);
|
inkernel ? info.major : -1, inkernel ? info.minor : -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
|
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||||
|
void *handle)
|
||||||
{
|
{
|
||||||
char *size;
|
struct lvinfo info;
|
||||||
uint32_t alloc;
|
int inkernel, snap_active;
|
||||||
struct dm_info info;
|
|
||||||
int inkernel;
|
|
||||||
char uuid[64];
|
char uuid[64];
|
||||||
struct snapshot *snap;
|
struct snapshot *snap = NULL;
|
||||||
struct stripe_segment *seg;
|
struct list *slh, *snaplist;
|
||||||
struct list *lvseg;
|
float snap_percent; /* fused, fsize; */
|
||||||
struct logical_volume *origin;
|
|
||||||
float snap_percent;
|
|
||||||
int snap_active;
|
|
||||||
|
|
||||||
if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) {
|
if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) {
|
||||||
stack;
|
stack;
|
||||||
@@ -234,170 +366,108 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
|
|||||||
|
|
||||||
inkernel = lv_info(lv, &info) && info.exists;
|
inkernel = lv_info(lv, &info) && info.exists;
|
||||||
|
|
||||||
set_cmd_name("");
|
|
||||||
init_msg_prefix("");
|
|
||||||
|
|
||||||
log_print("--- Logical volume ---");
|
log_print("--- Logical volume ---");
|
||||||
|
|
||||||
log_print("LV Name %s%s/%s", lv->vg->cmd->dev_dir,
|
log_print("LV Name %s%s/%s", lv->vg->cmd->dev_dir,
|
||||||
lv->vg->name, lv->name);
|
lv->vg->name, lv->name);
|
||||||
log_print("VG Name %s", lv->vg->name);
|
log_print("VG Name %s", lv->vg->name);
|
||||||
|
|
||||||
/* Not in LVM1 format
|
|
||||||
log_print("LV UUID %s", uuid);
|
log_print("LV UUID %s", uuid);
|
||||||
**/
|
|
||||||
log_print("LV Write Access %s",
|
log_print("LV Write Access %s",
|
||||||
(lv->status & LVM_WRITE) ? "read/write" : "read only");
|
(lv->status & LVM_WRITE) ? "read/write" : "read only");
|
||||||
|
|
||||||
/* see if this LV is an origin for a snapshot */
|
if (lv_is_origin(lv)) {
|
||||||
if ((snap = find_origin(lv))) {
|
|
||||||
struct list *slh, *snaplist = find_snapshots(lv);
|
|
||||||
|
|
||||||
log_print("LV snapshot status source of");
|
log_print("LV snapshot status source of");
|
||||||
|
|
||||||
|
snaplist = find_snapshots(lv);
|
||||||
list_iterate(slh, snaplist) {
|
list_iterate(slh, snaplist) {
|
||||||
snap = list_item(slh, struct snapshot_list)->snapshot;
|
snap = list_item(slh, struct snapshot_list)->snapshot;
|
||||||
snap_active = lv_snapshot_percentage(snap->cow,
|
snap_active = lv_snapshot_percent(snap->cow,
|
||||||
&snap_percent);
|
&snap_percent);
|
||||||
|
if (!snap_active || snap_percent < 0 ||
|
||||||
|
snap_percent >= 100)
|
||||||
|
snap_active = 0;
|
||||||
log_print(" %s%s/%s [%s]",
|
log_print(" %s%s/%s [%s]",
|
||||||
lv->vg->cmd->dev_dir, lv->vg->name,
|
lv->vg->cmd->dev_dir, lv->vg->name,
|
||||||
snap->cow->name,
|
snap->cow->name,
|
||||||
(snap_active > 0) ? "active" : "INACTIVE");
|
(snap_active > 0) ? "active" : "INACTIVE");
|
||||||
}
|
}
|
||||||
/* reset so we don't try to use this to display other snapshot
|
|
||||||
* related information. */
|
|
||||||
snap = NULL;
|
snap = NULL;
|
||||||
snap_active = 0;
|
} else if ((snap = find_cow(lv))) {
|
||||||
}
|
snap_active = lv_snapshot_percent(lv, &snap_percent);
|
||||||
/* Check to see if this LV is a COW target for a snapshot */
|
if (!snap_active || snap_percent < 0 || snap_percent >= 100)
|
||||||
else if ((snap = find_cow(lv))) {
|
snap_active = 0;
|
||||||
snap_active = lv_snapshot_percentage(lv, &snap_percent);
|
|
||||||
log_print("LV snapshot status %s destination for %s%s/%s",
|
log_print("LV snapshot status %s destination for %s%s/%s",
|
||||||
(snap_active > 0) ? "active" : "INACTIVE",
|
(snap_active > 0) ? "active" : "INACTIVE",
|
||||||
lv->vg->cmd->dev_dir, lv->vg->name,
|
lv->vg->cmd->dev_dir, lv->vg->name,
|
||||||
snap->origin->name);
|
snap->origin->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (inkernel && info.suspended)
|
if (inkernel && info.suspended)
|
||||||
log_print("LV Status suspended");
|
log_print("LV Status suspended");
|
||||||
else
|
else
|
||||||
log_print("LV Status %savailable",
|
log_print("LV Status %savailable",
|
||||||
!inkernel || (snap && (snap_active < 1))
|
inkernel ? "" : "NOT ");
|
||||||
? "NOT " : "");
|
|
||||||
|
|
||||||
/********* FIXME lv_number - not sure that we're going to bother with this
|
/********* FIXME lv_number
|
||||||
log_print("LV # %u", lv->lv_number + 1);
|
log_print("LV # %u", lv->lv_number + 1);
|
||||||
************/
|
************/
|
||||||
|
|
||||||
/* LVM1 lists the number of LVs open in this field, therefore, so do we. */
|
|
||||||
log_print("# open %u", lvs_in_vg_opened(lv->vg));
|
|
||||||
|
|
||||||
/* We're not going to use this count ATM, 'cause it's not what LVM1 does
|
|
||||||
if (inkernel)
|
if (inkernel)
|
||||||
log_print("# open %u", info.open_count);
|
log_print("# open %u", info.open_count);
|
||||||
*/
|
|
||||||
/********
|
|
||||||
#ifdef LVM_FUTURE
|
|
||||||
printf("Mirror copies %u\n", lv->lv_mirror_copies);
|
|
||||||
printf("Consistency recovery ");
|
|
||||||
if (lv->lv_recovery | LV_BADBLOCK_ON)
|
|
||||||
printf("bad blocks\n");
|
|
||||||
else
|
|
||||||
printf("none\n");
|
|
||||||
printf("Schedule %u\n", lv->lv_schedule);
|
|
||||||
#endif
|
|
||||||
********/
|
|
||||||
|
|
||||||
if(snap)
|
log_print("LV Size %s",
|
||||||
origin = snap->origin;
|
display_size(cmd,
|
||||||
else
|
snap ? snap->origin->size / 2 : lv->size / 2,
|
||||||
origin = lv;
|
SIZE_SHORT));
|
||||||
|
|
||||||
size = display_size(origin->size / 2, SIZE_SHORT);
|
|
||||||
log_print("LV Size %s", size);
|
|
||||||
dbg_free(size);
|
|
||||||
|
|
||||||
log_print("Current LE %u", origin->le_count);
|
log_print("Current LE %u",
|
||||||
|
snap ? snap->origin->le_count : lv->le_count);
|
||||||
/********** FIXME allocation - is there anytime the allocated LEs will not
|
|
||||||
* equal the current LEs? */
|
|
||||||
log_print("Allocated LE %u", origin->le_count);
|
|
||||||
/**********/
|
|
||||||
|
|
||||||
|
|
||||||
list_iterate(lvseg, &lv->segments) {
|
/********** FIXME allocation
|
||||||
seg = list_item(lvseg, struct stripe_segment);
|
log_print("Allocated LE %u", lv->allocated_le);
|
||||||
if(seg->stripes > 1) {
|
**********/
|
||||||
log_print("Stripes %u", seg->stripes);
|
|
||||||
log_print("Stripe size (KByte) %u",
|
|
||||||
seg->stripe_size/2);
|
|
||||||
}
|
|
||||||
/* only want the first segment for LVM1 format output */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(snap) {
|
|
||||||
float fused, fsize;
|
|
||||||
if(snap_percent == -1)
|
|
||||||
snap_percent=100;
|
|
||||||
|
|
||||||
size = display_size(snap->chunk_size / 2, SIZE_SHORT);
|
|
||||||
log_print("snapshot chunk size %s", size);
|
|
||||||
dbg_free(size);
|
|
||||||
|
|
||||||
size = display_size(lv->size / 2, SIZE_SHORT);
|
|
||||||
sscanf(size, "%f", &fsize);
|
|
||||||
fused = fsize * ( snap_percent / 100 );
|
|
||||||
log_print("Allocated to snapshot %2.2f%% [%2.2f/%s]",
|
|
||||||
snap_percent, fused, size);
|
|
||||||
dbg_free(size);
|
|
||||||
|
|
||||||
/* FIXME: Think this'll make them wonder?? */
|
|
||||||
log_print("Allocated to COW-table %s", "00.01 KB");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Not in LVM1 format output **
|
|
||||||
log_print("Segments %u", list_size(&lv->segments));
|
log_print("Segments %u", list_size(&lv->segments));
|
||||||
***/
|
|
||||||
|
|
||||||
/********* FIXME Stripes & stripesize for each segment
|
/********* FIXME Stripes & stripesize for each segment
|
||||||
log_print("Stripe size (KByte) %u", lv->stripesize / 2);
|
log_print("Stripe size (KByte) %u", lv->stripesize / 2);
|
||||||
***********/
|
***********/
|
||||||
|
|
||||||
/**************
|
if (snap) {
|
||||||
#ifdef LVM_FUTURE
|
if (snap_percent == -1)
|
||||||
printf("Bad block ");
|
snap_percent = 100;
|
||||||
if (lv->lv_badblock == LV_BADBLOCK_ON)
|
|
||||||
printf("on\n");
|
|
||||||
else
|
|
||||||
printf("off\n");
|
|
||||||
#endif
|
|
||||||
***************/
|
|
||||||
|
|
||||||
/* FIXME next free == ALLOC_SIMPLE */
|
log_print("Snapshot chunk size %s",
|
||||||
alloc = lv->status & (ALLOC_STRICT | ALLOC_CONTIGUOUS);
|
display_size(cmd, (uint64_t) snap->chunk_size / 2,
|
||||||
log_print("Allocation %s%s%s%s",
|
SIZE_SHORT));
|
||||||
!(alloc & (ALLOC_STRICT | ALLOC_CONTIGUOUS)) ? "next free" :
|
|
||||||
"", (alloc == ALLOC_STRICT) ? "strict" : "",
|
|
||||||
(alloc == ALLOC_CONTIGUOUS) ? "contiguous" : "",
|
|
||||||
(alloc ==
|
|
||||||
(ALLOC_STRICT | ALLOC_CONTIGUOUS)) ? "strict/contiguous" :
|
|
||||||
"");
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
size = display_size(lv->size / 2, SIZE_SHORT);
|
||||||
|
sscanf(size, "%f", &fsize);
|
||||||
|
fused = fsize * snap_percent / 100;
|
||||||
|
*/
|
||||||
|
log_print("Allocated to snapshot %.2f%% ", /* [%.2f/%s]", */
|
||||||
|
snap_percent); /*, fused, size); */
|
||||||
|
/* dbg_free(size); */
|
||||||
|
}
|
||||||
|
|
||||||
|
/********** FIXME Snapshot
|
||||||
|
size = ???
|
||||||
|
log_print("Allocated to COW-table %s", size);
|
||||||
|
dbg_free(size);
|
||||||
|
}
|
||||||
|
******************/
|
||||||
|
|
||||||
|
log_print("Allocation %s", get_alloc_string(lv->alloc));
|
||||||
log_print("Read ahead sectors %u", lv->read_ahead);
|
log_print("Read ahead sectors %u", lv->read_ahead);
|
||||||
|
|
||||||
if (lv->status & FIXED_MINOR)
|
if (lv->status & FIXED_MINOR) {
|
||||||
|
if (lv->major >= 0)
|
||||||
|
log_print("Persistent major %d", lv->major);
|
||||||
log_print("Persistent minor %d", lv->minor);
|
log_print("Persistent minor %d", lv->minor);
|
||||||
|
}
|
||||||
/****************
|
|
||||||
#ifdef LVM_FUTURE
|
|
||||||
printf("IO Timeout (seconds) ");
|
|
||||||
if (lv->lv_io_timeout == 0)
|
|
||||||
printf("default\n\n");
|
|
||||||
else
|
|
||||||
printf("%lu\n\n", lv->lv_io_timeout);
|
|
||||||
#endif
|
|
||||||
*************/
|
|
||||||
|
|
||||||
if (inkernel)
|
if (inkernel)
|
||||||
log_print("Block device %d:%d", info.major,
|
log_print("Block device %d:%d", info.major,
|
||||||
@@ -408,45 +478,80 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _display_stripe(struct stripe_segment *seg, int s, const char *pre)
|
static void _display_stripe(struct lv_segment *seg, uint32_t s, const char *pre)
|
||||||
{
|
{
|
||||||
uint32_t len = seg->len / seg->stripes;
|
switch (seg->area[s].type) {
|
||||||
|
case AREA_PV:
|
||||||
|
log_print("%sPhysical volume\t%s", pre,
|
||||||
|
seg->area[s].u.pv.pv ?
|
||||||
|
dev_name(seg->area[s].u.pv.pv->dev) : "Missing");
|
||||||
|
|
||||||
log_print("%sphysical volume\t%s", pre,
|
if (seg->area[s].u.pv.pv)
|
||||||
seg->area[s].pv ? dev_name(seg->area[s].pv->dev) : "Missing");
|
log_print("%sPhysical extents\t%d to %d", pre,
|
||||||
|
seg->area[s].u.pv.pe,
|
||||||
|
seg->area[s].u.pv.pe + seg->area_len - 1);
|
||||||
|
break;
|
||||||
|
case AREA_LV:
|
||||||
|
log_print("%sLogical volume\t%s", pre,
|
||||||
|
seg->area[s].u.lv.lv ?
|
||||||
|
seg->area[s].u.lv.lv->name : "Missing");
|
||||||
|
|
||||||
if (seg->area[s].pv)
|
if (seg->area[s].u.lv.lv)
|
||||||
log_print("%sphysical extents\t%d to %d", pre,
|
log_print("%sLogical extents\t%d to %d", pre,
|
||||||
seg->area[s].pe, seg->area[s].pe + len - 1);
|
seg->area[s].u.lv.le,
|
||||||
|
seg->area[s].u.lv.le + seg->area_len - 1);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int lvdisplay_segments(struct logical_volume *lv)
|
int lvdisplay_segments(struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
int s;
|
uint32_t s;
|
||||||
struct list *segh;
|
struct list *segh;
|
||||||
struct stripe_segment *seg;
|
struct lv_segment *seg;
|
||||||
|
|
||||||
log_print("--- Segments ---");
|
log_print("--- Segments ---");
|
||||||
|
|
||||||
list_iterate(segh, &lv->segments) {
|
list_iterate(segh, &lv->segments) {
|
||||||
seg = list_item(segh, struct stripe_segment);
|
seg = list_item(segh, struct lv_segment);
|
||||||
|
|
||||||
log_print("logical extent %d to %d:",
|
log_print("Logical extent %u to %u:",
|
||||||
seg->le, seg->le + seg->len - 1);
|
seg->le, seg->le + seg->len - 1);
|
||||||
|
|
||||||
if (seg->stripes == 1)
|
if (seg->type == SEG_STRIPED && seg->area_count == 1)
|
||||||
_display_stripe(seg, 0, " ");
|
log_print(" Type\t\tlinear");
|
||||||
|
else
|
||||||
|
log_print(" Type\t\t%s",
|
||||||
|
get_segtype_string(seg->type));
|
||||||
|
|
||||||
else {
|
switch (seg->type) {
|
||||||
log_print(" stripes\t\t%d", seg->stripes);
|
case SEG_STRIPED:
|
||||||
log_print(" stripe size\t\t%d", seg->stripe_size);
|
if (seg->area_count == 1)
|
||||||
|
_display_stripe(seg, 0, " ");
|
||||||
|
else {
|
||||||
|
log_print(" Stripes\t\t%u", seg->area_count);
|
||||||
|
log_print(" Stripe size\t\t%u KB",
|
||||||
|
seg->stripe_size / 2);
|
||||||
|
|
||||||
for (s = 0; s < seg->stripes; s++) {
|
for (s = 0; s < seg->area_count; s++) {
|
||||||
log_print(" stripe %d:", s);
|
log_print(" Stripe %d:", s);
|
||||||
_display_stripe(seg, s, " ");
|
_display_stripe(seg, s, " ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
log_print(" ");
|
||||||
|
break;
|
||||||
|
case SEG_SNAPSHOT:
|
||||||
|
break;
|
||||||
|
case SEG_MIRRORED:
|
||||||
|
log_print(" Mirrors\t\t%u", seg->area_count);
|
||||||
|
log_print(" Mirror size\t\t%u", seg->area_len);
|
||||||
|
log_print(" Mirror original:");
|
||||||
|
_display_stripe(seg, 0, " ");
|
||||||
|
log_print(" Mirror destination:");
|
||||||
|
_display_stripe(seg, 1, " ");
|
||||||
|
log_print(" ");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
log_print(" ");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_print(" ");
|
log_print(" ");
|
||||||
@@ -461,29 +566,23 @@ void vgdisplay_extents(struct volume_group *vg)
|
|||||||
void vgdisplay_full(struct volume_group *vg)
|
void vgdisplay_full(struct volume_group *vg)
|
||||||
{
|
{
|
||||||
uint32_t access;
|
uint32_t access;
|
||||||
char *s1;
|
|
||||||
char uuid[64];
|
|
||||||
uint32_t active_pvs;
|
uint32_t active_pvs;
|
||||||
struct list *pvlist;
|
char uuid[64];
|
||||||
|
|
||||||
set_cmd_name("");
|
if (vg->status & PARTIAL_VG)
|
||||||
init_msg_prefix("");
|
active_pvs = list_size(&vg->pvs);
|
||||||
|
|
||||||
/* get the number of active PVs */
|
|
||||||
if(vg->status & PARTIAL_VG) {
|
|
||||||
active_pvs=0;
|
|
||||||
list_iterate(pvlist, &(vg->pvs)) {
|
|
||||||
active_pvs++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
active_pvs=vg->pv_count;
|
active_pvs = vg->pv_count;
|
||||||
|
|
||||||
log_print("--- Volume group ---");
|
log_print("--- Volume group ---");
|
||||||
log_print("VG Name %s", vg->name);
|
log_print("VG Name %s", vg->name);
|
||||||
/****** Not in LVM1 output, so we aren't outputing it here:
|
|
||||||
log_print("System ID %s", vg->system_id);
|
log_print("System ID %s", vg->system_id);
|
||||||
*******/
|
log_print("Format %s", vg->fid->fmt->name);
|
||||||
|
if (vg->fid->fmt->features & FMT_MDAS) {
|
||||||
|
log_print("Metadata Areas %d",
|
||||||
|
list_size(&vg->fid->metadata_areas));
|
||||||
|
log_print("Metadata Sequence No %d", vg->seqno);
|
||||||
|
}
|
||||||
access = vg->status & (LVM_READ | LVM_WRITE);
|
access = vg->status & (LVM_READ | LVM_WRITE);
|
||||||
log_print("VG Access %s%s%s%s",
|
log_print("VG Access %s%s%s%s",
|
||||||
access == (LVM_READ | LVM_WRITE) ? "read/write" : "",
|
access == (LVM_READ | LVM_WRITE) ? "read/write" : "",
|
||||||
@@ -491,49 +590,56 @@ void vgdisplay_full(struct volume_group *vg)
|
|||||||
access == LVM_WRITE ? "write" : "",
|
access == LVM_WRITE ? "write" : "",
|
||||||
access == 0 ? "error" : "");
|
access == 0 ? "error" : "");
|
||||||
log_print("VG Status %s%sresizable",
|
log_print("VG Status %s%sresizable",
|
||||||
vg->status & EXPORTED_VG ? "exported/" : "available/",
|
vg->status & EXPORTED_VG ? "exported/" : "",
|
||||||
vg->status & RESIZEABLE_VG ? "" : "NOT ");
|
vg->status & RESIZEABLE_VG ? "" : "NOT ");
|
||||||
|
/* vg number not part of LVM2 design
|
||||||
|
log_print ("VG # %u\n", vg->vg_number);
|
||||||
|
*/
|
||||||
if (vg->status & CLUSTERED) {
|
if (vg->status & CLUSTERED) {
|
||||||
log_print("Clustered yes");
|
log_print("Clustered yes");
|
||||||
log_print("Shared %s",
|
log_print("Shared %s",
|
||||||
vg->status & SHARED ? "yes" : "no");
|
vg->status & SHARED ? "yes" : "no");
|
||||||
}
|
}
|
||||||
/****** FIXME VG # - we aren't implementing this because people should
|
|
||||||
* use the UUID for this anyway
|
|
||||||
log_print("VG # %u", vg->vg_number);
|
|
||||||
*******/
|
|
||||||
log_print("MAX LV %u", vg->max_lv);
|
log_print("MAX LV %u", vg->max_lv);
|
||||||
log_print("Cur LV %u", vg->lv_count);
|
log_print("Cur LV %u", vg->lv_count);
|
||||||
log_print("Open LV %u", lvs_in_vg_opened(vg));
|
log_print("Open LV %u", lvs_in_vg_opened(vg));
|
||||||
log_print("MAX LV Size 256 TB");
|
/****** FIXME Max LV Size
|
||||||
|
log_print ( "MAX LV Size %s",
|
||||||
|
( s1 = display_size ( LVM_LV_SIZE_MAX(vg) / 2, SIZE_SHORT)));
|
||||||
|
free ( s1);
|
||||||
|
*********/
|
||||||
log_print("Max PV %u", vg->max_pv);
|
log_print("Max PV %u", vg->max_pv);
|
||||||
log_print("Cur PV %u", vg->pv_count);
|
log_print("Cur PV %u", vg->pv_count);
|
||||||
log_print("Act PV %u", active_pvs);
|
log_print("Act PV %u", active_pvs);
|
||||||
|
|
||||||
s1 =
|
log_print("VG Size %s",
|
||||||
display_size((uint64_t) vg->extent_count * (vg->extent_size / 2),
|
display_size(vg->cmd,
|
||||||
SIZE_SHORT);
|
(uint64_t) vg->extent_count * (vg->extent_size /
|
||||||
log_print("VG Size %s", s1);
|
2), SIZE_SHORT));
|
||||||
dbg_free(s1);
|
|
||||||
|
|
||||||
s1 = display_size(vg->extent_size / 2, SIZE_SHORT);
|
log_print("PE Size %s",
|
||||||
log_print("PE Size %s", s1);
|
display_size(vg->cmd, (uint64_t) vg->extent_size / 2,
|
||||||
dbg_free(s1);
|
SIZE_SHORT));
|
||||||
|
|
||||||
log_print("Total PE %u", vg->extent_count);
|
log_print("Total PE %u", vg->extent_count);
|
||||||
|
|
||||||
s1 = display_size(((uint64_t)
|
|
||||||
vg->extent_count - vg->free_count) *
|
|
||||||
(vg->extent_size / 2), SIZE_SHORT);
|
|
||||||
log_print("Alloc PE / Size %u / %s",
|
log_print("Alloc PE / Size %u / %s",
|
||||||
vg->extent_count - vg->free_count, s1);
|
vg->extent_count - vg->free_count, display_size(vg->cmd,
|
||||||
dbg_free(s1);
|
((uint64_t)
|
||||||
|
vg->
|
||||||
|
extent_count
|
||||||
|
-
|
||||||
|
vg->
|
||||||
|
free_count) *
|
||||||
|
(vg->
|
||||||
|
extent_size /
|
||||||
|
2),
|
||||||
|
SIZE_SHORT));
|
||||||
|
|
||||||
s1 =
|
log_print("Free PE / Size %u / %s", vg->free_count,
|
||||||
display_size((uint64_t) vg->free_count * (vg->extent_size / 2),
|
display_size(vg->cmd,
|
||||||
SIZE_SHORT);
|
(uint64_t) vg->free_count * (vg->extent_size /
|
||||||
log_print("Free PE / Size %u / %s", vg->free_count, s1);
|
2), SIZE_SHORT));
|
||||||
dbg_free(s1);
|
|
||||||
|
|
||||||
if (!id_write_format(&vg->id, uuid, sizeof(uuid))) {
|
if (!id_write_format(&vg->id, uuid, sizeof(uuid))) {
|
||||||
stack;
|
stack;
|
||||||
@@ -548,22 +654,69 @@ void vgdisplay_full(struct volume_group *vg)
|
|||||||
|
|
||||||
void vgdisplay_colons(struct volume_group *vg)
|
void vgdisplay_colons(struct volume_group *vg)
|
||||||
{
|
{
|
||||||
|
uint32_t active_pvs;
|
||||||
|
const char *access;
|
||||||
|
char uuid[64];
|
||||||
|
|
||||||
|
if (vg->status & PARTIAL_VG)
|
||||||
|
active_pvs = list_size(&vg->pvs);
|
||||||
|
else
|
||||||
|
active_pvs = vg->pv_count;
|
||||||
|
|
||||||
|
switch (vg->status & (LVM_READ | LVM_WRITE)) {
|
||||||
|
case LVM_READ | LVM_WRITE:
|
||||||
|
access = "r/w";
|
||||||
|
break;
|
||||||
|
case LVM_READ:
|
||||||
|
access = "r";
|
||||||
|
break;
|
||||||
|
case LVM_WRITE:
|
||||||
|
access = "w";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
access = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!id_write_format(&vg->id, uuid, sizeof(uuid))) {
|
||||||
|
stack;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_print("%s:%s:%d:-1:%u:%u:%u:-1:%u:%u:%u:%" PRIu64 ":%" PRIu32
|
||||||
|
":%u:%u:%u:%s",
|
||||||
|
vg->name,
|
||||||
|
access,
|
||||||
|
vg->status,
|
||||||
|
/* internal volume group number; obsolete */
|
||||||
|
vg->max_lv,
|
||||||
|
vg->lv_count,
|
||||||
|
lvs_in_vg_opened(vg),
|
||||||
|
/* FIXME: maximum logical volume size */
|
||||||
|
vg->max_pv,
|
||||||
|
vg->pv_count,
|
||||||
|
active_pvs,
|
||||||
|
(uint64_t) vg->extent_count * (vg->extent_size / 2),
|
||||||
|
vg->extent_size / 2,
|
||||||
|
vg->extent_count,
|
||||||
|
vg->extent_count - vg->free_count,
|
||||||
|
vg->free_count,
|
||||||
|
uuid[0] ? uuid : "none");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vgdisplay_short(struct volume_group *vg)
|
void vgdisplay_short(struct volume_group *vg)
|
||||||
{
|
{
|
||||||
char *s1, *s2, *s3;
|
|
||||||
s1 = display_size(vg->extent_count * vg->extent_size / 2, SIZE_SHORT);
|
|
||||||
s2 =
|
|
||||||
display_size((vg->extent_count - vg->free_count) * vg->extent_size /
|
|
||||||
2, SIZE_SHORT);
|
|
||||||
s3 = display_size(vg->free_count * vg->extent_size / 2, SIZE_SHORT);
|
|
||||||
log_print("\"%s\" %-9s [%-9s used / %s free]", vg->name,
|
log_print("\"%s\" %-9s [%-9s used / %s free]", vg->name,
|
||||||
/********* FIXME if "open" print "/used" else print "/idle"??? ******/
|
/********* FIXME if "open" print "/used" else print "/idle"??? ******/
|
||||||
s1, s2, s3);
|
display_size(vg->cmd, (uint64_t) vg->extent_count *
|
||||||
dbg_free(s1);
|
vg->extent_size / 2, SIZE_SHORT),
|
||||||
dbg_free(s2);
|
display_size(vg->cmd,
|
||||||
dbg_free(s3);
|
((uint64_t) vg->extent_count -
|
||||||
|
vg->free_count) * vg->extent_size / 2,
|
||||||
|
SIZE_SHORT), display_size(vg->cmd,
|
||||||
|
(uint64_t) vg->
|
||||||
|
free_count *
|
||||||
|
vg->extent_size / 2,
|
||||||
|
SIZE_SHORT));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This LVM library is free software; you can redistribute it and/or
|
* This file is part of LVM2.
|
||||||
* modify it under the terms of the GNU Library General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
*
|
||||||
* This LVM library is distributed in the hope that it will be useful,
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* of the GNU General Public License v.2.
|
||||||
* Library General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Library General Public
|
|
||||||
* License along with this LVM library; if not, write to the Free
|
|
||||||
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
||||||
* MA 02111-1307, USA
|
|
||||||
*
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_DISPLAY_H
|
#ifndef _LVM_DISPLAY_H
|
||||||
@@ -25,23 +20,40 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef enum {SIZE_LONG=0, SIZE_SHORT=1} size_len_t;
|
typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1, SIZE_UNIT = 2 } size_len_t;
|
||||||
|
|
||||||
|
uint64_t units_to_bytes(const char *units, char *unit_type);
|
||||||
|
|
||||||
/* Specify size in KB */
|
/* Specify size in KB */
|
||||||
char *display_size(uint64_t size, size_len_t sl);
|
const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl);
|
||||||
char *display_uuid(char *uuidstr);
|
char *display_uuid(char *uuidstr);
|
||||||
|
|
||||||
void pvdisplay_colons(struct physical_volume *pv);
|
void pvdisplay_colons(struct physical_volume *pv);
|
||||||
void pvdisplay_full(struct physical_volume *pv);
|
void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
|
||||||
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv);
|
void *handle);
|
||||||
|
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
|
||||||
|
struct physical_volume *pv, void *handle);
|
||||||
|
|
||||||
void lvdisplay_colons(struct logical_volume *lv);
|
void lvdisplay_colons(struct logical_volume *lv);
|
||||||
int lvdisplay_segments(struct logical_volume *lv);
|
int lvdisplay_segments(struct logical_volume *lv);
|
||||||
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv);
|
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||||
|
void *handle);
|
||||||
|
|
||||||
void vgdisplay_extents(struct volume_group *vg);
|
void vgdisplay_extents(struct volume_group *vg);
|
||||||
void vgdisplay_full(struct volume_group *vg);
|
void vgdisplay_full(struct volume_group *vg);
|
||||||
void vgdisplay_colons(struct volume_group *vg);
|
void vgdisplay_colons(struct volume_group *vg);
|
||||||
void vgdisplay_short(struct volume_group *vg);
|
void vgdisplay_short(struct volume_group *vg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocation policy display conversion routines.
|
||||||
|
*/
|
||||||
|
const char *get_alloc_string(alloc_policy_t alloc);
|
||||||
|
alloc_policy_t get_alloc_from_string(const char *str);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Segment type display conversion routines.
|
||||||
|
*/
|
||||||
|
segment_type_t get_segtype_from_string(const char *str);
|
||||||
|
const char *get_segtype_string(segment_type_t segtype);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
#include "filter-composite.h"
|
#include "filter-composite.h"
|
||||||
#include "dbg_malloc.h"
|
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
@@ -20,6 +28,8 @@ static int _and_p(struct dev_filter *f, struct device *dev)
|
|||||||
filters++;
|
filters++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_debug("Using %s", dev_name(dev));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,35 +46,32 @@ static void _destroy(struct dev_filter *f)
|
|||||||
dbg_free(f);
|
dbg_free(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dev_filter *composite_filter_create(int n, ...)
|
struct dev_filter *composite_filter_create(int n, struct dev_filter **filters)
|
||||||
{
|
{
|
||||||
struct dev_filter **filters = dbg_malloc(sizeof(*filters) * (n + 1));
|
struct dev_filter **filters_copy, *cf;
|
||||||
struct dev_filter *cf;
|
|
||||||
va_list ap;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!filters) {
|
if (!filters) {
|
||||||
stack;
|
stack;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(cf = dbg_malloc(sizeof(*cf)))) {
|
if (!(filters_copy = dbg_malloc(sizeof(*filters) * (n + 1)))) {
|
||||||
stack;
|
log_error("composite filters allocation failed");
|
||||||
dbg_free(filters);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
va_start(ap, n);
|
memcpy(filters_copy, filters, sizeof(*filters) * n);
|
||||||
for (i = 0; i < n; i++) {
|
filters_copy[n] = NULL;
|
||||||
struct dev_filter *f = va_arg(ap, struct dev_filter *);
|
|
||||||
filters[i] = f;
|
if (!(cf = dbg_malloc(sizeof(*cf)))) {
|
||||||
|
log_error("compsoite filters allocation failed");
|
||||||
|
dbg_free(filters_copy);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
filters[i] = NULL;
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
cf->passes_filter = _and_p;
|
cf->passes_filter = _and_p;
|
||||||
cf->destroy = _destroy;
|
cf->destroy = _destroy;
|
||||||
cf->private = filters;
|
cf->private = filters_copy;
|
||||||
|
|
||||||
return cf;
|
return cf;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the GPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_FILTER_COMPOSITE_H
|
#ifndef _LVM_FILTER_COMPOSITE_H
|
||||||
@@ -9,6 +18,6 @@
|
|||||||
|
|
||||||
#include "dev-cache.h"
|
#include "dev-cache.h"
|
||||||
|
|
||||||
struct dev_filter *composite_filter_create(int n, ...);
|
struct dev_filter *composite_filter_create(int n, struct dev_filter **filters);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,17 +1,24 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "dev-cache.h"
|
#include "dev-cache.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "dbg_malloc.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "filter-persistent.h"
|
#include "filter-persistent.h"
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -34,8 +41,12 @@ static int _init_hash(struct pfilter *pf)
|
|||||||
if (pf->devices)
|
if (pf->devices)
|
||||||
hash_destroy(pf->devices);
|
hash_destroy(pf->devices);
|
||||||
|
|
||||||
pf->devices = hash_create(128);
|
if (!(pf->devices = hash_create(128))) {
|
||||||
return pf->devices ? 1 : 0;
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int persistent_filter_wipe(struct dev_filter *f)
|
int persistent_filter_wipe(struct dev_filter *f)
|
||||||
@@ -43,16 +54,19 @@ int persistent_filter_wipe(struct dev_filter *f)
|
|||||||
struct pfilter *pf = (struct pfilter *) f->private;
|
struct pfilter *pf = (struct pfilter *) f->private;
|
||||||
|
|
||||||
hash_wipe(pf->devices);
|
hash_wipe(pf->devices);
|
||||||
|
/* Trigger complete device scan */
|
||||||
|
dev_cache_scan(1);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _read_array(struct pfilter *pf, struct config_file *cf,
|
static int _read_array(struct pfilter *pf, struct config_tree *cft,
|
||||||
const char *path, void *data)
|
const char *path, void *data)
|
||||||
{
|
{
|
||||||
struct config_node *cn;
|
struct config_node *cn;
|
||||||
struct config_value *cv;
|
struct config_value *cv;
|
||||||
|
|
||||||
if (!(cn = find_config_node(cf->root, path, '/'))) {
|
if (!(cn = find_config_node(cft->root, path))) {
|
||||||
log_very_verbose("Couldn't find %s array in '%s'",
|
log_very_verbose("Couldn't find %s array in '%s'",
|
||||||
path, pf->file);
|
path, pf->file);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -72,6 +86,8 @@ static int _read_array(struct pfilter *pf, struct config_file *cf,
|
|||||||
if (!hash_insert(pf->devices, cv->v.str, data))
|
if (!hash_insert(pf->devices, cv->v.str, data))
|
||||||
log_verbose("Couldn't add '%s' to filter ... ignoring",
|
log_verbose("Couldn't add '%s' to filter ... ignoring",
|
||||||
cv->v.str);
|
cv->v.str);
|
||||||
|
/* Populate dev_cache ourselves */
|
||||||
|
dev_cache_get(cv->v.str, NULL);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -81,32 +97,39 @@ int persistent_filter_load(struct dev_filter *f)
|
|||||||
struct pfilter *pf = (struct pfilter *) f->private;
|
struct pfilter *pf = (struct pfilter *) f->private;
|
||||||
|
|
||||||
int r = 0;
|
int r = 0;
|
||||||
struct config_file *cf;
|
struct config_tree *cft;
|
||||||
|
|
||||||
if (!(cf = create_config_file())) {
|
if (!(cft = create_config_tree())) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!read_config(cf, pf->file)) {
|
if (!read_config_file(cft, pf->file)) {
|
||||||
stack;
|
stack;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
_read_array(pf, cf, "persistent_filter_cache/valid_devices",
|
_read_array(pf, cft, "persistent_filter_cache/valid_devices",
|
||||||
PF_GOOD_DEVICE);
|
PF_GOOD_DEVICE);
|
||||||
_read_array(pf, cf, "persistent_filter_cache/invalid_devices",
|
/* We don't gain anything by holding invalid devices */
|
||||||
PF_BAD_DEVICE);
|
/* _read_array(pf, cft, "persistent_filter_cache/invalid_devices",
|
||||||
|
PF_BAD_DEVICE); */
|
||||||
|
|
||||||
if (hash_get_num_entries(pf->devices))
|
/* Did we find anything? */
|
||||||
|
if (hash_get_num_entries(pf->devices)) {
|
||||||
|
/* We populated dev_cache ourselves */
|
||||||
|
dev_cache_scan(0);
|
||||||
r = 1;
|
r = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_very_verbose("Loaded persistent filter cache from %s", pf->file);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
destroy_config_file(cf);
|
destroy_config_tree(cft);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _write_array(struct pfilter *pf, FILE * fp, const char *path,
|
static void _write_array(struct pfilter *pf, FILE *fp, const char *path,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
void *d;
|
void *d;
|
||||||
@@ -147,11 +170,18 @@ int persistent_filter_dump(struct dev_filter *f)
|
|||||||
"- not writing to %s", pf->file);
|
"- not writing to %s", pf->file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (!dev_cache_has_scanned()) {
|
||||||
|
log_very_verbose("Device cache incomplete - not writing "
|
||||||
|
"to %s", pf->file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
log_very_verbose("Dumping persistent device cache to %s", pf->file);
|
log_very_verbose("Dumping persistent device cache to %s", pf->file);
|
||||||
|
|
||||||
fp = fopen(pf->file, "w");
|
fp = fopen(pf->file, "w");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
log_sys_error("fopen", pf->file);
|
if (errno != EROFS)
|
||||||
|
log_sys_error("fopen", pf->file);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +189,8 @@ int persistent_filter_dump(struct dev_filter *f)
|
|||||||
fprintf(fp, "persistent_filter_cache {\n");
|
fprintf(fp, "persistent_filter_cache {\n");
|
||||||
|
|
||||||
_write_array(pf, fp, "valid_devices", PF_GOOD_DEVICE);
|
_write_array(pf, fp, "valid_devices", PF_GOOD_DEVICE);
|
||||||
_write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE);
|
/* We don't gain anything by remembering invalid devices */
|
||||||
|
/* _write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE); */
|
||||||
|
|
||||||
fprintf(fp, "}\n");
|
fprintf(fp, "}\n");
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
@@ -183,7 +214,11 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return l == PF_GOOD_DEVICE;
|
if (l == PF_BAD_DEVICE) {
|
||||||
|
log_debug("%s: Skipping (cached)", dev_name(dev));
|
||||||
|
return 0;
|
||||||
|
} else
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _destroy(struct dev_filter *f)
|
static void _destroy(struct dev_filter *f)
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the GPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_FILTER_PERSISTENT_H
|
#ifndef _LVM_FILTER_PERSISTENT_H
|
||||||
|
|||||||
@@ -1,15 +1,24 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
#include "filter-regex.h"
|
#include "filter-regex.h"
|
||||||
#include "matcher.h"
|
#include "matcher.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "bitset.h"
|
#include "bitset.h"
|
||||||
#include "log.h"
|
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
|
||||||
struct rfilter {
|
struct rfilter {
|
||||||
@@ -19,7 +28,7 @@ struct rfilter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static int _extract_pattern(struct pool *mem, const char *pat,
|
static int _extract_pattern(struct pool *mem, const char *pat,
|
||||||
char **regex, bitset_t accept, int index)
|
char **regex, bitset_t accept, int ix)
|
||||||
{
|
{
|
||||||
char sep, *r, *ptr;
|
char sep, *r, *ptr;
|
||||||
|
|
||||||
@@ -28,11 +37,11 @@ static int _extract_pattern(struct pool *mem, const char *pat,
|
|||||||
*/
|
*/
|
||||||
switch (*pat) {
|
switch (*pat) {
|
||||||
case 'a':
|
case 'a':
|
||||||
bit_set(accept, index);
|
bit_set(accept, ix);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'r':
|
case 'r':
|
||||||
bit_clear(accept, index);
|
bit_clear(accept, ix);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -42,7 +51,7 @@ static int _extract_pattern(struct pool *mem, const char *pat,
|
|||||||
pat++;
|
pat++;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get the seperator
|
* get the separator
|
||||||
*/
|
*/
|
||||||
switch (*pat) {
|
switch (*pat) {
|
||||||
case '(':
|
case '(':
|
||||||
@@ -75,12 +84,12 @@ static int _extract_pattern(struct pool *mem, const char *pat,
|
|||||||
*/
|
*/
|
||||||
ptr = r + strlen(r) - 1;
|
ptr = r + strlen(r) - 1;
|
||||||
if (*ptr != sep) {
|
if (*ptr != sep) {
|
||||||
log_info("invalid seperator at end of regex");
|
log_info("invalid separator at end of regex");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
*ptr = '\0';
|
*ptr = '\0';
|
||||||
|
|
||||||
regex[index] = r;
|
regex[ix] = r;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +98,8 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
|||||||
struct pool *scratch;
|
struct pool *scratch;
|
||||||
struct config_value *v;
|
struct config_value *v;
|
||||||
char **regex;
|
char **regex;
|
||||||
int count = 0, i, r = 0;
|
unsigned count = 0;
|
||||||
|
int i, r = 0;
|
||||||
|
|
||||||
if (!(scratch = pool_create(1024))) {
|
if (!(scratch = pool_create(1024))) {
|
||||||
stack;
|
stack;
|
||||||
@@ -137,7 +147,7 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
|||||||
* build the matcher.
|
* build the matcher.
|
||||||
*/
|
*/
|
||||||
if (!(rf->engine = matcher_create(rf->mem, (const char **) regex,
|
if (!(rf->engine = matcher_create(rf->mem, (const char **) regex,
|
||||||
count)))
|
count)))
|
||||||
stack;
|
stack;
|
||||||
r = 1;
|
r = 1;
|
||||||
|
|
||||||
@@ -161,6 +171,8 @@ static int _accept_p(struct dev_filter *f, struct device *dev)
|
|||||||
if (bit(rf->accept, m)) {
|
if (bit(rf->accept, m)) {
|
||||||
|
|
||||||
if (!first) {
|
if (!first) {
|
||||||
|
log_debug("%s: New preferred name",
|
||||||
|
sl->str);
|
||||||
list_del(&sl->list);
|
list_del(&sl->list);
|
||||||
list_add_h(&dev->aliases, &sl->list);
|
list_add_h(&dev->aliases, &sl->list);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the GPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_FILTER_REGEX_H
|
#ifndef _LVM_FILTER_REGEX_H
|
||||||
|
|||||||
288
lib/filters/filter-sysfs.c
Normal file
288
lib/filters/filter-sysfs.c
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
|
#include "filter-sysfs.h"
|
||||||
|
#include "lvm-string.h"
|
||||||
|
#include "pool.h"
|
||||||
|
|
||||||
|
#ifdef linux
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
static int _locate_sysfs_blocks(const char *proc, char *path, size_t len)
|
||||||
|
{
|
||||||
|
char proc_mounts[PATH_MAX];
|
||||||
|
int r = 0;
|
||||||
|
FILE *fp;
|
||||||
|
char *split[4], buffer[PATH_MAX + 16];
|
||||||
|
|
||||||
|
if (!*proc) {
|
||||||
|
log_verbose("No proc filesystem found: skipping sysfs filter");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lvm_snprintf(proc_mounts, sizeof(proc_mounts),
|
||||||
|
"%s/mounts", proc) < 0) {
|
||||||
|
log_error("Failed to create /proc/mounts string");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(fp = fopen(proc_mounts, "r"))) {
|
||||||
|
log_sys_error("fopen %s", proc_mounts);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fgets(buffer, sizeof(buffer), fp)) {
|
||||||
|
if (split_words(buffer, 4, split) == 4 &&
|
||||||
|
!strcmp(split[2], "sysfs")) {
|
||||||
|
if (lvm_snprintf(path, len, "%s/%s", split[1],
|
||||||
|
"block") >= 0) {
|
||||||
|
r = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------
|
||||||
|
* We need to store a set of dev_t.
|
||||||
|
*--------------------------------------------------------------*/
|
||||||
|
struct entry {
|
||||||
|
struct entry *next;
|
||||||
|
dev_t dev;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SET_BUCKETS 64
|
||||||
|
struct dev_set {
|
||||||
|
struct pool *mem;
|
||||||
|
const char *sys_block;
|
||||||
|
int initialised;
|
||||||
|
struct entry *slots[SET_BUCKETS];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dev_set *_dev_set_create(struct pool *mem, const char *sys_block)
|
||||||
|
{
|
||||||
|
struct dev_set *ds;
|
||||||
|
|
||||||
|
if (!(ds = pool_zalloc(mem, sizeof(*ds))))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ds->mem = mem;
|
||||||
|
ds->sys_block = pool_strdup(mem, sys_block);
|
||||||
|
ds->initialised = 0;
|
||||||
|
|
||||||
|
return ds;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned _hash_dev(dev_t dev)
|
||||||
|
{
|
||||||
|
return (major(dev) ^ minor(dev)) & (SET_BUCKETS - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Doesn't check that the set already contains dev.
|
||||||
|
*/
|
||||||
|
static int _set_insert(struct dev_set *ds, dev_t dev)
|
||||||
|
{
|
||||||
|
struct entry *e;
|
||||||
|
unsigned h = _hash_dev(dev);
|
||||||
|
|
||||||
|
if (!(e = pool_alloc(ds->mem, sizeof(*e))))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
e->next = ds->slots[h];
|
||||||
|
e->dev = dev;
|
||||||
|
ds->slots[h] = e;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _set_lookup(struct dev_set *ds, dev_t dev)
|
||||||
|
{
|
||||||
|
unsigned h = _hash_dev(dev);
|
||||||
|
struct entry *e;
|
||||||
|
|
||||||
|
for (e = ds->slots[h]; e; e = e->next)
|
||||||
|
if (e->dev == dev)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------
|
||||||
|
* filter methods
|
||||||
|
*--------------------------------------------------------------*/
|
||||||
|
static int _parse_dev(const char *file, FILE *fp, dev_t *result)
|
||||||
|
{
|
||||||
|
unsigned major, minor;
|
||||||
|
char buffer[64];
|
||||||
|
|
||||||
|
if (!fgets(buffer, sizeof(buffer), fp)) {
|
||||||
|
log_error("Empty sysfs device file: %s", file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sscanf(buffer, "%u:%u", &major, &minor) != 2) {
|
||||||
|
log_info("sysfs device file not correct format");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*result = makedev(major, minor);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _read_dev(const char *file, dev_t *result)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
if (!(fp = fopen(file, "r"))) {
|
||||||
|
log_sys_error("fopen", file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = _parse_dev(file, fp, result);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Recurse through sysfs directories, inserting any devs found.
|
||||||
|
*/
|
||||||
|
static int _read_devs(struct dev_set *ds, const char *dir)
|
||||||
|
{
|
||||||
|
struct dirent *d;
|
||||||
|
DIR *dr;
|
||||||
|
char path[PATH_MAX];
|
||||||
|
dev_t dev;
|
||||||
|
int r = 1;
|
||||||
|
|
||||||
|
if (!(dr = opendir(dir))) {
|
||||||
|
log_sys_error("opendir", dir);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((d = readdir(dr))) {
|
||||||
|
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (lvm_snprintf(path, sizeof(path), "%s/%s", dir,
|
||||||
|
d->d_name) < 0) {
|
||||||
|
log_error("sysfs path name too long: %s in %s",
|
||||||
|
d->d_name, dir);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d->d_type == DT_DIR) {
|
||||||
|
if (!_read_devs(ds, path)) {
|
||||||
|
r = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((d->d_type == DT_REG && !strcmp(d->d_name, "dev")))
|
||||||
|
if (!_read_dev(path, &dev) || !_set_insert(ds, dev)) {
|
||||||
|
r = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closedir(dr))
|
||||||
|
log_sys_error("closedir", dir);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _init_devs(struct dev_set *ds)
|
||||||
|
{
|
||||||
|
if (!_read_devs(ds, ds->sys_block)) {
|
||||||
|
ds->initialised = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ds->initialised = 1;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int _accept_p(struct dev_filter *f, struct device *dev)
|
||||||
|
{
|
||||||
|
struct dev_set *ds = (struct dev_set *) f->private;
|
||||||
|
|
||||||
|
if (!ds->initialised)
|
||||||
|
_init_devs(ds);
|
||||||
|
|
||||||
|
/* Pass through if initialisation failed */
|
||||||
|
if (ds->initialised != 1)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return _set_lookup(ds, dev->dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _destroy(struct dev_filter *f)
|
||||||
|
{
|
||||||
|
struct dev_set *ds = (struct dev_set *) f->private;
|
||||||
|
pool_destroy(ds->mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dev_filter *sysfs_filter_create(const char *proc)
|
||||||
|
{
|
||||||
|
char sys_block[PATH_MAX];
|
||||||
|
struct pool *mem;
|
||||||
|
struct dev_set *ds;
|
||||||
|
struct dev_filter *f;
|
||||||
|
|
||||||
|
if (!_locate_sysfs_blocks(proc, sys_block, sizeof(sys_block)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!(mem = pool_create(256))) {
|
||||||
|
log_error("sysfs pool creation failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(ds = _dev_set_create(mem, sys_block))) {
|
||||||
|
log_error("sysfs dev_set creation failed");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(f = pool_zalloc(mem, sizeof(*f)))) {
|
||||||
|
stack;
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
f->passes_filter = _accept_p;
|
||||||
|
f->destroy = _destroy;
|
||||||
|
f->private = ds;
|
||||||
|
return f;
|
||||||
|
|
||||||
|
bad:
|
||||||
|
pool_destroy(mem);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
struct dev_filter *sysfs_filter_create(const char *proc)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
23
lib/filters/filter-sysfs.h
Normal file
23
lib/filters/filter-sysfs.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LVM_FILTER_SYSFS_H
|
||||||
|
#define _LVM_FILTER_SYSFS_H
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "dev-cache.h"
|
||||||
|
|
||||||
|
struct dev_filter *sysfs_filter_create(const char *proc);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,49 +1,46 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* lvm is free software; you can redistribute it and/or modify
|
* This file is part of LVM2.
|
||||||
* 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,
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* of the GNU General Public License v.2.
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with GNU CC; see the file COPYING. If not, write to
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
* Boston, MA 02111-1307, USA.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dbg_malloc.h"
|
#include "lib.h"
|
||||||
#include "log.h"
|
|
||||||
#include "dev-cache.h"
|
#include "dev-cache.h"
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
#include "lvm-string.h"
|
#include "lvm-string.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <linux/kdev_t.h>
|
#include <limits.h>
|
||||||
|
|
||||||
#define NUMBER_OF_MAJORS 256
|
#define NUMBER_OF_MAJORS 256
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *name;
|
const char *name;
|
||||||
int max_partitions;
|
const int max_partitions;
|
||||||
} device_info_t;
|
} device_info_t;
|
||||||
|
|
||||||
static int _md_major = -1;
|
static int _md_major = -1;
|
||||||
|
|
||||||
static device_info_t device_info[] = {
|
int md_major(void)
|
||||||
|
{
|
||||||
|
return _md_major;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This list can be supplemented with devices/types in the config file */
|
||||||
|
static const device_info_t device_info[] = {
|
||||||
{"ide", 16}, /* IDE disk */
|
{"ide", 16}, /* IDE disk */
|
||||||
{"sd", 16}, /* SCSI disk */
|
{"sd", 16}, /* SCSI disk */
|
||||||
{"md", 16}, /* Multiple Disk driver (SoftRAID) */
|
{"md", 16}, /* Multiple Disk driver (SoftRAID) */
|
||||||
@@ -55,24 +52,28 @@ static device_info_t device_info[] = {
|
|||||||
{"cciss", 16}, /* Compaq CCISS array */
|
{"cciss", 16}, /* Compaq CCISS array */
|
||||||
{"ubd", 16}, /* User-mode virtual block device */
|
{"ubd", 16}, /* User-mode virtual block device */
|
||||||
{"ataraid", 16}, /* ATA Raid */
|
{"ataraid", 16}, /* ATA Raid */
|
||||||
|
{"drbd", 16}, /* Distributed Replicated Block Device */
|
||||||
|
{"power2", 16}, /* EMC Powerpath */
|
||||||
{NULL, 0}
|
{NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
static int *scan_proc_dev(const char *proc);
|
static int _passes_lvm_type_device_filter(struct dev_filter *f,
|
||||||
|
struct device *dev)
|
||||||
static int passes_lvm_type_device_filter(struct dev_filter *f,
|
|
||||||
struct device *dev)
|
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
const char *name = dev_name(dev);
|
const char *name = dev_name(dev);
|
||||||
|
|
||||||
/* Is this a recognised device type? */
|
/* Is this a recognised device type? */
|
||||||
if (!(((int *) f->private)[MAJOR(dev->dev)]))
|
if (!(((int *) f->private)[MAJOR(dev->dev)])) {
|
||||||
|
log_debug("%s: Skipping: Unrecognised LVM device type %"
|
||||||
|
PRIu64, name, (uint64_t) MAJOR(dev->dev));
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check it's accessible */
|
/* Check it's accessible */
|
||||||
if ((fd = open(name, O_RDONLY)) < 0) {
|
if ((fd = open(name, O_RDONLY)) < 0) {
|
||||||
log_debug("Unable to open %s: %s", name, strerror(errno));
|
log_debug("%s: Skipping: open failed: %s", name,
|
||||||
|
strerror(errno));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,48 +82,18 @@ static int passes_lvm_type_device_filter(struct dev_filter *f,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dev_filter *lvm_type_filter_create(const char *proc)
|
static int *_scan_proc_dev(const char *proc, struct config_node *cn)
|
||||||
{
|
|
||||||
struct dev_filter *f;
|
|
||||||
|
|
||||||
if (!(f = dbg_malloc(sizeof(struct dev_filter)))) {
|
|
||||||
log_error("LVM type filter allocation failed");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
f->passes_filter = passes_lvm_type_device_filter;
|
|
||||||
f->destroy = lvm_type_filter_destroy;
|
|
||||||
|
|
||||||
if (!(f->private = scan_proc_dev(proc)))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
int md_major(void)
|
|
||||||
{
|
|
||||||
return _md_major;
|
|
||||||
}
|
|
||||||
|
|
||||||
void lvm_type_filter_destroy(struct dev_filter *f)
|
|
||||||
{
|
|
||||||
dbg_free(f->private);
|
|
||||||
dbg_free(f);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int *scan_proc_dev(const char *proc)
|
|
||||||
{
|
{
|
||||||
char line[80];
|
char line[80];
|
||||||
char proc_devices[PATH_MAX];
|
char proc_devices[PATH_MAX];
|
||||||
FILE *pd = NULL;
|
FILE *pd = NULL;
|
||||||
int ret = 0;
|
|
||||||
int i, j = 0;
|
int i, j = 0;
|
||||||
int line_maj = 0;
|
int line_maj = 0;
|
||||||
int blocksection = 0;
|
int blocksection = 0;
|
||||||
int dev_len = 0;
|
size_t dev_len = 0;
|
||||||
|
struct config_value *cv;
|
||||||
int *max_partitions_by_major;
|
int *max_partitions_by_major;
|
||||||
|
char *name;
|
||||||
|
|
||||||
if (!(max_partitions_by_major =
|
if (!(max_partitions_by_major =
|
||||||
dbg_malloc(sizeof(int) * NUMBER_OF_MAJORS))) {
|
dbg_malloc(sizeof(int) * NUMBER_OF_MAJORS))) {
|
||||||
@@ -130,6 +101,14 @@ static int *scan_proc_dev(const char *proc)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!*proc) {
|
||||||
|
log_verbose("No proc filesystem found: using all block device "
|
||||||
|
"types");
|
||||||
|
for (i = 0; i < NUMBER_OF_MAJORS; i++)
|
||||||
|
max_partitions_by_major[i] = 1;
|
||||||
|
return max_partitions_by_major;
|
||||||
|
}
|
||||||
|
|
||||||
if (lvm_snprintf(proc_devices, sizeof(proc_devices),
|
if (lvm_snprintf(proc_devices, sizeof(proc_devices),
|
||||||
"%s/devices", proc) < 0) {
|
"%s/devices", proc) < 0) {
|
||||||
log_error("Failed to create /proc/devices string");
|
log_error("Failed to create /proc/devices string");
|
||||||
@@ -173,12 +152,44 @@ static int *scan_proc_dev(const char *proc)
|
|||||||
for (j = 0; device_info[j].name != NULL; j++) {
|
for (j = 0; device_info[j].name != NULL; j++) {
|
||||||
|
|
||||||
dev_len = strlen(device_info[j].name);
|
dev_len = strlen(device_info[j].name);
|
||||||
if (dev_len <= strlen(line + i)
|
if (dev_len <= strlen(line + i) &&
|
||||||
&& !strncmp(device_info[j].name, line + i, dev_len)
|
!strncmp(device_info[j].name, line + i, dev_len) &&
|
||||||
&& (line_maj < NUMBER_OF_MAJORS)) {
|
(line_maj < NUMBER_OF_MAJORS)) {
|
||||||
max_partitions_by_major[line_maj] =
|
max_partitions_by_major[line_maj] =
|
||||||
device_info[j].max_partitions;
|
device_info[j].max_partitions;
|
||||||
ret++;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_partitions_by_major[line_maj] || !cn)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Check devices/types for local variations */
|
||||||
|
for (cv = cn->v; cv; cv = cv->next) {
|
||||||
|
if (cv->type != CFG_STRING) {
|
||||||
|
log_error("Expecting string in devices/types "
|
||||||
|
"in config file");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
dev_len = strlen(cv->v.str);
|
||||||
|
name = cv->v.str;
|
||||||
|
cv = cv->next;
|
||||||
|
if (!cv || cv->type != CFG_INT) {
|
||||||
|
log_error("Max partition count missing for %s "
|
||||||
|
"in devices/types in config file",
|
||||||
|
name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!cv->v.i) {
|
||||||
|
log_error("Zero partition count invalid for "
|
||||||
|
"%s in devices/types in config file",
|
||||||
|
name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (dev_len <= strlen(line + i) &&
|
||||||
|
!strncmp(name, line + i, dev_len) &&
|
||||||
|
(line_maj < NUMBER_OF_MAJORS)) {
|
||||||
|
max_partitions_by_major[line_maj] = cv->v.i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -186,3 +197,31 @@ static int *scan_proc_dev(const char *proc)
|
|||||||
fclose(pd);
|
fclose(pd);
|
||||||
return max_partitions_by_major;
|
return max_partitions_by_major;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct dev_filter *lvm_type_filter_create(const char *proc,
|
||||||
|
struct config_node *cn)
|
||||||
|
{
|
||||||
|
struct dev_filter *f;
|
||||||
|
|
||||||
|
if (!(f = dbg_malloc(sizeof(struct dev_filter)))) {
|
||||||
|
log_error("LVM type filter allocation failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
f->passes_filter = _passes_lvm_type_device_filter;
|
||||||
|
f->destroy = lvm_type_filter_destroy;
|
||||||
|
|
||||||
|
if (!(f->private = _scan_proc_dev(proc, cn))) {
|
||||||
|
stack;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lvm_type_filter_destroy(struct dev_filter *f)
|
||||||
|
{
|
||||||
|
dbg_free(f->private);
|
||||||
|
dbg_free(f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,31 +1,38 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* lvm is free software; you can redistribute it and/or modify
|
* This file is part of LVM2.
|
||||||
* 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,
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* of the GNU General Public License v.2.
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with GNU CC; see the file COPYING. If not, write to
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
* Boston, MA 02111-1307, USA.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_FILTER_H
|
#ifndef _LVM_FILTER_H
|
||||||
#define _LVM_FILTER_H
|
#define _LVM_FILTER_H
|
||||||
|
|
||||||
struct dev_filter *lvm_type_filter_create(const char *proc);
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#ifdef linux
|
||||||
|
# include <linux/kdev_t.h>
|
||||||
|
#else
|
||||||
|
# define MAJOR(x) major((x))
|
||||||
|
# define MINOR(x) minor((x))
|
||||||
|
# define MKDEV(x,y) makedev((x),(y))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct dev_filter *lvm_type_filter_create(const char *proc,
|
||||||
|
struct config_node *cn);
|
||||||
|
|
||||||
void lvm_type_filter_destroy(struct dev_filter *f);
|
void lvm_type_filter_destroy(struct dev_filter *f);
|
||||||
|
|
||||||
int md_major(void);
|
int md_major(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
1
lib/format1/.exported_symbols
Normal file
1
lib/format1/.exported_symbols
Normal file
@@ -0,0 +1 @@
|
|||||||
|
init_format
|
||||||
38
lib/format1/Makefile.in
Normal file
38
lib/format1/Makefile.in
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#
|
||||||
|
# Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
|
#
|
||||||
|
# This file is part of the LVM2.
|
||||||
|
#
|
||||||
|
# This copyrighted material is made available to anyone wishing to use,
|
||||||
|
# modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
# of the GNU General Public License v.2.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
srcdir = @srcdir@
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
VPATH = @srcdir@
|
||||||
|
|
||||||
|
SOURCES =\
|
||||||
|
disk-rep.c \
|
||||||
|
format1.c \
|
||||||
|
import-export.c \
|
||||||
|
import-extents.c \
|
||||||
|
layout.c \
|
||||||
|
lvm1-label.c \
|
||||||
|
vg_number.c
|
||||||
|
|
||||||
|
LIB_SHARED = liblvm2format1.so
|
||||||
|
|
||||||
|
include ../../make.tmpl
|
||||||
|
|
||||||
|
.PHONY: install
|
||||||
|
|
||||||
|
install: liblvm2format1.so
|
||||||
|
$(INSTALL) -D -o $(OWNER) -g $(GROUP) -m 555 $(STRIP) $< \
|
||||||
|
$(libdir)/liblvm2format1.so.$(LIB_VERSION)
|
||||||
|
$(LN_S) -f liblvm2format1.so.$(LIB_VERSION) $(libdir)/liblvm2format1.so
|
||||||
|
|
||||||
@@ -1,21 +1,26 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
#include "disk-rep.h"
|
#include "disk-rep.h"
|
||||||
#include "dbg_malloc.h"
|
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
#include "xlate.h"
|
#include "xlate.h"
|
||||||
#include "log.h"
|
|
||||||
#include "vgcache.h"
|
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
|
#include "lvmcache.h"
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <linux/kdev_t.h>
|
|
||||||
|
|
||||||
#define fail do {stack; return 0;} while(0)
|
#define fail do {stack; return 0;} while(0)
|
||||||
#define xx16(v) disk->v = xlate16(disk->v)
|
#define xx16(v) disk->v = xlate16(disk->v)
|
||||||
@@ -96,7 +101,7 @@ static void _xlate_vgd(struct vg_disk *disk)
|
|||||||
xx32(pvg_total);
|
xx32(pvg_total);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _xlate_extents(struct pe_disk *extents, int count)
|
static void _xlate_extents(struct pe_disk *extents, uint32_t count)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -116,12 +121,12 @@ static int _munge_formats(struct pv_disk *pvd)
|
|||||||
switch (pvd->version) {
|
switch (pvd->version) {
|
||||||
case 1:
|
case 1:
|
||||||
pvd->pe_start = ((pvd->pe_on_disk.base +
|
pvd->pe_start = ((pvd->pe_on_disk.base +
|
||||||
pvd->pe_on_disk.size) / SECTOR_SIZE);
|
pvd->pe_on_disk.size) >> SECTOR_SHIFT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
pvd->version = 1;
|
pvd->version = 1;
|
||||||
pe_start = pvd->pe_start * SECTOR_SIZE;
|
pe_start = pvd->pe_start << SECTOR_SHIFT;
|
||||||
pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base;
|
pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -132,9 +137,9 @@ static int _munge_formats(struct pv_disk *pvd)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_pvd(struct device *dev, struct pv_disk *pvd)
|
static int _read_pvd(struct device *dev, struct pv_disk *pvd)
|
||||||
{
|
{
|
||||||
if (dev_read(dev, 0, sizeof(*pvd), pvd) != sizeof(*pvd)) {
|
if (!dev_read(dev, UINT64_C(0), sizeof(*pvd), pvd)) {
|
||||||
log_very_verbose("Failed to read PV data from %s",
|
log_very_verbose("Failed to read PV data from %s",
|
||||||
dev_name(dev));
|
dev_name(dev));
|
||||||
return 0;
|
return 0;
|
||||||
@@ -143,23 +148,27 @@ int read_pvd(struct device *dev, struct pv_disk *pvd)
|
|||||||
_xlate_pvd(pvd);
|
_xlate_pvd(pvd);
|
||||||
|
|
||||||
if (pvd->id[0] != 'H' || pvd->id[1] != 'M') {
|
if (pvd->id[0] != 'H' || pvd->id[1] != 'M') {
|
||||||
log_very_verbose("%s does not have a valid PV identifier",
|
log_very_verbose("%s does not have a valid LVM1 PV identifier",
|
||||||
dev_name(dev));
|
dev_name(dev));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_munge_formats(pvd)) {
|
if (!_munge_formats(pvd)) {
|
||||||
log_very_verbose("Unknown metadata version %d found on %s",
|
log_very_verbose("format1: Unknown metadata version %d "
|
||||||
pvd->version, dev_name(dev));
|
"found on %s", pvd->version, dev_name(dev));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If UUID is missing, create one */
|
||||||
|
if (pvd->pv_uuid[0] == '\0')
|
||||||
|
uuid_from_num(pvd->pv_uuid, pvd->pv_number);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _read_lvd(struct device *dev, ulong pos, struct lv_disk *disk)
|
static int _read_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
|
||||||
{
|
{
|
||||||
if (dev_read(dev, pos, sizeof(*disk), disk) != sizeof(*disk))
|
if (!dev_read(dev, pos, sizeof(*disk), disk))
|
||||||
fail;
|
fail;
|
||||||
|
|
||||||
_xlate_lvd(disk);
|
_xlate_lvd(disk);
|
||||||
@@ -170,12 +179,16 @@ static int _read_lvd(struct device *dev, ulong pos, struct lv_disk *disk)
|
|||||||
static int _read_vgd(struct disk_list *data)
|
static int _read_vgd(struct disk_list *data)
|
||||||
{
|
{
|
||||||
struct vg_disk *vgd = &data->vgd;
|
struct vg_disk *vgd = &data->vgd;
|
||||||
ulong pos = data->pvd.vg_on_disk.base;
|
uint64_t pos = data->pvd.vg_on_disk.base;
|
||||||
if (dev_read(data->dev, pos, sizeof(*vgd), vgd) != sizeof(*vgd))
|
if (!dev_read(data->dev, pos, sizeof(*vgd), vgd))
|
||||||
fail;
|
fail;
|
||||||
|
|
||||||
_xlate_vgd(vgd);
|
_xlate_vgd(vgd);
|
||||||
|
|
||||||
|
/* If UUID is missing, create one */
|
||||||
|
if (vgd->vg_uuid[0] == '\0')
|
||||||
|
uuid_from_num(vgd->vg_uuid, vgd->vg_number);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,12 +197,11 @@ static int _read_uuids(struct disk_list *data)
|
|||||||
int num_read = 0;
|
int num_read = 0;
|
||||||
struct uuid_list *ul;
|
struct uuid_list *ul;
|
||||||
char buffer[NAME_LEN];
|
char buffer[NAME_LEN];
|
||||||
ulong pos = data->pvd.pv_uuidlist_on_disk.base;
|
uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
|
||||||
ulong end = pos + data->pvd.pv_uuidlist_on_disk.size;
|
uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
|
||||||
|
|
||||||
while (pos < end && num_read < data->vgd.pv_cur) {
|
while (pos < end && num_read < data->vgd.pv_cur) {
|
||||||
if (dev_read(data->dev, pos, sizeof(buffer), buffer) !=
|
if (!dev_read(data->dev, pos, sizeof(buffer), buffer))
|
||||||
sizeof(buffer))
|
|
||||||
fail;
|
fail;
|
||||||
|
|
||||||
if (!(ul = pool_alloc(data->mem, sizeof(*ul))))
|
if (!(ul = pool_alloc(data->mem, sizeof(*ul))))
|
||||||
@@ -214,8 +226,8 @@ static inline int _check_lvd(struct lv_disk *lvd)
|
|||||||
|
|
||||||
static int _read_lvs(struct disk_list *data)
|
static int _read_lvs(struct disk_list *data)
|
||||||
{
|
{
|
||||||
int i, read = 0;
|
unsigned int i, read = 0;
|
||||||
ulong pos;
|
uint64_t pos;
|
||||||
struct lvd_list *ll;
|
struct lvd_list *ll;
|
||||||
struct vg_disk *vgd = &data->vgd;
|
struct vg_disk *vgd = &data->vgd;
|
||||||
|
|
||||||
@@ -243,12 +255,12 @@ static int _read_extents(struct disk_list *data)
|
|||||||
{
|
{
|
||||||
size_t len = sizeof(struct pe_disk) * data->pvd.pe_total;
|
size_t len = sizeof(struct pe_disk) * data->pvd.pe_total;
|
||||||
struct pe_disk *extents = pool_alloc(data->mem, len);
|
struct pe_disk *extents = pool_alloc(data->mem, len);
|
||||||
ulong pos = data->pvd.pe_on_disk.base;
|
uint64_t pos = data->pvd.pe_on_disk.base;
|
||||||
|
|
||||||
if (!extents)
|
if (!extents)
|
||||||
fail;
|
fail;
|
||||||
|
|
||||||
if (dev_read(data->dev, pos, len, extents) != len)
|
if (!dev_read(data->dev, pos, len, extents))
|
||||||
fail;
|
fail;
|
||||||
|
|
||||||
_xlate_extents(extents, data->pvd.pe_total);
|
_xlate_extents(extents, data->pvd.pe_total);
|
||||||
@@ -260,28 +272,30 @@ static int _read_extents(struct disk_list *data)
|
|||||||
/*
|
/*
|
||||||
* If exported, remove "PV_EXP" from end of VG name
|
* If exported, remove "PV_EXP" from end of VG name
|
||||||
*/
|
*/
|
||||||
static void _munge_exported_vg(struct disk_list *data)
|
void munge_exported_vg(struct pv_disk *pvd)
|
||||||
{
|
{
|
||||||
int l, s;
|
int l;
|
||||||
|
size_t s;
|
||||||
|
|
||||||
/* Return if PV not in a VG or VG not exported */
|
/* Return if PV not in a VG */
|
||||||
if ((!*data->pvd.vg_name) || !(data->vgd.vg_status & VG_EXPORTED))
|
if ((!*pvd->vg_name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
l = strlen(data->pvd.vg_name);
|
l = strlen(pvd->vg_name);
|
||||||
s = sizeof(EXPORTED_TAG);
|
s = sizeof(EXPORTED_TAG);
|
||||||
if (!strncmp(data->pvd.vg_name + l - s + 1, EXPORTED_TAG, s))
|
if (!strncmp(pvd->vg_name + l - s + 1, EXPORTED_TAG, s)) {
|
||||||
data->pvd.vg_name[l - s + 1] = '\0';
|
pvd->vg_name[l - s + 1] = '\0';
|
||||||
|
pvd->pv_status |= VG_EXPORTED;
|
||||||
data->pvd.pv_status |= VG_EXPORTED;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct disk_list *__read_disk(struct format_type *fmt,
|
static struct disk_list *__read_disk(const struct format_type *fmt,
|
||||||
struct device *dev, struct pool *mem,
|
struct device *dev, struct pool *mem,
|
||||||
const char *vg_name)
|
const char *vg_name)
|
||||||
{
|
{
|
||||||
struct disk_list *dl = pool_alloc(mem, sizeof(*dl));
|
struct disk_list *dl = pool_alloc(mem, sizeof(*dl));
|
||||||
const char *name = dev_name(dev);
|
const char *name = dev_name(dev);
|
||||||
|
struct lvmcache_info *info;
|
||||||
|
|
||||||
if (!dl) {
|
if (!dl) {
|
||||||
stack;
|
stack;
|
||||||
@@ -293,11 +307,23 @@ static struct disk_list *__read_disk(struct format_type *fmt,
|
|||||||
list_init(&dl->uuids);
|
list_init(&dl->uuids);
|
||||||
list_init(&dl->lvds);
|
list_init(&dl->lvds);
|
||||||
|
|
||||||
if (!read_pvd(dev, &dl->pvd)) {
|
if (!_read_pvd(dev, &dl->pvd)) {
|
||||||
stack;
|
stack;
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If VG is exported, set VG name back to the real name */
|
||||||
|
munge_exported_vg(&dl->pvd);
|
||||||
|
|
||||||
|
if (!(info = lvmcache_add(fmt->labeller, dl->pvd.pv_uuid, dev,
|
||||||
|
dl->pvd.vg_name, NULL)))
|
||||||
|
stack;
|
||||||
|
else {
|
||||||
|
info->device_size = xlate32(dl->pvd.pv_size) << SECTOR_SHIFT;
|
||||||
|
list_init(&info->mdas);
|
||||||
|
info->status &= ~CACHE_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* is it an orphan ?
|
* is it an orphan ?
|
||||||
*/
|
*/
|
||||||
@@ -305,7 +331,7 @@ static struct disk_list *__read_disk(struct format_type *fmt,
|
|||||||
log_very_verbose("%s is not a member of any format1 VG", name);
|
log_very_verbose("%s is not a member of any format1 VG", name);
|
||||||
|
|
||||||
/* Update VG cache */
|
/* Update VG cache */
|
||||||
vgcache_add(dl->pvd.vg_name, NULL, dev, fmt);
|
/* vgcache_add(dl->pvd.vg_name, NULL, dev, fmt); */
|
||||||
|
|
||||||
return (vg_name) ? NULL : dl;
|
return (vg_name) ? NULL : dl;
|
||||||
}
|
}
|
||||||
@@ -315,11 +341,8 @@ static struct disk_list *__read_disk(struct format_type *fmt,
|
|||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If VG is exported, set VG name back to the real name */
|
|
||||||
_munge_exported_vg(dl);
|
|
||||||
|
|
||||||
/* Update VG cache with what we found */
|
/* Update VG cache with what we found */
|
||||||
vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt);
|
/* vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt); */
|
||||||
|
|
||||||
if (vg_name && strcmp(vg_name, dl->pvd.vg_name)) {
|
if (vg_name && strcmp(vg_name, dl->pvd.vg_name)) {
|
||||||
log_very_verbose("%s is not a member of the VG %s",
|
log_very_verbose("%s is not a member of the VG %s",
|
||||||
@@ -353,12 +376,12 @@ static struct disk_list *__read_disk(struct format_type *fmt,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct disk_list *read_disk(struct format_type *fmt, struct device *dev,
|
struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
|
||||||
struct pool *mem, const char *vg_name)
|
struct pool *mem, const char *vg_name)
|
||||||
{
|
{
|
||||||
struct disk_list *r;
|
struct disk_list *r;
|
||||||
|
|
||||||
if (!dev_open(dev, O_RDONLY)) {
|
if (!dev_open(dev)) {
|
||||||
stack;
|
stack;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -400,21 +423,22 @@ static void _add_pv_to_list(struct list *head, struct disk_list *data)
|
|||||||
* We keep track of the first object allocated form the pool
|
* We keep track of the first object allocated form the pool
|
||||||
* so we can free off all the memory if something goes wrong.
|
* so we can free off all the memory if something goes wrong.
|
||||||
*/
|
*/
|
||||||
int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
|
int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
|
||||||
struct dev_filter *filter, struct pool *mem,
|
struct dev_filter *filter, struct pool *mem,
|
||||||
struct list *head)
|
struct list *head)
|
||||||
{
|
{
|
||||||
struct dev_iter *iter;
|
struct dev_iter *iter;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct disk_list *data = NULL;
|
struct disk_list *data = NULL;
|
||||||
|
struct list *vgih;
|
||||||
struct list *pvdh, *pvdh2;
|
struct lvmcache_vginfo *vginfo;
|
||||||
|
|
||||||
/* Fast path if we already saw this VG and cached the list of PVs */
|
/* Fast path if we already saw this VG and cached the list of PVs */
|
||||||
if ((pvdh = vgcache_find(vg_name))) {
|
if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) &&
|
||||||
list_iterate(pvdh2, pvdh) {
|
vginfo->infos.n) {
|
||||||
dev = list_item(pvdh2, struct pvdev_list)->dev;
|
list_iterate(vgih, &vginfo->infos) {
|
||||||
if (!(data = read_disk(fmt, dev, mem, vg_name)))
|
dev = list_item(vgih, struct lvmcache_info)->dev;
|
||||||
|
if (dev && !(data = read_disk(fmt, dev, mem, vg_name)))
|
||||||
break;
|
break;
|
||||||
_add_pv_to_list(head, data);
|
_add_pv_to_list(head, data);
|
||||||
}
|
}
|
||||||
@@ -422,11 +446,12 @@ int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
|
|||||||
/* Did we find the whole VG? */
|
/* Did we find the whole VG? */
|
||||||
if (!vg_name || !*vg_name ||
|
if (!vg_name || !*vg_name ||
|
||||||
(data && *data->pvd.vg_name &&
|
(data && *data->pvd.vg_name &&
|
||||||
list_size(head) == data->vgd.pv_cur)) return 1;
|
list_size(head) == data->vgd.pv_cur))
|
||||||
|
return 1;
|
||||||
|
|
||||||
/* Something changed. Remove the hints. */
|
/* Failed */
|
||||||
list_init(head);
|
list_init(head);
|
||||||
vgcache_del(vg_name);
|
/* vgcache_del(vg_name); */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(iter = dev_iter_create(filter))) {
|
if (!(iter = dev_iter_create(filter))) {
|
||||||
@@ -451,10 +476,10 @@ int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
|
|||||||
static int _write_vgd(struct disk_list *data)
|
static int _write_vgd(struct disk_list *data)
|
||||||
{
|
{
|
||||||
struct vg_disk *vgd = &data->vgd;
|
struct vg_disk *vgd = &data->vgd;
|
||||||
ulong pos = data->pvd.vg_on_disk.base;
|
uint64_t pos = data->pvd.vg_on_disk.base;
|
||||||
|
|
||||||
_xlate_vgd(vgd);
|
_xlate_vgd(vgd);
|
||||||
if (dev_write(data->dev, pos, sizeof(*vgd), vgd) != sizeof(*vgd))
|
if (!dev_write(data->dev, pos, sizeof(*vgd), vgd))
|
||||||
fail;
|
fail;
|
||||||
|
|
||||||
_xlate_vgd(vgd);
|
_xlate_vgd(vgd);
|
||||||
@@ -466,8 +491,8 @@ static int _write_uuids(struct disk_list *data)
|
|||||||
{
|
{
|
||||||
struct uuid_list *ul;
|
struct uuid_list *ul;
|
||||||
struct list *uh;
|
struct list *uh;
|
||||||
ulong pos = data->pvd.pv_uuidlist_on_disk.base;
|
uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
|
||||||
ulong end = pos + data->pvd.pv_uuidlist_on_disk.size;
|
uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
|
||||||
|
|
||||||
list_iterate(uh, &data->uuids) {
|
list_iterate(uh, &data->uuids) {
|
||||||
if (pos >= end) {
|
if (pos >= end) {
|
||||||
@@ -477,7 +502,7 @@ static int _write_uuids(struct disk_list *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ul = list_item(uh, struct uuid_list);
|
ul = list_item(uh, struct uuid_list);
|
||||||
if (dev_write(data->dev, pos, NAME_LEN, ul->uuid) != NAME_LEN)
|
if (!dev_write(data->dev, pos, NAME_LEN, ul->uuid))
|
||||||
fail;
|
fail;
|
||||||
|
|
||||||
pos += NAME_LEN;
|
pos += NAME_LEN;
|
||||||
@@ -486,10 +511,10 @@ static int _write_uuids(struct disk_list *data)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _write_lvd(struct device *dev, ulong pos, struct lv_disk *disk)
|
static int _write_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
|
||||||
{
|
{
|
||||||
_xlate_lvd(disk);
|
_xlate_lvd(disk);
|
||||||
if (dev_write(dev, pos, sizeof(*disk), disk) != sizeof(*disk))
|
if (!dev_write(dev, pos, sizeof(*disk), disk))
|
||||||
fail;
|
fail;
|
||||||
|
|
||||||
_xlate_lvd(disk);
|
_xlate_lvd(disk);
|
||||||
@@ -500,7 +525,7 @@ static int _write_lvd(struct device *dev, ulong pos, struct lv_disk *disk)
|
|||||||
static int _write_lvs(struct disk_list *data)
|
static int _write_lvs(struct disk_list *data)
|
||||||
{
|
{
|
||||||
struct list *lvh;
|
struct list *lvh;
|
||||||
ulong pos;
|
uint64_t pos, offset;
|
||||||
|
|
||||||
pos = data->pvd.lv_on_disk.base;
|
pos = data->pvd.lv_on_disk.base;
|
||||||
|
|
||||||
@@ -513,10 +538,14 @@ static int _write_lvs(struct disk_list *data)
|
|||||||
list_iterate(lvh, &data->lvds) {
|
list_iterate(lvh, &data->lvds) {
|
||||||
struct lvd_list *ll = list_item(lvh, struct lvd_list);
|
struct lvd_list *ll = list_item(lvh, struct lvd_list);
|
||||||
|
|
||||||
if (!_write_lvd(data->dev, pos, &ll->lvd))
|
offset = sizeof(struct lv_disk) * ll->lvd.lv_number;
|
||||||
fail;
|
if (offset + sizeof(struct lv_disk) > data->pvd.lv_on_disk.size) {
|
||||||
|
log_error("lv_number %d too large", ll->lvd.lv_number);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
pos += sizeof(struct lv_disk);
|
if (!_write_lvd(data->dev, pos + offset, &ll->lvd))
|
||||||
|
fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -526,10 +555,10 @@ static int _write_extents(struct disk_list *data)
|
|||||||
{
|
{
|
||||||
size_t len = sizeof(struct pe_disk) * data->pvd.pe_total;
|
size_t len = sizeof(struct pe_disk) * data->pvd.pe_total;
|
||||||
struct pe_disk *extents = data->extents;
|
struct pe_disk *extents = data->extents;
|
||||||
ulong pos = data->pvd.pe_on_disk.base;
|
uint64_t pos = data->pvd.pe_on_disk.base;
|
||||||
|
|
||||||
_xlate_extents(extents, data->pvd.pe_total);
|
_xlate_extents(extents, data->pvd.pe_total);
|
||||||
if (dev_write(data->dev, pos, len, extents) != len)
|
if (!dev_write(data->dev, pos, len, extents))
|
||||||
fail;
|
fail;
|
||||||
|
|
||||||
_xlate_extents(extents, data->pvd.pe_total);
|
_xlate_extents(extents, data->pvd.pe_total);
|
||||||
@@ -540,8 +569,8 @@ static int _write_extents(struct disk_list *data)
|
|||||||
static int _write_pvd(struct disk_list *data)
|
static int _write_pvd(struct disk_list *data)
|
||||||
{
|
{
|
||||||
char *buf;
|
char *buf;
|
||||||
ulong pos = data->pvd.pv_on_disk.base;
|
uint64_t pos = data->pvd.pv_on_disk.base;
|
||||||
ulong size = data->pvd.pv_on_disk.size;
|
size_t size = data->pvd.pv_on_disk.size;
|
||||||
|
|
||||||
if (size < sizeof(struct pv_disk)) {
|
if (size < sizeof(struct pv_disk)) {
|
||||||
log_error("Invalid PV structure size.");
|
log_error("Invalid PV structure size.");
|
||||||
@@ -561,7 +590,7 @@ static int _write_pvd(struct disk_list *data)
|
|||||||
memcpy(buf, &data->pvd, sizeof(struct pv_disk));
|
memcpy(buf, &data->pvd, sizeof(struct pv_disk));
|
||||||
|
|
||||||
_xlate_pvd((struct pv_disk *) buf);
|
_xlate_pvd((struct pv_disk *) buf);
|
||||||
if (dev_write(data->dev, pos, size, buf) != size) {
|
if (!dev_write(data->dev, pos, size, buf)) {
|
||||||
dbg_free(buf);
|
dbg_free(buf);
|
||||||
fail;
|
fail;
|
||||||
}
|
}
|
||||||
@@ -573,7 +602,8 @@ static int _write_pvd(struct disk_list *data)
|
|||||||
/*
|
/*
|
||||||
* assumes the device has been opened.
|
* assumes the device has been opened.
|
||||||
*/
|
*/
|
||||||
static int __write_all_pvd(struct format_type *fmt, struct disk_list *data)
|
static int __write_all_pvd(const struct format_type *fmt,
|
||||||
|
struct disk_list *data)
|
||||||
{
|
{
|
||||||
const char *pv_name = dev_name(data->dev);
|
const char *pv_name = dev_name(data->dev);
|
||||||
|
|
||||||
@@ -582,19 +612,19 @@ static int __write_all_pvd(struct format_type *fmt, struct disk_list *data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt);
|
/* vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt); */
|
||||||
/*
|
/*
|
||||||
* Stop here for orphan pv's.
|
* Stop here for orphan pv's.
|
||||||
*/
|
*/
|
||||||
if (data->pvd.vg_name[0] == '\0') {
|
if (data->pvd.vg_name[0] == '\0') {
|
||||||
if (!test_mode())
|
/* if (!test_mode())
|
||||||
vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt);
|
vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt); */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!test_mode())
|
/* if (!test_mode())
|
||||||
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev,
|
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev,
|
||||||
fmt);
|
fmt); */
|
||||||
|
|
||||||
if (!_write_vgd(data)) {
|
if (!_write_vgd(data)) {
|
||||||
log_error("Failed to write VG data to %s", pv_name);
|
log_error("Failed to write VG data to %s", pv_name);
|
||||||
@@ -622,11 +652,11 @@ static int __write_all_pvd(struct format_type *fmt, struct disk_list *data)
|
|||||||
/*
|
/*
|
||||||
* opens the device and hands to the above fn.
|
* opens the device and hands to the above fn.
|
||||||
*/
|
*/
|
||||||
static int _write_all_pvd(struct format_type *fmt, struct disk_list *data)
|
static int _write_all_pvd(const struct format_type *fmt, struct disk_list *data)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!dev_open(data->dev, O_WRONLY)) {
|
if (!dev_open(data->dev)) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -644,7 +674,7 @@ static int _write_all_pvd(struct format_type *fmt, struct disk_list *data)
|
|||||||
* little sanity checking, so make sure correct
|
* little sanity checking, so make sure correct
|
||||||
* data is passed to here.
|
* data is passed to here.
|
||||||
*/
|
*/
|
||||||
int write_disks(struct format_type *fmt, struct list *pvs)
|
int write_disks(const struct format_type *fmt, struct list *pvs)
|
||||||
{
|
{
|
||||||
struct list *pvh;
|
struct list *pvh;
|
||||||
struct disk_list *dl;
|
struct disk_list *dl;
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the GPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef DISK_REP_FORMAT1_H
|
#ifndef DISK_REP_FORMAT1_H
|
||||||
@@ -10,21 +19,20 @@
|
|||||||
#include "lvm-types.h"
|
#include "lvm-types.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
|
#include "toolcontext.h"
|
||||||
|
|
||||||
#define SECTOR_SIZE 512
|
|
||||||
|
|
||||||
#define MAX_PV 256
|
#define MAX_PV 256
|
||||||
#define MAX_LV 256
|
#define MAX_LV 256
|
||||||
#define MAX_VG 99
|
#define MAX_VG 99
|
||||||
|
|
||||||
#define MAX_PV_SIZE ((uint32_t) -1) /* 2TB in sectors - 1 */
|
#define LVM_BLK_MAJOR 58
|
||||||
#define MIN_PE_SIZE (8192L / SECTOR_SIZE) /* 8 KB in sectors */
|
|
||||||
#define MAX_PE_SIZE (16L * 1024L * 1024L / SECTOR_SIZE * 1024)
|
|
||||||
#define PE_SIZE_PV_SIZE_REL 5 /* PV size must be at least 5 times PE size */
|
|
||||||
#define MAX_LE_TOTAL 65534 /* 2^16 - 2 */
|
|
||||||
#define MAX_PE_TOTAL ((uint32_t) -2)
|
|
||||||
|
|
||||||
|
#define MAX_PV_SIZE ((uint32_t) -1) /* 2TB in sectors - 1 */
|
||||||
|
#define MIN_PE_SIZE (8192L >> SECTOR_SHIFT) /* 8 KB in sectors */
|
||||||
|
#define MAX_PE_SIZE (16L * 1024L * (1024L >> SECTOR_SHIFT) * 1024L)
|
||||||
|
#define PE_SIZE_PV_SIZE_REL 5 /* PV size must be at least 5 times PE size */
|
||||||
|
#define MAX_LE_TOTAL 65534 /* 2^16 - 2 */
|
||||||
|
#define MAX_PE_TOTAL ((uint32_t) -2)
|
||||||
|
|
||||||
#define UNMAPPED_EXTENT 0
|
#define UNMAPPED_EXTENT 0
|
||||||
|
|
||||||
@@ -60,86 +68,84 @@
|
|||||||
#define EXPORTED_TAG "PV_EXP" /* Identifier for exported PV */
|
#define EXPORTED_TAG "PV_EXP" /* Identifier for exported PV */
|
||||||
#define IMPORTED_TAG "PV_IMP" /* Identifier for imported PV */
|
#define IMPORTED_TAG "PV_IMP" /* Identifier for imported PV */
|
||||||
|
|
||||||
|
|
||||||
struct data_area {
|
struct data_area {
|
||||||
uint32_t base;
|
uint32_t base;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
};
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct pv_disk {
|
struct pv_disk {
|
||||||
uint8_t id[2];
|
uint8_t id[2];
|
||||||
uint16_t version; /* lvm version */
|
uint16_t version; /* lvm version */
|
||||||
struct data_area pv_on_disk;
|
struct data_area pv_on_disk;
|
||||||
struct data_area vg_on_disk;
|
struct data_area vg_on_disk;
|
||||||
struct data_area pv_uuidlist_on_disk;
|
struct data_area pv_uuidlist_on_disk;
|
||||||
struct data_area lv_on_disk;
|
struct data_area lv_on_disk;
|
||||||
struct data_area pe_on_disk;
|
struct data_area pe_on_disk;
|
||||||
uint8_t pv_uuid[NAME_LEN];
|
uint8_t pv_uuid[NAME_LEN];
|
||||||
uint8_t vg_name[NAME_LEN];
|
uint8_t vg_name[NAME_LEN];
|
||||||
uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */
|
uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */
|
||||||
uint32_t pv_major;
|
uint32_t pv_major;
|
||||||
uint32_t pv_number;
|
uint32_t pv_number;
|
||||||
uint32_t pv_status;
|
uint32_t pv_status;
|
||||||
uint32_t pv_allocatable;
|
uint32_t pv_allocatable;
|
||||||
uint32_t pv_size;
|
uint32_t pv_size;
|
||||||
uint32_t lv_cur;
|
uint32_t lv_cur;
|
||||||
uint32_t pe_size;
|
uint32_t pe_size;
|
||||||
uint32_t pe_total;
|
uint32_t pe_total;
|
||||||
uint32_t pe_allocated;
|
uint32_t pe_allocated;
|
||||||
|
|
||||||
/* only present on version == 2 pv's */
|
/* only present on version == 2 pv's */
|
||||||
uint32_t pe_start;
|
uint32_t pe_start;
|
||||||
};
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct lv_disk {
|
struct lv_disk {
|
||||||
uint8_t lv_name[NAME_LEN];
|
uint8_t lv_name[NAME_LEN];
|
||||||
uint8_t vg_name[NAME_LEN];
|
uint8_t vg_name[NAME_LEN];
|
||||||
uint32_t lv_access;
|
uint32_t lv_access;
|
||||||
uint32_t lv_status;
|
uint32_t lv_status;
|
||||||
uint32_t lv_open;
|
uint32_t lv_open;
|
||||||
uint32_t lv_dev;
|
uint32_t lv_dev;
|
||||||
uint32_t lv_number;
|
uint32_t lv_number;
|
||||||
uint32_t lv_mirror_copies; /* for future use */
|
uint32_t lv_mirror_copies; /* for future use */
|
||||||
uint32_t lv_recovery; /* " */
|
uint32_t lv_recovery; /* " */
|
||||||
uint32_t lv_schedule; /* " */
|
uint32_t lv_schedule; /* " */
|
||||||
uint32_t lv_size;
|
uint32_t lv_size;
|
||||||
uint32_t lv_snapshot_minor; /* minor number of original */
|
uint32_t lv_snapshot_minor; /* minor number of original */
|
||||||
uint16_t lv_chunk_size; /* chunk size of snapshot */
|
uint16_t lv_chunk_size; /* chunk size of snapshot */
|
||||||
uint16_t dummy;
|
uint16_t dummy;
|
||||||
uint32_t lv_allocated_le;
|
uint32_t lv_allocated_le;
|
||||||
uint32_t lv_stripes;
|
uint32_t lv_stripes;
|
||||||
uint32_t lv_stripesize;
|
uint32_t lv_stripesize;
|
||||||
uint32_t lv_badblock; /* for future use */
|
uint32_t lv_badblock; /* for future use */
|
||||||
uint32_t lv_allocation;
|
uint32_t lv_allocation;
|
||||||
uint32_t lv_io_timeout; /* for future use */
|
uint32_t lv_io_timeout; /* for future use */
|
||||||
uint32_t lv_read_ahead;
|
uint32_t lv_read_ahead;
|
||||||
};
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct vg_disk {
|
struct vg_disk {
|
||||||
uint8_t vg_uuid[ID_LEN]; /* volume group UUID */
|
uint8_t vg_uuid[ID_LEN]; /* volume group UUID */
|
||||||
uint8_t vg_name_dummy[NAME_LEN - ID_LEN]; /* rest of v1 VG name */
|
uint8_t vg_name_dummy[NAME_LEN - ID_LEN]; /* rest of v1 VG name */
|
||||||
uint32_t vg_number; /* volume group number */
|
uint32_t vg_number; /* volume group number */
|
||||||
uint32_t vg_access; /* read/write */
|
uint32_t vg_access; /* read/write */
|
||||||
uint32_t vg_status; /* active or not */
|
uint32_t vg_status; /* active or not */
|
||||||
uint32_t lv_max; /* maximum logical volumes */
|
uint32_t lv_max; /* maximum logical volumes */
|
||||||
uint32_t lv_cur; /* current logical volumes */
|
uint32_t lv_cur; /* current logical volumes */
|
||||||
uint32_t lv_open; /* open logical volumes */
|
uint32_t lv_open; /* open logical volumes */
|
||||||
uint32_t pv_max; /* maximum physical volumes */
|
uint32_t pv_max; /* maximum physical volumes */
|
||||||
uint32_t pv_cur; /* current physical volumes FU */
|
uint32_t pv_cur; /* current physical volumes FU */
|
||||||
uint32_t pv_act; /* active physical volumes */
|
uint32_t pv_act; /* active physical volumes */
|
||||||
uint32_t dummy;
|
uint32_t dummy;
|
||||||
uint32_t vgda; /* volume group descriptor arrays FU */
|
uint32_t vgda; /* volume group descriptor arrays FU */
|
||||||
uint32_t pe_size; /* physical extent size in sectors */
|
uint32_t pe_size; /* physical extent size in sectors */
|
||||||
uint32_t pe_total; /* total of physical extents */
|
uint32_t pe_total; /* total of physical extents */
|
||||||
uint32_t pe_allocated; /* allocated physical extents */
|
uint32_t pe_allocated; /* allocated physical extents */
|
||||||
uint32_t pvg_total; /* physical volume groups FU */
|
uint32_t pvg_total; /* physical volume groups FU */
|
||||||
};
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct pe_disk {
|
struct pe_disk {
|
||||||
uint16_t lv_num;
|
uint16_t lv_num;
|
||||||
uint16_t le_num;
|
uint16_t le_num;
|
||||||
};
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
struct uuid_list {
|
struct uuid_list {
|
||||||
struct list list;
|
struct list list;
|
||||||
@@ -163,7 +169,6 @@ struct disk_list {
|
|||||||
struct pe_disk *extents;
|
struct pe_disk *extents;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Layout constants.
|
* Layout constants.
|
||||||
*/
|
*/
|
||||||
@@ -173,29 +178,26 @@ struct disk_list {
|
|||||||
#define PV_SIZE 1024UL
|
#define PV_SIZE 1024UL
|
||||||
#define VG_SIZE 4096UL
|
#define VG_SIZE 4096UL
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Functions to calculate layout info.
|
* Functions to calculate layout info.
|
||||||
*/
|
*/
|
||||||
int calculate_layout(struct disk_list *dl);
|
int calculate_layout(struct disk_list *dl);
|
||||||
int calculate_extent_count(struct physical_volume *pv);
|
int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size,
|
||||||
|
uint32_t max_extent_count, uint64_t pe_start);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Low level io routines which read/write
|
* Low level io routines which read/write
|
||||||
* disk_lists.
|
* disk_lists.
|
||||||
*/
|
*/
|
||||||
int read_pvd(struct device *dev, struct pv_disk *pvd);
|
|
||||||
|
|
||||||
struct disk_list *read_disk(struct format_type *fmt, struct device *dev,
|
struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
|
||||||
struct pool *mem, const char *vg_name);
|
struct pool *mem, const char *vg_name);
|
||||||
|
|
||||||
int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
|
int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
|
||||||
struct dev_filter *filter,
|
struct dev_filter *filter,
|
||||||
struct pool *mem, struct list *results);
|
struct pool *mem, struct list *results);
|
||||||
|
|
||||||
int write_disks(struct format_type *fmt, struct list *pvds);
|
int write_disks(const struct format_type *fmt, struct list *pvds);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Functions to translate to between disk and in
|
* Functions to translate to between disk and in
|
||||||
@@ -204,31 +206,26 @@ int write_disks(struct format_type *fmt, struct list *pvds);
|
|||||||
int import_pv(struct pool *mem, struct device *dev,
|
int import_pv(struct pool *mem, struct device *dev,
|
||||||
struct volume_group *vg,
|
struct volume_group *vg,
|
||||||
struct physical_volume *pv, struct pv_disk *pvd);
|
struct physical_volume *pv, struct pv_disk *pvd);
|
||||||
int export_pv(struct pool *mem, struct volume_group *vg,
|
int export_pv(struct cmd_context *cmd, struct pool *mem,
|
||||||
|
struct volume_group *vg,
|
||||||
struct pv_disk *pvd, struct physical_volume *pv);
|
struct pv_disk *pvd, struct physical_volume *pv);
|
||||||
|
|
||||||
int import_vg(struct pool *mem,
|
int import_vg(struct pool *mem,
|
||||||
struct volume_group *vg, struct disk_list *dl,
|
struct volume_group *vg, struct disk_list *dl, int partial);
|
||||||
int partial);
|
|
||||||
int export_vg(struct vg_disk *vgd, struct volume_group *vg);
|
int export_vg(struct vg_disk *vgd, struct volume_group *vg);
|
||||||
|
|
||||||
int import_lv(struct pool *mem, struct logical_volume *lv,
|
int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd);
|
||||||
struct lv_disk *lvd);
|
|
||||||
void export_lv(struct lv_disk *lvd, struct volume_group *vg,
|
|
||||||
struct logical_volume *lv, const char *dev_dir);
|
|
||||||
|
|
||||||
int import_extents(struct pool *mem, struct volume_group *vg,
|
int import_extents(struct pool *mem, struct volume_group *vg,
|
||||||
struct list *pvds);
|
struct list *pvds);
|
||||||
int export_extents(struct disk_list *dl, int lv_num,
|
int export_extents(struct disk_list *dl, uint32_t lv_num,
|
||||||
struct logical_volume *lv,
|
struct logical_volume *lv, struct physical_volume *pv);
|
||||||
struct physical_volume *pv);
|
|
||||||
|
|
||||||
int import_pvs(struct format_instance *fid, struct pool *mem,
|
int import_pvs(const struct format_type *fmt, struct pool *mem,
|
||||||
struct volume_group *vg,
|
struct volume_group *vg,
|
||||||
struct list *pvds, struct list *results, int *count);
|
struct list *pvds, struct list *results, int *count);
|
||||||
|
|
||||||
int import_lvs(struct pool *mem, struct volume_group *vg,
|
int import_lvs(struct pool *mem, struct volume_group *vg, struct list *pvds);
|
||||||
struct list *pvds);
|
|
||||||
int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||||
struct physical_volume *pv, const char *dev_dir);
|
struct physical_volume *pv, const char *dev_dir);
|
||||||
|
|
||||||
@@ -240,6 +237,7 @@ int export_uuids(struct disk_list *dl, struct volume_group *vg);
|
|||||||
void export_numbers(struct list *pvds, struct volume_group *vg);
|
void export_numbers(struct list *pvds, struct volume_group *vg);
|
||||||
|
|
||||||
void export_pv_act(struct list *pvds);
|
void export_pv_act(struct list *pvds);
|
||||||
|
void munge_exported_vg(struct pv_disk *pvd);
|
||||||
|
|
||||||
/* blech */
|
/* blech */
|
||||||
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
|
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
|
||||||
@@ -247,5 +245,4 @@ int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
|
|||||||
int export_vg_number(struct format_instance *fid, struct list *pvds,
|
int export_vg_number(struct format_instance *fid, struct list *pvds,
|
||||||
const char *vg_name, struct dev_filter *filter);
|
const char *vg_name, struct dev_filter *filter);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,18 +1,31 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
#include "disk-rep.h"
|
#include "disk-rep.h"
|
||||||
#include "dbg_malloc.h"
|
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "limits.h"
|
#include "limits.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "log.h"
|
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "toolcontext.h"
|
#include "toolcontext.h"
|
||||||
|
#include "lvmcache.h"
|
||||||
|
#include "lvm1-label.h"
|
||||||
|
#include "format1.h"
|
||||||
|
|
||||||
|
#define FMT_LVM1_NAME "lvm1"
|
||||||
|
|
||||||
/* VG consistency checks */
|
/* VG consistency checks */
|
||||||
static int _check_vgs(struct list *pvs, int *partial)
|
static int _check_vgs(struct list *pvs, int *partial)
|
||||||
@@ -21,8 +34,9 @@ static int _check_vgs(struct list *pvs, int *partial)
|
|||||||
struct disk_list *dl = NULL;
|
struct disk_list *dl = NULL;
|
||||||
struct disk_list *first = NULL;
|
struct disk_list *first = NULL;
|
||||||
|
|
||||||
int pv_count = 0;
|
uint32_t pv_count = 0;
|
||||||
int exported = -1;
|
uint32_t exported = 0;
|
||||||
|
int first_time = 1;
|
||||||
|
|
||||||
*partial = 0;
|
*partial = 0;
|
||||||
|
|
||||||
@@ -34,8 +48,9 @@ static int _check_vgs(struct list *pvs, int *partial)
|
|||||||
list_iterate(pvh, pvs) {
|
list_iterate(pvh, pvs) {
|
||||||
dl = list_item(pvh, struct disk_list);
|
dl = list_item(pvh, struct disk_list);
|
||||||
|
|
||||||
if (exported < 0) {
|
if (first_time) {
|
||||||
exported = dl->pvd.pv_status & VG_EXPORTED;
|
exported = dl->pvd.pv_status & VG_EXPORTED;
|
||||||
|
first_time = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,6 +75,35 @@ static int _check_vgs(struct list *pvs, int *partial)
|
|||||||
else if (memcmp(&first->vgd, &dl->vgd, sizeof(first->vgd))) {
|
else if (memcmp(&first->vgd, &dl->vgd, sizeof(first->vgd))) {
|
||||||
log_error("VG data differs between PVs %s and %s",
|
log_error("VG data differs between PVs %s and %s",
|
||||||
dev_name(first->dev), dev_name(dl->dev));
|
dev_name(first->dev), dev_name(dl->dev));
|
||||||
|
log_debug("VG data on %s: %s %s %" PRIu32 " %" PRIu32
|
||||||
|
" %" PRIu32 " %" PRIu32 " %" PRIu32 " %"
|
||||||
|
PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32
|
||||||
|
" %" PRIu32 " %" PRIu32 " %" PRIu32 " %"
|
||||||
|
PRIu32 " %" PRIu32 " %" PRIu32,
|
||||||
|
dev_name(first->dev), first->vgd.vg_uuid,
|
||||||
|
first->vgd.vg_name_dummy,
|
||||||
|
first->vgd.vg_number, first->vgd.vg_access,
|
||||||
|
first->vgd.vg_status, first->vgd.lv_max,
|
||||||
|
first->vgd.lv_cur, first->vgd.lv_open,
|
||||||
|
first->vgd.pv_max, first->vgd.pv_cur,
|
||||||
|
first->vgd.pv_act, first->vgd.dummy,
|
||||||
|
first->vgd.vgda, first->vgd.pe_size,
|
||||||
|
first->vgd.pe_total, first->vgd.pe_allocated,
|
||||||
|
first->vgd.pvg_total);
|
||||||
|
log_debug("VG data on %s: %s %s %" PRIu32 " %" PRIu32
|
||||||
|
" %" PRIu32 " %" PRIu32 " %" PRIu32 " %"
|
||||||
|
PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32
|
||||||
|
" %" PRIu32 " %" PRIu32 " %" PRIu32 " %"
|
||||||
|
PRIu32 " %" PRIu32 " %" PRIu32,
|
||||||
|
dev_name(dl->dev), dl->vgd.vg_uuid,
|
||||||
|
dl->vgd.vg_name_dummy, dl->vgd.vg_number,
|
||||||
|
dl->vgd.vg_access, dl->vgd.vg_status,
|
||||||
|
dl->vgd.lv_max, dl->vgd.lv_cur,
|
||||||
|
dl->vgd.lv_open, dl->vgd.pv_max,
|
||||||
|
dl->vgd.pv_cur, dl->vgd.pv_act, dl->vgd.dummy,
|
||||||
|
dl->vgd.vgda, dl->vgd.pe_size,
|
||||||
|
dl->vgd.pe_total, dl->vgd.pe_allocated,
|
||||||
|
dl->vgd.pvg_total);
|
||||||
list_del(pvh);
|
list_del(pvh);
|
||||||
if (partial_mode()) {
|
if (partial_mode()) {
|
||||||
*partial = 1;
|
*partial = 1;
|
||||||
@@ -71,9 +115,9 @@ static int _check_vgs(struct list *pvs, int *partial)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* On entry to fn, list known to be non-empty */
|
/* On entry to fn, list known to be non-empty */
|
||||||
if (pv_count != dl->vgd.pv_cur) {
|
if (pv_count != first->vgd.pv_cur) {
|
||||||
log_error("%d PV(s) found for VG %s: expected %d",
|
log_error("%d PV(s) found for VG %s: expected %d",
|
||||||
pv_count, dl->pvd.vg_name, dl->vgd.pv_cur);
|
pv_count, first->pvd.vg_name, first->vgd.pv_cur);
|
||||||
if (!partial_mode())
|
if (!partial_mode())
|
||||||
return 0;
|
return 0;
|
||||||
*partial = 1;
|
*partial = 1;
|
||||||
@@ -104,6 +148,7 @@ static struct volume_group *_build_vg(struct format_instance *fid,
|
|||||||
list_init(&vg->pvs);
|
list_init(&vg->pvs);
|
||||||
list_init(&vg->lvs);
|
list_init(&vg->lvs);
|
||||||
list_init(&vg->snapshots);
|
list_init(&vg->snapshots);
|
||||||
|
list_init(&vg->tags);
|
||||||
|
|
||||||
if (!_check_vgs(pvs, &partial))
|
if (!_check_vgs(pvs, &partial))
|
||||||
goto bad;
|
goto bad;
|
||||||
@@ -113,7 +158,7 @@ static struct volume_group *_build_vg(struct format_instance *fid,
|
|||||||
if (!import_vg(mem, vg, dl, partial))
|
if (!import_vg(mem, vg, dl, partial))
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
if (!import_pvs(fid, mem, vg, pvs, &vg->pvs, &vg->pv_count))
|
if (!import_pvs(fid->fmt, mem, vg, pvs, &vg->pvs, &vg->pv_count))
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
if (!import_lvs(mem, vg, pvs))
|
if (!import_lvs(mem, vg, pvs))
|
||||||
@@ -134,7 +179,8 @@ static struct volume_group *_build_vg(struct format_instance *fid,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct volume_group *_vg_read(struct format_instance *fid,
|
static struct volume_group *_vg_read(struct format_instance *fid,
|
||||||
const char *vg_name, void *mda)
|
const char *vg_name,
|
||||||
|
struct metadata_area *mda)
|
||||||
{
|
{
|
||||||
struct pool *mem = pool_create(1024 * 10);
|
struct pool *mem = pool_create(1024 * 10);
|
||||||
struct list pvs;
|
struct list pvs;
|
||||||
@@ -165,7 +211,8 @@ static struct volume_group *_vg_read(struct format_instance *fid,
|
|||||||
return vg;
|
return vg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct disk_list *_flatten_pv(struct pool *mem, struct volume_group *vg,
|
static struct disk_list *_flatten_pv(struct format_instance *fid,
|
||||||
|
struct pool *mem, struct volume_group *vg,
|
||||||
struct physical_volume *pv,
|
struct physical_volume *pv,
|
||||||
const char *dev_dir)
|
const char *dev_dir)
|
||||||
{
|
{
|
||||||
@@ -182,11 +229,10 @@ static struct disk_list *_flatten_pv(struct pool *mem, struct volume_group *vg,
|
|||||||
list_init(&dl->uuids);
|
list_init(&dl->uuids);
|
||||||
list_init(&dl->lvds);
|
list_init(&dl->lvds);
|
||||||
|
|
||||||
if (!export_pv(mem, vg, &dl->pvd, pv) ||
|
if (!export_pv(fid->fmt->cmd, mem, vg, &dl->pvd, pv) ||
|
||||||
!export_vg(&dl->vgd, vg) ||
|
!export_vg(&dl->vgd, vg) ||
|
||||||
!export_uuids(dl, vg) ||
|
!export_uuids(dl, vg) ||
|
||||||
!export_lvs(dl, vg, pv, dev_dir) ||
|
!export_lvs(dl, vg, pv, dev_dir) || !calculate_layout(dl)) {
|
||||||
!calculate_layout(dl)) {
|
|
||||||
stack;
|
stack;
|
||||||
pool_free(mem, dl);
|
pool_free(mem, dl);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -207,7 +253,7 @@ static int _flatten_vg(struct format_instance *fid, struct pool *mem,
|
|||||||
list_iterate(pvh, &vg->pvs) {
|
list_iterate(pvh, &vg->pvs) {
|
||||||
pvl = list_item(pvh, struct pv_list);
|
pvl = list_item(pvh, struct pv_list);
|
||||||
|
|
||||||
if (!(data = _flatten_pv(mem, vg, pvl->pv, dev_dir))) {
|
if (!(data = _flatten_pv(fid, mem, vg, pvl->pv, dev_dir))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -227,7 +273,7 @@ static int _flatten_vg(struct format_instance *fid, struct pool *mem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int _vg_write(struct format_instance *fid, struct volume_group *vg,
|
static int _vg_write(struct format_instance *fid, struct volume_group *vg,
|
||||||
void *mdl)
|
struct metadata_area *mda)
|
||||||
{
|
{
|
||||||
struct pool *mem = pool_create(1024 * 10);
|
struct pool *mem = pool_create(1024 * 10);
|
||||||
struct list pvds;
|
struct list pvds;
|
||||||
@@ -243,26 +289,28 @@ static int _vg_write(struct format_instance *fid, struct volume_group *vg,
|
|||||||
r = (_flatten_vg(fid, mem, vg, &pvds, fid->fmt->cmd->dev_dir,
|
r = (_flatten_vg(fid, mem, vg, &pvds, fid->fmt->cmd->dev_dir,
|
||||||
fid->fmt->cmd->filter) &&
|
fid->fmt->cmd->filter) &&
|
||||||
write_disks(fid->fmt, &pvds));
|
write_disks(fid->fmt, &pvds));
|
||||||
|
|
||||||
|
lvmcache_update_vg(vg);
|
||||||
pool_destroy(mem);
|
pool_destroy(mem);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _pv_read(struct format_type *fmt, const char *name,
|
static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||||
struct physical_volume *pv)
|
struct physical_volume *pv, struct list *mdas)
|
||||||
{
|
{
|
||||||
struct pool *mem = pool_create(1024);
|
struct pool *mem = pool_create(1024);
|
||||||
struct disk_list *dl;
|
struct disk_list *dl;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
log_very_verbose("Reading physical volume data %s from disk", name);
|
log_very_verbose("Reading physical volume data %s from disk", pv_name);
|
||||||
|
|
||||||
if (!mem) {
|
if (!mem) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(dev = dev_cache_get(name, fmt->cmd->filter))) {
|
if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) {
|
||||||
stack;
|
stack;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -277,7 +325,7 @@ int _pv_read(struct format_type *fmt, const char *name,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
pv->fid = fmt->ops->create_instance(fmt, NULL, NULL);
|
pv->fmt = fmt;
|
||||||
|
|
||||||
r = 1;
|
r = 1;
|
||||||
|
|
||||||
@@ -286,144 +334,42 @@ int _pv_read(struct format_type *fmt, const char *name,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct list *_get_pvs(struct format_type *fmt, struct list *results)
|
static int _pv_setup(const struct format_type *fmt,
|
||||||
|
uint64_t pe_start, uint32_t extent_count,
|
||||||
|
uint32_t extent_size,
|
||||||
|
int pvmetadatacopies,
|
||||||
|
uint64_t pvmetadatasize, struct list *mdas,
|
||||||
|
struct physical_volume *pv, struct volume_group *vg)
|
||||||
{
|
{
|
||||||
struct pool *mem = pool_create(1024 * 10);
|
|
||||||
struct list pvs;
|
|
||||||
uint32_t count;
|
|
||||||
|
|
||||||
if (!mem) {
|
|
||||||
stack;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_init(&pvs);
|
|
||||||
|
|
||||||
if (!read_pvs_in_vg(fmt, NULL, fmt->cmd->filter, mem, &pvs)) {
|
|
||||||
stack;
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!import_pvs(NULL, fmt->cmd->mem, NULL, &pvs, results, &count)) {
|
|
||||||
stack;
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
pool_destroy(mem);
|
|
||||||
return results;
|
|
||||||
|
|
||||||
bad:
|
|
||||||
pool_destroy(mem);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _find_vg_name(struct list *names, const char *vg)
|
|
||||||
{
|
|
||||||
struct list *nh;
|
|
||||||
struct name_list *nl;
|
|
||||||
|
|
||||||
list_iterate(nh, names) {
|
|
||||||
nl = list_item(nh, struct name_list);
|
|
||||||
if (!strcmp(nl->name, vg))
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct list *_get_vgs(struct format_type *fmt, struct list *names)
|
|
||||||
{
|
|
||||||
struct list *pvh;
|
|
||||||
struct list *pvs;
|
|
||||||
struct name_list *nl;
|
|
||||||
|
|
||||||
if (!(pvs = pool_alloc(fmt->cmd->mem, sizeof(*pvs)))) {
|
|
||||||
log_error("PV list allocation failed");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_init(pvs);
|
|
||||||
|
|
||||||
if (!_get_pvs(fmt, pvs)) {
|
|
||||||
stack;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_iterate(pvh, pvs) {
|
|
||||||
struct pv_list *pvl = list_item(pvh, struct pv_list);
|
|
||||||
|
|
||||||
if (!(*pvl->pv->vg_name) ||
|
|
||||||
_find_vg_name(names, pvl->pv->vg_name))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!(nl = pool_alloc(fmt->cmd->mem, sizeof(*nl)))) {
|
|
||||||
stack;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(nl->name = pool_strdup(fmt->cmd->mem, pvl->pv->vg_name))) {
|
|
||||||
stack;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_add(names, &nl->list);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (list_empty(names))
|
|
||||||
pool_free(fmt->cmd->mem, pvs);
|
|
||||||
|
|
||||||
return names;
|
|
||||||
|
|
||||||
err:
|
|
||||||
pool_free(fmt->cmd->mem, pvs);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _pv_setup(struct format_instance *fid, struct physical_volume *pv,
|
|
||||||
struct volume_group *vg)
|
|
||||||
{
|
|
||||||
/* setup operations for the PV structure */
|
|
||||||
if (pv->size > MAX_PV_SIZE)
|
if (pv->size > MAX_PV_SIZE)
|
||||||
pv->size--;
|
pv->size--;
|
||||||
if (pv->size > MAX_PV_SIZE) {
|
if (pv->size > MAX_PV_SIZE) {
|
||||||
/* FIXME Limit hardcoded */
|
log_error("Physical volumes cannot be bigger than %s",
|
||||||
log_error("Physical volumes cannot be bigger than 2TB");
|
display_size(fmt->cmd, (uint64_t) MAX_PV_SIZE / 2,
|
||||||
|
SIZE_SHORT));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Nothing more to do if pe_size isn't known */
|
/* Nothing more to do if extent size isn't provided */
|
||||||
if (!vg)
|
if (!extent_size)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This works out pe_start and pe_count.
|
* This works out pe_start and pe_count.
|
||||||
*/
|
*/
|
||||||
if (!calculate_extent_count(pv)) {
|
if (!calculate_extent_count(pv, extent_size, extent_count, pe_start)) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
/* Retain existing extent locations exactly */
|
||||||
}
|
if (((pe_start || extent_count) && (pe_start != pv->pe_start)) ||
|
||||||
|
(extent_count && (extent_count != pv->pe_count))) {
|
||||||
static int _find_free_lvnum(struct logical_volume *lv)
|
log_error("Metadata would overwrite physical extents");
|
||||||
{
|
return 0;
|
||||||
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])
|
return 1;
|
||||||
i++;
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
|
static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
|
||||||
@@ -431,7 +377,7 @@ static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
|
|||||||
uint64_t max_size = UINT_MAX;
|
uint64_t max_size = UINT_MAX;
|
||||||
|
|
||||||
if (!*lv->lvid.s)
|
if (!*lv->lvid.s)
|
||||||
lvid_from_lvnum(&lv->lvid, &lv->vg->id, _find_free_lvnum(lv));
|
lvid_from_lvnum(&lv->lvid, &lv->vg->id, find_free_lvnum(lv));
|
||||||
|
|
||||||
if (lv->le_count > MAX_LE_TOTAL) {
|
if (lv->le_count > MAX_LE_TOTAL) {
|
||||||
log_error("logical volumes cannot contain more than "
|
log_error("logical volumes cannot contain more than "
|
||||||
@@ -439,29 +385,36 @@ static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (lv->size > max_size) {
|
if (lv->size > max_size) {
|
||||||
char *dummy = display_size(max_size, SIZE_SHORT);
|
log_error("logical volumes cannot be larger than %s",
|
||||||
log_error("logical volumes cannot be larger than %s", dummy);
|
display_size(fid->fmt->cmd, max_size / 2,
|
||||||
dbg_free(dummy);
|
SIZE_SHORT));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _pv_write(struct format_instance *fid, struct physical_volume *pv,
|
static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||||
void *mdl)
|
struct list *mdas, int64_t sector)
|
||||||
{
|
{
|
||||||
struct pool *mem;
|
struct pool *mem;
|
||||||
struct disk_list *dl;
|
struct disk_list *dl;
|
||||||
struct list pvs;
|
struct list pvs;
|
||||||
|
struct label *label;
|
||||||
|
struct lvmcache_info *info;
|
||||||
|
|
||||||
list_init(&pvs);
|
if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev,
|
||||||
|
pv->vg_name, NULL))) {
|
||||||
if (*pv->vg_name || pv->pe_alloc_count) {
|
stack;
|
||||||
log_error("Assertion failed: can't _pv_write non-orphan PV "
|
|
||||||
"(in VG %s)", pv->vg_name);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
label = info->label;
|
||||||
|
info->device_size = pv->size << SECTOR_SHIFT;
|
||||||
|
info->fmt = fmt;
|
||||||
|
|
||||||
|
list_init(&info->mdas);
|
||||||
|
|
||||||
|
list_init(&pvs);
|
||||||
|
|
||||||
/* Ensure any residual PE structure is gone */
|
/* Ensure any residual PE structure is gone */
|
||||||
pv->pe_size = pv->pe_count = 0;
|
pv->pe_size = pv->pe_count = 0;
|
||||||
@@ -479,7 +432,7 @@ static int _pv_write(struct format_instance *fid, struct physical_volume *pv,
|
|||||||
dl->mem = mem;
|
dl->mem = mem;
|
||||||
dl->dev = pv->dev;
|
dl->dev = pv->dev;
|
||||||
|
|
||||||
if (!export_pv(mem, NULL, &dl->pvd, pv)) {
|
if (!export_pv(fmt->cmd, mem, NULL, &dl->pvd, pv)) {
|
||||||
stack;
|
stack;
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
@@ -488,10 +441,10 @@ static int _pv_write(struct format_instance *fid, struct physical_volume *pv,
|
|||||||
dev_write in order to make other disk tools happy */
|
dev_write in order to make other disk tools happy */
|
||||||
dl->pvd.pv_on_disk.base = METADATA_BASE;
|
dl->pvd.pv_on_disk.base = METADATA_BASE;
|
||||||
dl->pvd.pv_on_disk.size = PV_SIZE;
|
dl->pvd.pv_on_disk.size = PV_SIZE;
|
||||||
dl->pvd.pe_on_disk.base = PE_ALIGN * SECTOR_SIZE;
|
dl->pvd.pe_on_disk.base = PE_ALIGN << SECTOR_SHIFT;
|
||||||
|
|
||||||
list_add(&pvs, &dl->list);
|
list_add(&pvs, &dl->list);
|
||||||
if (!write_disks(fid->fmt, &pvs)) {
|
if (!write_disks(fmt, &pvs)) {
|
||||||
stack;
|
stack;
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
@@ -504,32 +457,32 @@ static int _pv_write(struct format_instance *fid, struct physical_volume *pv,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _vg_setup(struct format_instance *fid, struct volume_group *vg)
|
static int _vg_setup(struct format_instance *fid, struct volume_group *vg)
|
||||||
{
|
{
|
||||||
/* just check max_pv and max_lv */
|
/* just check max_pv and max_lv */
|
||||||
if (vg->max_lv >= MAX_LV)
|
if (!vg->max_lv || vg->max_lv >= MAX_LV)
|
||||||
vg->max_lv = MAX_LV - 1;
|
vg->max_lv = MAX_LV - 1;
|
||||||
|
|
||||||
if (vg->max_pv >= MAX_PV)
|
if (!vg->max_pv || vg->max_pv >= MAX_PV)
|
||||||
vg->max_pv = MAX_PV - 1;
|
vg->max_pv = MAX_PV - 1;
|
||||||
|
|
||||||
if (vg->extent_size > MAX_PE_SIZE || vg->extent_size < MIN_PE_SIZE) {
|
if (vg->extent_size > MAX_PE_SIZE || vg->extent_size < MIN_PE_SIZE) {
|
||||||
char *dummy, *dummy2;
|
|
||||||
|
|
||||||
log_error("Extent size must be between %s and %s",
|
log_error("Extent size must be between %s and %s",
|
||||||
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)),
|
display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE
|
||||||
(dummy2 = display_size(MAX_PE_SIZE / 2, SIZE_SHORT)));
|
/ 2,
|
||||||
|
SIZE_SHORT), display_size(fid->fmt->cmd,
|
||||||
|
(uint64_t)
|
||||||
|
MAX_PE_SIZE
|
||||||
|
/ 2,
|
||||||
|
SIZE_SHORT));
|
||||||
|
|
||||||
dbg_free(dummy);
|
|
||||||
dbg_free(dummy2);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vg->extent_size % MIN_PE_SIZE) {
|
if (vg->extent_size % MIN_PE_SIZE) {
|
||||||
char *dummy;
|
|
||||||
log_error("Extent size must be multiple of %s",
|
log_error("Extent size must be multiple of %s",
|
||||||
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)));
|
display_size(fid->fmt->cmd,
|
||||||
dbg_free(dummy);
|
(uint64_t) MIN_PE_SIZE / 2, SIZE_SHORT));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -542,8 +495,14 @@ int _vg_setup(struct format_instance *fid, struct volume_group *vg)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct format_instance *_create_instance(struct format_type *fmt,
|
static struct metadata_area_ops _metadata_format1_ops = {
|
||||||
const char *vgname, void *private)
|
vg_read:_vg_read,
|
||||||
|
vg_write:_vg_write,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct format_instance *_create_instance(const struct format_type *fmt,
|
||||||
|
const char *vgname,
|
||||||
|
void *private)
|
||||||
{
|
{
|
||||||
struct format_instance *fid;
|
struct format_instance *fid;
|
||||||
struct metadata_area *mda;
|
struct metadata_area *mda;
|
||||||
@@ -563,38 +522,40 @@ struct format_instance *_create_instance(struct format_type *fmt,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mda->ops = &_metadata_format1_ops;
|
||||||
mda->metadata_locn = NULL;
|
mda->metadata_locn = NULL;
|
||||||
list_add(&fid->metadata_areas, &mda->list);
|
list_add(&fid->metadata_areas, &mda->list);
|
||||||
|
|
||||||
return fid;
|
return fid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _destroy_instance(struct format_instance *fid)
|
static void _destroy_instance(struct format_instance *fid)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _destroy(struct format_type *fmt)
|
static void _destroy(const struct format_type *fmt)
|
||||||
{
|
{
|
||||||
dbg_free(fmt);
|
dbg_free((void *) fmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct format_handler _format1_ops = {
|
static struct format_handler _format1_ops = {
|
||||||
get_vgs: _get_vgs,
|
pv_read:_pv_read,
|
||||||
get_pvs: _get_pvs,
|
pv_setup:_pv_setup,
|
||||||
pv_read: _pv_read,
|
pv_write:_pv_write,
|
||||||
pv_setup: _pv_setup,
|
lv_setup:_lv_setup,
|
||||||
pv_write: _pv_write,
|
vg_setup:_vg_setup,
|
||||||
lv_setup: _lv_setup,
|
|
||||||
vg_read: _vg_read,
|
|
||||||
vg_setup: _vg_setup,
|
|
||||||
vg_write: _vg_write,
|
|
||||||
create_instance:_create_instance,
|
create_instance:_create_instance,
|
||||||
destroy_instance:_destroy_instance,
|
destroy_instance:_destroy_instance,
|
||||||
destroy: _destroy,
|
destroy:_destroy,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct format_type *create_lvm1_format(struct cmd_context *cmd)
|
#ifdef LVM1_INTERNAL
|
||||||
|
struct format_type *init_lvm1_format(struct cmd_context *cmd)
|
||||||
|
#else /* Shared */
|
||||||
|
struct format_type *init_format(struct cmd_context *cmd);
|
||||||
|
struct format_type *init_format(struct cmd_context *cmd)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
struct format_type *fmt = dbg_malloc(sizeof(*fmt));
|
struct format_type *fmt = dbg_malloc(sizeof(*fmt));
|
||||||
|
|
||||||
@@ -606,8 +567,19 @@ struct format_type *create_lvm1_format(struct cmd_context *cmd)
|
|||||||
fmt->cmd = cmd;
|
fmt->cmd = cmd;
|
||||||
fmt->ops = &_format1_ops;
|
fmt->ops = &_format1_ops;
|
||||||
fmt->name = FMT_LVM1_NAME;
|
fmt->name = FMT_LVM1_NAME;
|
||||||
fmt->features = 0;
|
fmt->alias = NULL;
|
||||||
|
fmt->features = FMT_RESTRICTED_LVIDS | FMT_ORPHAN_ALLOCATABLE;
|
||||||
fmt->private = NULL;
|
fmt->private = NULL;
|
||||||
|
|
||||||
|
if (!(fmt->labeller = lvm1_labeller_create(fmt))) {
|
||||||
|
log_error("Couldn't create lvm1 label handler.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(label_register_handler(FMT_LVM1_NAME, fmt->labeller))) {
|
||||||
|
log_error("Couldn't register lvm1 label handler.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return fmt;
|
return fmt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the GPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_FORMAT1_H
|
#ifndef _LVM_FORMAT1_H
|
||||||
@@ -9,6 +18,8 @@
|
|||||||
|
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
|
|
||||||
struct format_type *create_lvm1_format(struct cmd_context *cmd);
|
#ifdef LVM1_INTERNAL
|
||||||
|
struct format_type *init_lvm1_format(struct cmd_context *cmd);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,22 +1,32 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* Translates between disk and in-core formats.
|
* This file is part of LVM2.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Translates between disk and in-core formats.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
#include "disk-rep.h"
|
#include "disk-rep.h"
|
||||||
#include "dbg_malloc.h"
|
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "log.h"
|
|
||||||
#include "lvm-string.h"
|
#include "lvm-string.h"
|
||||||
|
#include "filter.h"
|
||||||
|
#include "toolcontext.h"
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/utsname.h>
|
|
||||||
#include <linux/kdev_t.h>
|
|
||||||
|
|
||||||
static int _check_vg_name(const char *name)
|
static int _check_vg_name(const char *name)
|
||||||
{
|
{
|
||||||
@@ -77,20 +87,16 @@ int import_pv(struct pool *mem, struct device *dev,
|
|||||||
pv->pe_count = pvd->pe_total;
|
pv->pe_count = pvd->pe_total;
|
||||||
pv->pe_alloc_count = pvd->pe_allocated;
|
pv->pe_alloc_count = pvd->pe_allocated;
|
||||||
|
|
||||||
|
list_init(&pv->tags);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _system_id(char *s, const char *prefix)
|
static int _system_id(struct cmd_context *cmd, char *s, const char *prefix)
|
||||||
{
|
{
|
||||||
struct utsname uts;
|
|
||||||
|
|
||||||
if (uname(&uts) != 0) {
|
|
||||||
log_sys_error("uname", "_system_id");
|
|
||||||
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) {
|
prefix, cmd->hostname, time(NULL)) < 0) {
|
||||||
log_error("Generated system_id too long");
|
log_error("Generated system_id too long");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -98,7 +104,8 @@ int _system_id(char *s, const char *prefix)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int export_pv(struct pool *mem, struct volume_group *vg,
|
int export_pv(struct cmd_context *cmd, struct pool *mem,
|
||||||
|
struct volume_group *vg,
|
||||||
struct pv_disk *pvd, struct physical_volume *pv)
|
struct pv_disk *pvd, struct physical_volume *pv)
|
||||||
{
|
{
|
||||||
memset(pvd, 0, sizeof(*pvd));
|
memset(pvd, 0, sizeof(*pvd));
|
||||||
@@ -129,7 +136,7 @@ int export_pv(struct pool *mem, struct volume_group *vg,
|
|||||||
if (!*vg->system_id ||
|
if (!*vg->system_id ||
|
||||||
strncmp(vg->system_id, EXPORTED_TAG,
|
strncmp(vg->system_id, EXPORTED_TAG,
|
||||||
sizeof(EXPORTED_TAG) - 1)) {
|
sizeof(EXPORTED_TAG) - 1)) {
|
||||||
if (!_system_id(pvd->system_id, EXPORTED_TAG)) {
|
if (!_system_id(cmd, pvd->system_id, EXPORTED_TAG)) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -146,7 +153,7 @@ int export_pv(struct pool *mem, struct volume_group *vg,
|
|||||||
/* Is VG being imported? */
|
/* Is VG being imported? */
|
||||||
if (vg && !(vg->status & EXPORTED_VG) && *vg->system_id &&
|
if (vg && !(vg->status & EXPORTED_VG) && *vg->system_id &&
|
||||||
!strncmp(vg->system_id, EXPORTED_TAG, sizeof(EXPORTED_TAG) - 1)) {
|
!strncmp(vg->system_id, EXPORTED_TAG, sizeof(EXPORTED_TAG) - 1)) {
|
||||||
if (!_system_id(pvd->system_id, IMPORTED_TAG)) {
|
if (!_system_id(cmd, pvd->system_id, IMPORTED_TAG)) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -154,7 +161,7 @@ int export_pv(struct pool *mem, struct volume_group *vg,
|
|||||||
|
|
||||||
/* Generate system_id if PV is in VG */
|
/* Generate system_id if PV is in VG */
|
||||||
if (!pvd->system_id || !*pvd->system_id)
|
if (!pvd->system_id || !*pvd->system_id)
|
||||||
if (!_system_id(pvd->system_id, "")) {
|
if (!_system_id(cmd, pvd->system_id, "")) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -172,7 +179,10 @@ int export_pv(struct pool *mem, struct volume_group *vg,
|
|||||||
|
|
||||||
pvd->pv_size = pv->size;
|
pvd->pv_size = pv->size;
|
||||||
pvd->lv_cur = 0; /* this is set when exporting the lv list */
|
pvd->lv_cur = 0; /* this is set when exporting the lv list */
|
||||||
pvd->pe_size = pv->pe_size;
|
if (vg)
|
||||||
|
pvd->pe_size = vg->extent_size;
|
||||||
|
else
|
||||||
|
pvd->pe_size = pv->pe_size;
|
||||||
pvd->pe_total = pv->pe_count;
|
pvd->pe_total = pv->pe_count;
|
||||||
pvd->pe_allocated = pv->pe_alloc_count;
|
pvd->pe_allocated = pv->pe_alloc_count;
|
||||||
pvd->pe_start = pv->pe_start;
|
pvd->pe_start = pv->pe_start;
|
||||||
@@ -278,14 +288,19 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lv->status |= VISIBLE_LV;
|
||||||
|
|
||||||
if (lvd->lv_status & LV_SPINDOWN)
|
if (lvd->lv_status & LV_SPINDOWN)
|
||||||
lv->status |= SPINDOWN_LV;
|
lv->status |= SPINDOWN_LV;
|
||||||
|
|
||||||
if (lvd->lv_status & LV_PERSISTENT_MINOR) {
|
if (lvd->lv_status & LV_PERSISTENT_MINOR) {
|
||||||
lv->status |= FIXED_MINOR;
|
lv->status |= FIXED_MINOR;
|
||||||
lv->minor = MINOR(lvd->lv_dev);
|
lv->minor = MINOR(lvd->lv_dev);
|
||||||
} else
|
lv->major = MAJOR(lvd->lv_dev);
|
||||||
|
} else {
|
||||||
|
lv->major = -1;
|
||||||
lv->minor = -1;
|
lv->minor = -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (lvd->lv_access & LV_READ)
|
if (lvd->lv_access & LV_READ)
|
||||||
lv->status |= LVM_READ;
|
lv->status |= LVM_READ;
|
||||||
@@ -296,32 +311,29 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
|
|||||||
if (lvd->lv_badblock)
|
if (lvd->lv_badblock)
|
||||||
lv->status |= BADBLOCK_ON;
|
lv->status |= BADBLOCK_ON;
|
||||||
|
|
||||||
if (lvd->lv_allocation & LV_STRICT)
|
/* Drop the unused LV_STRICT here */
|
||||||
lv->status |= ALLOC_STRICT;
|
|
||||||
|
|
||||||
if (lvd->lv_allocation & LV_CONTIGUOUS)
|
if (lvd->lv_allocation & LV_CONTIGUOUS)
|
||||||
lv->status |= ALLOC_CONTIGUOUS;
|
lv->alloc = ALLOC_CONTIGUOUS;
|
||||||
else
|
else
|
||||||
lv->status |= ALLOC_SIMPLE;
|
lv->alloc = ALLOC_NEXT_FREE;
|
||||||
|
|
||||||
lv->read_ahead = lvd->lv_read_ahead;
|
lv->read_ahead = lvd->lv_read_ahead;
|
||||||
lv->size = lvd->lv_size;
|
lv->size = lvd->lv_size;
|
||||||
lv->le_count = lvd->lv_allocated_le;
|
lv->le_count = lvd->lv_allocated_le;
|
||||||
|
|
||||||
list_init(&lv->segments);
|
list_init(&lv->segments);
|
||||||
|
list_init(&lv->tags);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void export_lv(struct lv_disk *lvd, struct volume_group *vg,
|
static void _export_lv(struct lv_disk *lvd, struct volume_group *vg,
|
||||||
struct logical_volume *lv, const char *dev_dir)
|
struct logical_volume *lv, const char *dev_dir)
|
||||||
{
|
{
|
||||||
memset(lvd, 0, sizeof(*lvd));
|
memset(lvd, 0, sizeof(*lvd));
|
||||||
snprintf(lvd->lv_name, sizeof(lvd->lv_name), "%s%s/%s",
|
snprintf(lvd->lv_name, sizeof(lvd->lv_name), "%s%s/%s",
|
||||||
dev_dir, vg->name, lv->name);
|
dev_dir, vg->name, lv->name);
|
||||||
|
|
||||||
/* FIXME: Add 'if' test */
|
|
||||||
_check_vg_name(vg->name);
|
|
||||||
strcpy(lvd->vg_name, vg->name);
|
strcpy(lvd->vg_name, vg->name);
|
||||||
|
|
||||||
if (lv->status & LVM_READ)
|
if (lv->status & LVM_READ)
|
||||||
@@ -335,14 +347,16 @@ void export_lv(struct lv_disk *lvd, struct volume_group *vg,
|
|||||||
|
|
||||||
if (lv->status & FIXED_MINOR) {
|
if (lv->status & FIXED_MINOR) {
|
||||||
lvd->lv_status |= LV_PERSISTENT_MINOR;
|
lvd->lv_status |= LV_PERSISTENT_MINOR;
|
||||||
lvd->lv_dev = MKDEV(0, lv->minor);
|
lvd->lv_dev = MKDEV(lv->major, lv->minor);
|
||||||
|
} else {
|
||||||
|
lvd->lv_dev = MKDEV(LVM_BLK_MAJOR, lvnum_from_lvid(&lv->lvid));
|
||||||
}
|
}
|
||||||
|
|
||||||
lvd->lv_read_ahead = lv->read_ahead;
|
lvd->lv_read_ahead = lv->read_ahead;
|
||||||
lvd->lv_stripes = list_item(lv->segments.n,
|
lvd->lv_stripes =
|
||||||
struct stripe_segment)->stripes;
|
list_item(lv->segments.n, struct lv_segment)->area_count;
|
||||||
lvd->lv_stripesize = list_item(lv->segments.n,
|
lvd->lv_stripesize =
|
||||||
struct stripe_segment)->stripe_size;
|
list_item(lv->segments.n, struct lv_segment)->stripe_size;
|
||||||
|
|
||||||
lvd->lv_size = lv->size;
|
lvd->lv_size = lv->size;
|
||||||
lvd->lv_allocated_le = lv->le_count;
|
lvd->lv_allocated_le = lv->le_count;
|
||||||
@@ -350,33 +364,40 @@ void export_lv(struct lv_disk *lvd, struct volume_group *vg,
|
|||||||
if (lv->status & BADBLOCK_ON)
|
if (lv->status & BADBLOCK_ON)
|
||||||
lvd->lv_badblock = LV_BADBLOCK_ON;
|
lvd->lv_badblock = LV_BADBLOCK_ON;
|
||||||
|
|
||||||
if (lv->status & ALLOC_STRICT)
|
if (lv->alloc == ALLOC_CONTIGUOUS)
|
||||||
lvd->lv_allocation |= LV_STRICT;
|
|
||||||
|
|
||||||
if (lv->status & ALLOC_CONTIGUOUS)
|
|
||||||
lvd->lv_allocation |= LV_CONTIGUOUS;
|
lvd->lv_allocation |= LV_CONTIGUOUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int export_extents(struct disk_list *dl, int lv_num,
|
int export_extents(struct disk_list *dl, uint32_t lv_num,
|
||||||
struct logical_volume *lv, struct physical_volume *pv)
|
struct logical_volume *lv, struct physical_volume *pv)
|
||||||
{
|
{
|
||||||
struct list *segh;
|
struct list *segh;
|
||||||
struct pe_disk *ped;
|
struct pe_disk *ped;
|
||||||
struct stripe_segment *seg;
|
struct lv_segment *seg;
|
||||||
uint32_t pe, s;
|
uint32_t pe, s;
|
||||||
|
|
||||||
list_iterate(segh, &lv->segments) {
|
list_iterate(segh, &lv->segments) {
|
||||||
seg = list_item(segh, struct stripe_segment);
|
seg = list_item(segh, struct lv_segment);
|
||||||
|
|
||||||
for (s = 0; s < seg->stripes; s++) {
|
for (s = 0; s < seg->area_count; s++) {
|
||||||
if (seg->area[s].pv != pv)
|
if (seg->type != SEG_STRIPED) {
|
||||||
|
log_error("Non-striped segment type in LV %s: "
|
||||||
|
"unsupported by format1", lv->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (seg->area[s].type != AREA_PV) {
|
||||||
|
log_error("LV stripe found in LV %s: "
|
||||||
|
"unsupported by format1", lv->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (seg->area[s].u.pv.pv != pv)
|
||||||
continue; /* not our pv */
|
continue; /* not our pv */
|
||||||
|
|
||||||
for (pe = 0; pe < (seg->len / seg->stripes); pe++) {
|
for (pe = 0; pe < (seg->len / seg->area_count); pe++) {
|
||||||
ped = &dl->extents[pe + seg->area[s].pe];
|
ped = &dl->extents[pe + seg->area[s].u.pv.pe];
|
||||||
ped->lv_num = lv_num;
|
ped->lv_num = lv_num;
|
||||||
ped->le_num = (seg->le / seg->stripes) + pe +
|
ped->le_num = (seg->le / seg->area_count) + pe +
|
||||||
s * (lv->le_count / seg->stripes);
|
s * (lv->le_count / seg->area_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -384,7 +405,7 @@ int export_extents(struct disk_list *dl, int lv_num,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int import_pvs(struct format_instance *fid, struct pool *mem,
|
int import_pvs(const struct format_type *fmt, struct pool *mem,
|
||||||
struct volume_group *vg,
|
struct volume_group *vg,
|
||||||
struct list *pvds, struct list *results, int *count)
|
struct list *pvds, struct list *results, int *count)
|
||||||
{
|
{
|
||||||
@@ -397,7 +418,7 @@ int import_pvs(struct format_instance *fid, struct pool *mem,
|
|||||||
|
|
||||||
dl = list_item(pvdh, struct disk_list);
|
dl = list_item(pvdh, struct disk_list);
|
||||||
|
|
||||||
if (!(pvl = pool_alloc(mem, sizeof(*pvl))) ||
|
if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) ||
|
||||||
!(pvl->pv = pool_alloc(mem, sizeof(*pvl->pv)))) {
|
!(pvl->pv = pool_alloc(mem, sizeof(*pvl->pv)))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -408,7 +429,7 @@ int import_pvs(struct format_instance *fid, struct pool *mem,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pvl->pv->fid = fid;
|
pvl->pv->fmt = fmt;
|
||||||
list_add(results, &pvl->list);
|
list_add(results, &pvl->list);
|
||||||
(*count)++;
|
(*count)++;
|
||||||
}
|
}
|
||||||
@@ -474,9 +495,15 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
|||||||
struct list *lvh, *sh;
|
struct list *lvh, *sh;
|
||||||
struct lv_list *ll;
|
struct lv_list *ll;
|
||||||
struct lvd_list *lvdl;
|
struct lvd_list *lvdl;
|
||||||
int lv_num, len;
|
size_t len;
|
||||||
|
uint32_t lv_num;
|
||||||
struct hash_table *lvd_hash;
|
struct hash_table *lvd_hash;
|
||||||
|
|
||||||
|
if (!_check_vg_name(vg->name)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(lvd_hash = hash_create(32))) {
|
if (!(lvd_hash = hash_create(32))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -499,7 +526,7 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
|
_export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
|
||||||
|
|
||||||
lv_num = lvnum_from_lvid(&ll->lv->lvid);
|
lv_num = lvnum_from_lvid(&ll->lv->lvid);
|
||||||
|
|
||||||
@@ -616,7 +643,8 @@ int import_snapshots(struct pool *mem, struct volume_group *vg,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* insert the snapshot */
|
/* insert the snapshot */
|
||||||
if (!vg_add_snapshot(org, cow, 1, lvd->lv_chunk_size)) {
|
if (!vg_add_snapshot(org, cow, 1, NULL,
|
||||||
|
lvd->lv_chunk_size)) {
|
||||||
log_err("Couldn't add snapshot.");
|
log_err("Couldn't add snapshot.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,24 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "dbg_malloc.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
#include "disk-rep.h"
|
#include "disk-rep.h"
|
||||||
|
#include "lv_alloc.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* After much thought I have decided it is easier,
|
* After much thought I have decided it is easier,
|
||||||
@@ -192,42 +201,33 @@ static int _check_maps_are_complete(struct hash_table *maps)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct stripe_segment *_alloc_seg(struct pool *mem, uint32_t stripes)
|
|
||||||
{
|
|
||||||
struct stripe_segment *seg;
|
|
||||||
uint32_t len = sizeof(*seg) + (stripes * sizeof(seg->area[0]));
|
|
||||||
|
|
||||||
if (!(seg = pool_zalloc(mem, len))) {
|
|
||||||
stack;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return seg;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _read_linear(struct pool *mem, struct lv_map *lvm)
|
static int _read_linear(struct pool *mem, struct lv_map *lvm)
|
||||||
{
|
{
|
||||||
uint32_t le = 0;
|
uint32_t le = 0;
|
||||||
struct stripe_segment *seg;
|
struct lv_segment *seg;
|
||||||
|
|
||||||
while (le < lvm->lv->le_count) {
|
while (le < lvm->lv->le_count) {
|
||||||
seg = _alloc_seg(mem, 1);
|
seg = alloc_lv_segment(mem, 1);
|
||||||
|
|
||||||
seg->lv = lvm->lv;
|
seg->lv = lvm->lv;
|
||||||
|
seg->type = SEG_STRIPED;
|
||||||
seg->le = le;
|
seg->le = le;
|
||||||
seg->len = 0;
|
seg->len = 0;
|
||||||
|
seg->area_len = 0;
|
||||||
seg->stripe_size = 0;
|
seg->stripe_size = 0;
|
||||||
seg->stripes = 1;
|
seg->area_count = 1;
|
||||||
|
|
||||||
seg->area[0].pv = lvm->map[le].pv;
|
seg->area[0].type = AREA_PV;
|
||||||
seg->area[0].pe = lvm->map[le].pe;
|
seg->area[0].u.pv.pv = lvm->map[le].pv;
|
||||||
|
seg->area[0].u.pv.pe = lvm->map[le].pe;
|
||||||
|
|
||||||
do
|
do {
|
||||||
seg->len++;
|
seg->len++;
|
||||||
|
seg->area_len++;
|
||||||
while ((lvm->map[le + seg->len].pv == seg->area[0].pv) &&
|
} while ((lvm->map[le + seg->len].pv == seg->area[0].u.pv.pv) &&
|
||||||
(lvm->map[le + seg->len].pe == seg->area[0].pe +
|
(seg->area[0].u.pv.pv &&
|
||||||
seg->len));
|
lvm->map[le + seg->len].pe == seg->area[0].u.pv.pe +
|
||||||
|
seg->len));
|
||||||
|
|
||||||
le += seg->len;
|
le += seg->len;
|
||||||
|
|
||||||
@@ -237,7 +237,7 @@ static int _read_linear(struct pool *mem, struct lv_map *lvm)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _check_stripe(struct lv_map *lvm, struct stripe_segment *seg,
|
static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg,
|
||||||
uint32_t base_le, uint32_t len)
|
uint32_t base_le, uint32_t len)
|
||||||
{
|
{
|
||||||
uint32_t le, st;
|
uint32_t le, st;
|
||||||
@@ -247,9 +247,11 @@ static int _check_stripe(struct lv_map *lvm, struct stripe_segment *seg,
|
|||||||
/*
|
/*
|
||||||
* Is the next physical extent in every stripe adjacent to the last?
|
* Is the next physical extent in every stripe adjacent to the last?
|
||||||
*/
|
*/
|
||||||
for (st = 0; st < seg->stripes; st++)
|
for (st = 0; st < seg->area_count; st++)
|
||||||
if ((lvm->map[le + st * len].pv != seg->area[st].pv) ||
|
if ((lvm->map[le + st * len].pv != seg->area[st].u.pv.pv) ||
|
||||||
(lvm->map[le + st * len].pe != seg->area[st].pe + seg->len))
|
(seg->area[st].u.pv.pv &&
|
||||||
|
lvm->map[le + st * len].pe !=
|
||||||
|
seg->area[st].u.pv.pe + seg->len))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -258,7 +260,7 @@ static int _check_stripe(struct lv_map *lvm, struct stripe_segment *seg,
|
|||||||
static int _read_stripes(struct pool *mem, struct lv_map *lvm)
|
static int _read_stripes(struct pool *mem, struct lv_map *lvm)
|
||||||
{
|
{
|
||||||
uint32_t st, le = 0, len;
|
uint32_t st, le = 0, len;
|
||||||
struct stripe_segment *seg;
|
struct lv_segment *seg;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Work out overall striped length
|
* Work out overall striped length
|
||||||
@@ -271,34 +273,38 @@ static int _read_stripes(struct pool *mem, struct lv_map *lvm)
|
|||||||
len = lvm->lv->le_count / lvm->stripes;
|
len = lvm->lv->le_count / lvm->stripes;
|
||||||
|
|
||||||
while (le < len) {
|
while (le < len) {
|
||||||
if (!(seg = _alloc_seg(mem, lvm->stripes))) {
|
if (!(seg = alloc_lv_segment(mem, lvm->stripes))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
seg->lv = lvm->lv;
|
seg->lv = lvm->lv;
|
||||||
|
seg->type = SEG_STRIPED;
|
||||||
seg->stripe_size = lvm->stripe_size;
|
seg->stripe_size = lvm->stripe_size;
|
||||||
seg->stripes = lvm->stripes;
|
seg->area_count = lvm->stripes;
|
||||||
seg->le = seg->stripes * le;
|
seg->le = seg->area_count * le;
|
||||||
seg->len = 1;
|
seg->len = 1;
|
||||||
|
seg->area_len = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up start positions of each stripe in this segment
|
* Set up start positions of each stripe in this segment
|
||||||
*/
|
*/
|
||||||
for (st = 0; st < seg->stripes; st++) {
|
for (st = 0; st < seg->area_count; st++) {
|
||||||
seg->area[st].pv = lvm->map[le + st * len].pv;
|
seg->area[st].u.pv.pv = lvm->map[le + st * len].pv;
|
||||||
seg->area[st].pe = lvm->map[le + st * len].pe;
|
seg->area[st].u.pv.pe = lvm->map[le + st * len].pe;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find how many blocks are contiguous in all stripes
|
* Find how many blocks are contiguous in all stripes
|
||||||
* and so can form part of this segment
|
* and so can form part of this segment
|
||||||
*/
|
*/
|
||||||
while (_check_stripe(lvm, seg, le, len))
|
while (_check_stripe(lvm, seg, le, len)) {
|
||||||
seg->len++;
|
seg->len++;
|
||||||
|
seg->area_len++;
|
||||||
|
}
|
||||||
|
|
||||||
le += seg->len;
|
le += seg->len;
|
||||||
seg->len *= seg->stripes;
|
seg->len *= seg->area_count;
|
||||||
|
|
||||||
list_add(&lvm->lv->segments, &seg->list);
|
list_add(&lvm->lv->segments, &seg->list);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,31 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
#include "disk-rep.h"
|
#include "disk-rep.h"
|
||||||
#include "log.h"
|
|
||||||
#include "dbg_malloc.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only works with powers of 2.
|
* Only works with powers of 2.
|
||||||
*/
|
*/
|
||||||
static inline ulong _round_up(ulong n, ulong size)
|
static inline uint32_t _round_up(uint32_t n, uint32_t size)
|
||||||
{
|
{
|
||||||
size--;
|
size--;
|
||||||
return (n + size) & ~size;
|
return (n + size) & ~size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline ulong _div_up(ulong n, ulong size)
|
static inline uint32_t _div_up(uint32_t n, uint32_t size)
|
||||||
{
|
{
|
||||||
return _round_up(n, size) / size;
|
return _round_up(n, size) / size;
|
||||||
}
|
}
|
||||||
@@ -36,7 +44,7 @@ static uint32_t _next_base(struct data_area *area)
|
|||||||
*/
|
*/
|
||||||
static int _adjust_pe_on_disk(struct pv_disk *pvd)
|
static int _adjust_pe_on_disk(struct pv_disk *pvd)
|
||||||
{
|
{
|
||||||
uint32_t pe_start = pvd->pe_start * SECTOR_SIZE;
|
uint32_t pe_start = pvd->pe_start << SECTOR_SHIFT;
|
||||||
|
|
||||||
if (pe_start < pvd->pe_on_disk.base + pvd->pe_on_disk.size)
|
if (pe_start < pvd->pe_on_disk.base + pvd->pe_on_disk.size)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -63,7 +71,7 @@ static void _calc_simple_layout(struct pv_disk *pvd)
|
|||||||
pvd->pe_on_disk.size = pvd->pe_total * sizeof(struct pe_disk);
|
pvd->pe_on_disk.size = pvd->pe_total * sizeof(struct pe_disk);
|
||||||
}
|
}
|
||||||
|
|
||||||
int _check_vg_limits(struct disk_list *dl)
|
static int _check_vg_limits(struct disk_list *dl)
|
||||||
{
|
{
|
||||||
if (dl->vgd.lv_max > MAX_LV) {
|
if (dl->vgd.lv_max > MAX_LV) {
|
||||||
log_error("MaxLogicalVolumes of %d exceeds format limit of %d "
|
log_error("MaxLogicalVolumes of %d exceeds format limit of %d "
|
||||||
@@ -103,11 +111,11 @@ int calculate_layout(struct disk_list *dl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It may seem strange to have a struct physical_volume in here,
|
* The number of extents that can fit on a disk is metadata format dependant.
|
||||||
* but the number of extents that can fit on a disk *is* metadata
|
* pe_start is any existing value for pe_start
|
||||||
* format dependant.
|
|
||||||
*/
|
*/
|
||||||
int calculate_extent_count(struct physical_volume *pv)
|
int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size,
|
||||||
|
uint32_t max_extent_count, uint64_t pe_start)
|
||||||
{
|
{
|
||||||
struct pv_disk *pvd = dbg_malloc(sizeof(*pvd));
|
struct pv_disk *pvd = dbg_malloc(sizeof(*pvd));
|
||||||
uint32_t end;
|
uint32_t end;
|
||||||
@@ -122,10 +130,13 @@ int calculate_extent_count(struct physical_volume *pv)
|
|||||||
* one is going to be knocked off at the start of the
|
* one is going to be knocked off at the start of the
|
||||||
* next loop.
|
* next loop.
|
||||||
*/
|
*/
|
||||||
pvd->pe_total = (pv->size / pv->pe_size);
|
if (max_extent_count)
|
||||||
|
pvd->pe_total = max_extent_count + 1;
|
||||||
|
else
|
||||||
|
pvd->pe_total = (pv->size / extent_size);
|
||||||
|
|
||||||
if (pvd->pe_total < PE_SIZE_PV_SIZE_REL) {
|
if (pvd->pe_total < PE_SIZE_PV_SIZE_REL) {
|
||||||
log_error("Insufficient space for extents on %s",
|
log_error("Too few extents on %s. Try smaller extent size.",
|
||||||
dev_name(pv->dev));
|
dev_name(pv->dev));
|
||||||
dbg_free(pvd);
|
dbg_free(pvd);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -135,11 +146,15 @@ int calculate_extent_count(struct physical_volume *pv)
|
|||||||
pvd->pe_total--;
|
pvd->pe_total--;
|
||||||
_calc_simple_layout(pvd);
|
_calc_simple_layout(pvd);
|
||||||
end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size +
|
end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size +
|
||||||
SECTOR_SIZE - 1) / SECTOR_SIZE);
|
SECTOR_SIZE - 1) >> SECTOR_SHIFT);
|
||||||
|
|
||||||
|
if (pe_start && end < pe_start)
|
||||||
|
end = pe_start;
|
||||||
|
|
||||||
pvd->pe_start = _round_up(end, PE_ALIGN);
|
pvd->pe_start = _round_up(end, PE_ALIGN);
|
||||||
|
|
||||||
} while ((pvd->pe_start + (pvd->pe_total * pv->pe_size)) > pv->size);
|
} while ((pvd->pe_start + (pvd->pe_total * extent_size))
|
||||||
|
> pv->size);
|
||||||
|
|
||||||
if (pvd->pe_total > MAX_PE_TOTAL) {
|
if (pvd->pe_total > MAX_PE_TOTAL) {
|
||||||
log_error("Metadata extent limit (%u) exceeded for %s - "
|
log_error("Metadata extent limit (%u) exceeded for %s - "
|
||||||
@@ -151,6 +166,7 @@ int calculate_extent_count(struct physical_volume *pv)
|
|||||||
|
|
||||||
pv->pe_count = pvd->pe_total;
|
pv->pe_count = pvd->pe_total;
|
||||||
pv->pe_start = pvd->pe_start;
|
pv->pe_start = pvd->pe_start;
|
||||||
|
/* We can't set pe_size here without breaking LVM1 compatibility */
|
||||||
dbg_free(pvd);
|
dbg_free(pvd);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
118
lib/format1/lvm1-label.c
Normal file
118
lib/format1/lvm1-label.c
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
|
#include "lvm1-label.h"
|
||||||
|
#include "disk-rep.h"
|
||||||
|
#include "label.h"
|
||||||
|
#include "metadata.h"
|
||||||
|
#include "xlate.h"
|
||||||
|
#include "lvmcache.h"
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
static void _not_supported(const char *op)
|
||||||
|
{
|
||||||
|
log_err("The '%s' operation is not supported for the lvm1 labeller.",
|
||||||
|
op);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _can_handle(struct labeller *l, char *buf, uint64_t sector)
|
||||||
|
{
|
||||||
|
struct pv_disk *pvd = (struct pv_disk *) buf;
|
||||||
|
uint32_t version;
|
||||||
|
|
||||||
|
/* LVM1 label must always be in first sector */
|
||||||
|
if (sector)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
version = xlate16(pvd->version);
|
||||||
|
|
||||||
|
if (pvd->id[0] == 'H' && pvd->id[1] == 'M' &&
|
||||||
|
(version == 1 || version == 2))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _write(struct label *label, char *buf)
|
||||||
|
{
|
||||||
|
_not_supported("write");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||||
|
struct label **label)
|
||||||
|
{
|
||||||
|
struct pv_disk *pvd = (struct pv_disk *) buf;
|
||||||
|
struct lvmcache_info *info;
|
||||||
|
|
||||||
|
munge_exported_vg(pvd);
|
||||||
|
if (!(info = lvmcache_add(l, pvd->pv_uuid, dev, pvd->vg_name, NULL))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*label = info->label;
|
||||||
|
|
||||||
|
info->device_size = xlate32(pvd->pv_size) << SECTOR_SHIFT;
|
||||||
|
list_init(&info->mdas);
|
||||||
|
|
||||||
|
info->status &= ~CACHE_INVALID;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _initialise_label(struct labeller *l, struct label *label)
|
||||||
|
{
|
||||||
|
strcpy(label->type, "LVM1");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _destroy_label(struct labeller *l, struct label *label)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _destroy(struct labeller *l)
|
||||||
|
{
|
||||||
|
dbg_free(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct label_ops _lvm1_ops = {
|
||||||
|
can_handle:_can_handle,
|
||||||
|
write:_write,
|
||||||
|
read:_read,
|
||||||
|
verify:_can_handle,
|
||||||
|
initialise_label:_initialise_label,
|
||||||
|
destroy_label:_destroy_label,
|
||||||
|
destroy:_destroy
|
||||||
|
};
|
||||||
|
|
||||||
|
struct labeller *lvm1_labeller_create(struct format_type *fmt)
|
||||||
|
{
|
||||||
|
struct labeller *l;
|
||||||
|
|
||||||
|
if (!(l = dbg_malloc(sizeof(*l)))) {
|
||||||
|
log_err("Couldn't allocate labeller object.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
l->ops = &_lvm1_ops;
|
||||||
|
l->private = (const void *) fmt;
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
23
lib/format1/lvm1-label.h
Normal file
23
lib/format1/lvm1-label.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LVM_LVM1_LABEL_H
|
||||||
|
#define _LVM_LVM1_LABEL_H
|
||||||
|
|
||||||
|
#include "metadata.h"
|
||||||
|
|
||||||
|
struct labeller *lvm1_labeller_create(struct format_type *fmt);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2002 Sistina Software (UK) Limited.
|
|
||||||
*
|
|
||||||
* This file is released under the LGPL.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lvm1_label.h"
|
|
||||||
#include "dbg_malloc.h"
|
|
||||||
#include "disk-rep.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "label.h"
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
static void _not_supported(const char *op)
|
|
||||||
{
|
|
||||||
log_err("The '%s' operation is not supported for the lvm1 labeller.",
|
|
||||||
op);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _can_handle(struct labeller *l, struct device *dev)
|
|
||||||
{
|
|
||||||
struct pv_disk pvd;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!dev_open(dev, O_RDONLY)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_pvd(dev, &pvd);
|
|
||||||
|
|
||||||
if (!dev_close(dev))
|
|
||||||
stack;
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _write(struct labeller *l, struct device *dev, struct label *label)
|
|
||||||
{
|
|
||||||
_not_supported("write");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _remove(struct labeller *l, struct device *dev)
|
|
||||||
{
|
|
||||||
_not_supported("remove");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct label *_to_label(struct pv_disk *pvd)
|
|
||||||
{
|
|
||||||
struct label *l;
|
|
||||||
struct lvm_label_info *info;
|
|
||||||
|
|
||||||
if (!(l = dbg_malloc(sizeof(*l)))) {
|
|
||||||
log_err("Couldn't allocate label.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(info = (struct lvm_label_info *) dbg_strdup(pvd->vg_name))) {
|
|
||||||
dbg_free(l);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&l->id, &pvd->pv_uuid, sizeof(l->id));
|
|
||||||
strcpy(l->volume_type, "lvm");
|
|
||||||
l->version[0] = 1;
|
|
||||||
l->version[0] = 0;
|
|
||||||
l->version[0] = 0;
|
|
||||||
l->extra_info = info;
|
|
||||||
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _read(struct labeller *l, struct device *dev, struct label **label)
|
|
||||||
{
|
|
||||||
struct pv_disk pvd;
|
|
||||||
int r = 0;
|
|
||||||
|
|
||||||
if (!dev_open(dev, O_RDONLY)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_pvd(dev, &pvd);
|
|
||||||
|
|
||||||
if (!dev_close(dev))
|
|
||||||
stack;
|
|
||||||
|
|
||||||
if (!r) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Convert the disk_list into a label structure.
|
|
||||||
*/
|
|
||||||
if (!(*label = _to_label(&pvd))) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _destroy_label(struct labeller *l, struct label *label)
|
|
||||||
{
|
|
||||||
dbg_free(label->extra_info);
|
|
||||||
dbg_free(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _destroy(struct labeller *l)
|
|
||||||
{
|
|
||||||
dbg_free(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct label_ops _lvm1_ops = {
|
|
||||||
can_handle: _can_handle,
|
|
||||||
write: _write,
|
|
||||||
remove: _remove,
|
|
||||||
read: _read,
|
|
||||||
verify: _can_handle,
|
|
||||||
destroy_label: _destroy_label,
|
|
||||||
destroy: _destroy
|
|
||||||
};
|
|
||||||
|
|
||||||
struct labeller *lvm1_labeller_create(void)
|
|
||||||
{
|
|
||||||
struct labeller *l;
|
|
||||||
|
|
||||||
if (!(l = dbg_malloc(sizeof(*l)))) {
|
|
||||||
log_err("Couldn't allocate labeller object.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
l->ops = &_lvm1_ops;
|
|
||||||
l->private = NULL;
|
|
||||||
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2002 Sistina Software (UK) Limited.
|
|
||||||
*
|
|
||||||
* This file is released under the LGPL.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _LVM_LVM1_LABEL_H
|
|
||||||
#define _LVM_LVM1_LABEL_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is what the 'extra_info' field of the label will point to
|
|
||||||
* if the label type is lvm1.
|
|
||||||
*/
|
|
||||||
struct lvm_label_info {
|
|
||||||
char volume_group[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct labeller *lvm1_labeller_create(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,10 +1,19 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "log.h"
|
#include "lib.h"
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
#include "disk-rep.h"
|
#include "disk-rep.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
#include "format-text.h"
|
#include "format-text.h"
|
||||||
|
|
||||||
#include "log.h"
|
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
@@ -17,7 +26,6 @@
|
|||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -51,32 +59,32 @@ struct archive_file {
|
|||||||
/*
|
/*
|
||||||
* Extract vg name and version number from a filename.
|
* Extract vg name and version number from a filename.
|
||||||
*/
|
*/
|
||||||
static int _split_vg(const char *filename, char *vg, size_t vg_size,
|
static int _split_vg(const char *filename, char *vgname, size_t vg_size,
|
||||||
uint32_t * index)
|
uint32_t *ix)
|
||||||
{
|
{
|
||||||
int len, vg_len;
|
size_t len, vg_len;
|
||||||
char *dot, *underscore;
|
const char *dot, *underscore;
|
||||||
|
|
||||||
len = strlen(filename);
|
len = strlen(filename);
|
||||||
if (len < 7)
|
if (len < 7)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
dot = (char *) (filename + len - 3);
|
dot = (filename + len - 3);
|
||||||
if (strcmp(".vg", dot))
|
if (strcmp(".vg", dot))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!(underscore = rindex(filename, '_')))
|
if (!(underscore = rindex(filename, '_')))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (sscanf(underscore + 1, "%u", index) != 1)
|
if (sscanf(underscore + 1, "%u", ix) != 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
vg_len = underscore - filename;
|
vg_len = underscore - filename;
|
||||||
if (vg_len + 1 > vg_size)
|
if (vg_len + 1 > vg_size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
strncpy(vg, filename, vg_len);
|
strncpy(vgname, filename, vg_len);
|
||||||
vg[vg_len] = '\0';
|
vgname[vg_len] = '\0';
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -84,7 +92,7 @@ static int _split_vg(const char *filename, char *vg, size_t vg_size,
|
|||||||
static void _insert_file(struct list *head, struct archive_file *b)
|
static void _insert_file(struct list *head, struct archive_file *b)
|
||||||
{
|
{
|
||||||
struct list *bh;
|
struct list *bh;
|
||||||
struct archive_file *bf;
|
struct archive_file *bf = NULL;
|
||||||
|
|
||||||
if (list_empty(head)) {
|
if (list_empty(head)) {
|
||||||
list_add(head, &b->list);
|
list_add(head, &b->list);
|
||||||
@@ -122,10 +130,10 @@ static char *_join(struct pool *mem, const char *dir, const char *name)
|
|||||||
* Returns a list of archive_files.
|
* Returns a list of archive_files.
|
||||||
*/
|
*/
|
||||||
static struct list *_scan_archive(struct pool *mem,
|
static struct list *_scan_archive(struct pool *mem,
|
||||||
const char *vg, const char *dir)
|
const char *vgname, const char *dir)
|
||||||
{
|
{
|
||||||
int i, count, index;
|
int i, count, ix;
|
||||||
char vg_name[64], *path;
|
char vgname_found[64], *path;
|
||||||
struct dirent **dirent;
|
struct dirent **dirent;
|
||||||
struct archive_file *af;
|
struct archive_file *af;
|
||||||
struct list *results;
|
struct list *results;
|
||||||
@@ -149,12 +157,12 @@ static struct list *_scan_archive(struct pool *mem,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* check the name is the correct format */
|
/* check the name is the correct format */
|
||||||
if (!_split_vg(dirent[i]->d_name, vg_name, sizeof(vg_name),
|
if (!_split_vg(dirent[i]->d_name, vgname_found,
|
||||||
&index))
|
sizeof(vgname_found), &ix))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* is it the vg we're interested in ? */
|
/* is it the vg we're interested in ? */
|
||||||
if (strcmp(vg, vg_name))
|
if (strcmp(vgname, vgname_found))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!(path = _join(mem, dir, dirent[i]->d_name))) {
|
if (!(path = _join(mem, dir, dirent[i]->d_name))) {
|
||||||
@@ -171,7 +179,7 @@ static struct list *_scan_archive(struct pool *mem,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
af->index = index;
|
af->index = ix;
|
||||||
af->path = path;
|
af->path = path;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -202,7 +210,7 @@ static void _remove_expired(struct list *archives, uint32_t archives_size,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/* Convert retain_days into the time after which we must retain */
|
/* Convert retain_days into the time after which we must retain */
|
||||||
retain_time = time(NULL) - (time_t) retain_days * SECS_PER_DAY;
|
retain_time = time(NULL) - (time_t) retain_days *SECS_PER_DAY;
|
||||||
|
|
||||||
/* Assume list is ordered oldest first (by index) */
|
/* Assume list is ordered oldest first (by index) */
|
||||||
list_iterate(bh, archives) {
|
list_iterate(bh, archives) {
|
||||||
@@ -232,7 +240,7 @@ int archive_vg(struct volume_group *vg,
|
|||||||
uint32_t retain_days, uint32_t min_archive)
|
uint32_t retain_days, uint32_t min_archive)
|
||||||
{
|
{
|
||||||
int i, fd, renamed = 0;
|
int i, fd, renamed = 0;
|
||||||
unsigned int index = 0;
|
unsigned int ix = 0;
|
||||||
struct archive_file *last;
|
struct archive_file *last;
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
char temp_file[PATH_MAX], archive_name[PATH_MAX];
|
char temp_file[PATH_MAX], archive_name[PATH_MAX];
|
||||||
@@ -252,7 +260,7 @@ int archive_vg(struct volume_group *vg,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!text_vg_export(fp, vg, desc)) {
|
if (!text_vg_export_file(vg, desc, fp)) {
|
||||||
stack;
|
stack;
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -269,15 +277,15 @@ int archive_vg(struct volume_group *vg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (list_empty(archives))
|
if (list_empty(archives))
|
||||||
index = 0;
|
ix = 0;
|
||||||
else {
|
else {
|
||||||
last = list_item(archives->p, struct archive_file);
|
last = list_item(archives->p, struct archive_file);
|
||||||
index = last->index + 1;
|
ix = last->index + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < 10; i++) {
|
for (i = 0; i < 10; i++) {
|
||||||
if (lvm_snprintf(archive_name, sizeof(archive_name),
|
if (lvm_snprintf(archive_name, sizeof(archive_name),
|
||||||
"%s/%s_%05d.vg", dir, vg->name, index) < 0) {
|
"%s/%s_%05d.vg", dir, vg->name, ix) < 0) {
|
||||||
log_error("Archive file name too long.");
|
log_error("Archive file name too long.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -285,7 +293,7 @@ int archive_vg(struct volume_group *vg,
|
|||||||
if ((renamed = lvm_rename(temp_file, archive_name)))
|
if ((renamed = lvm_rename(temp_file, archive_name)))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
index++;
|
ix++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!renamed)
|
if (!renamed)
|
||||||
@@ -297,8 +305,7 @@ int archive_vg(struct volume_group *vg,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
|
static void _display_archive(struct cmd_context *cmd, struct archive_file *af)
|
||||||
struct archive_file *af)
|
|
||||||
{
|
{
|
||||||
struct volume_group *vg = NULL;
|
struct volume_group *vg = NULL;
|
||||||
struct format_instance *tf;
|
struct format_instance *tf;
|
||||||
@@ -306,10 +313,12 @@ static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
|
|||||||
char *desc;
|
char *desc;
|
||||||
void *context;
|
void *context;
|
||||||
|
|
||||||
log_print("path:\t\t%s", af->path);
|
log_print(" ");
|
||||||
|
log_print("File:\t\t%s", af->path);
|
||||||
|
|
||||||
if (!(context = create_text_context(cmd->fmtt, af->path, NULL)) ||
|
if (!(context = create_text_context(cmd, af->path, NULL)) ||
|
||||||
!(tf = cmd->fmtt->ops->create_instance(cmd->fmtt, NULL, context))) {
|
!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
|
||||||
|
context))) {
|
||||||
log_error("Couldn't create text instance object.");
|
log_error("Couldn't create text instance object.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -319,41 +328,56 @@ static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
|
|||||||
* retrieve the archive time and description.
|
* retrieve the archive time and description.
|
||||||
*/
|
*/
|
||||||
/* FIXME Use variation on _vg_read */
|
/* FIXME Use variation on _vg_read */
|
||||||
if (!(vg = text_vg_import(tf, af->path, um, &when, &desc))) {
|
if (!(vg = text_vg_import_file(tf, af->path, &when, &desc))) {
|
||||||
log_print("Unable to read archive file.");
|
log_print("Unable to read archive file.");
|
||||||
tf->fmt->ops->destroy_instance(tf);
|
tf->fmt->ops->destroy_instance(tf);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_print("description:\t%s", desc ? desc : "<No description>");
|
log_print("VG name: \t%s", vg->name);
|
||||||
log_print("time:\t\t%s", ctime(&when));
|
log_print("Description:\t%s", desc ? desc : "<No description>");
|
||||||
|
log_print("Backup Time:\t%s", ctime(&when));
|
||||||
|
|
||||||
pool_free(cmd->mem, vg);
|
pool_free(cmd->mem, vg);
|
||||||
tf->fmt->ops->destroy_instance(tf);
|
tf->fmt->ops->destroy_instance(tf);
|
||||||
}
|
}
|
||||||
|
|
||||||
int archive_list(struct cmd_context *cmd, struct uuid_map *um,
|
int archive_list(struct cmd_context *cmd, const char *dir, const char *vgname)
|
||||||
const char *dir, const char *vg)
|
|
||||||
{
|
{
|
||||||
struct list *archives, *ah;
|
struct list *archives, *ah;
|
||||||
struct archive_file *af;
|
struct archive_file *af;
|
||||||
|
|
||||||
if (!(archives = _scan_archive(cmd->mem, vg, dir))) {
|
if (!(archives = _scan_archive(cmd->mem, vgname, dir))) {
|
||||||
log_err("Couldn't scan the archive directory (%s).", dir);
|
log_err("Couldn't scan the archive directory (%s).", dir);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list_empty(archives))
|
if (list_empty(archives))
|
||||||
log_print("No archives found.");
|
log_print("No archives found in %s.", dir);
|
||||||
|
|
||||||
list_iterate(ah, archives) {
|
list_iterate(ah, archives) {
|
||||||
af = list_item(ah, struct archive_file);
|
af = list_item(ah, struct archive_file);
|
||||||
|
|
||||||
_display_archive(cmd, um, af);
|
_display_archive(cmd, af);
|
||||||
log_print(" ");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pool_free(cmd->mem, archives);
|
pool_free(cmd->mem, archives);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int backup_list(struct cmd_context *cmd, const char *dir, const char *vgname)
|
||||||
|
{
|
||||||
|
struct archive_file af;
|
||||||
|
|
||||||
|
if (!(af.path = _join(cmd->mem, dir, vgname))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path_exists(af.path))
|
||||||
|
_display_archive(cmd, &af);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,34 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
#include "import-export.h"
|
#include "import-export.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
#include "log.h"
|
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
#include "dbg_malloc.h"
|
#include "display.h"
|
||||||
#include "lvm-string.h"
|
#include "lvm-string.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
|
||||||
|
struct formatter;
|
||||||
|
typedef int (*out_with_comment_fn) (struct formatter * f, const char *comment,
|
||||||
|
const char *fmt, va_list ap);
|
||||||
|
typedef void (*nl_fn) (struct formatter * f);
|
||||||
/*
|
/*
|
||||||
* The first half of this file deals with
|
* The first half of this file deals with
|
||||||
* exporting the vg, ie. writing it to a file.
|
* exporting the vg, ie. writing it to a file.
|
||||||
@@ -24,22 +37,50 @@ struct formatter {
|
|||||||
struct pool *mem; /* pv names allocated from here */
|
struct pool *mem; /* pv names allocated from here */
|
||||||
struct hash_table *pv_names; /* dev_name -> pv_name (eg, pv1) */
|
struct hash_table *pv_names; /* dev_name -> pv_name (eg, pv1) */
|
||||||
|
|
||||||
FILE *fp; /* where we're writing to */
|
union {
|
||||||
int indent; /* current level of indentation */
|
FILE *fp; /* where we're writing to */
|
||||||
|
struct {
|
||||||
|
char *buf;
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t used;
|
||||||
|
} buf;
|
||||||
|
} data;
|
||||||
|
|
||||||
|
out_with_comment_fn out_with_comment;
|
||||||
|
nl_fn nl;
|
||||||
|
|
||||||
|
int indent; /* current level of indentation */
|
||||||
int error;
|
int error;
|
||||||
|
int header; /* 1 => comments at start; 0 => end */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct utsname _utsname;
|
||||||
|
|
||||||
|
static void _init(void)
|
||||||
|
{
|
||||||
|
static int _initialised = 0;
|
||||||
|
|
||||||
|
if (_initialised)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (uname(&_utsname)) {
|
||||||
|
log_error("uname failed: %s", strerror(errno));
|
||||||
|
memset(&_utsname, 0, sizeof(_utsname));
|
||||||
|
}
|
||||||
|
|
||||||
|
_initialised = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Formatting functions.
|
* Formatting functions.
|
||||||
*/
|
*/
|
||||||
static void _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
|
static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
|
||||||
__attribute__ ((format(printf, 3, 4)));
|
__attribute__ ((format(printf, 3, 4)));
|
||||||
|
|
||||||
static void _out_hint(struct formatter *f, const char *fmt, ...)
|
static int _out_hint(struct formatter *f, const char *fmt, ...)
|
||||||
__attribute__ ((format(printf, 2, 3)));
|
__attribute__ ((format(printf, 2, 3)));
|
||||||
|
|
||||||
static void _out(struct formatter *f, const char *fmt, ...)
|
static int _out(struct formatter *f, const char *fmt, ...)
|
||||||
__attribute__ ((format(printf, 2, 3)));
|
__attribute__ ((format(printf, 2, 3)));
|
||||||
|
|
||||||
#define MAX_INDENT 5
|
#define MAX_INDENT 5
|
||||||
@@ -60,26 +101,39 @@ static void _dec_indent(struct formatter *f)
|
|||||||
/*
|
/*
|
||||||
* Newline function for prettier layout.
|
* Newline function for prettier layout.
|
||||||
*/
|
*/
|
||||||
static void _nl(struct formatter *f)
|
static void _nl_file(struct formatter *f)
|
||||||
{
|
{
|
||||||
fprintf(f->fp, "\n");
|
fprintf(f->data.fp, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _nl_raw(struct formatter *f)
|
||||||
|
{
|
||||||
|
if (f->data.buf.used >= f->data.buf.size - 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
*f->data.buf.buf = '\n';
|
||||||
|
f->data.buf.buf += 1;
|
||||||
|
f->data.buf.used += 1;
|
||||||
|
*f->data.buf.buf = '\0';
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define COMMENT_TAB 6
|
#define COMMENT_TAB 6
|
||||||
static void _out_with_comment(struct formatter *f, const char *comment,
|
static int _out_with_comment_file(struct formatter *f, const char *comment,
|
||||||
const char *fmt, va_list ap)
|
const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char white_space[MAX_INDENT + 1];
|
char white_space[MAX_INDENT + 1];
|
||||||
|
|
||||||
if (ferror(f->fp))
|
if (ferror(f->data.fp))
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < f->indent; i++)
|
for (i = 0; i < f->indent; i++)
|
||||||
white_space[i] = '\t';
|
white_space[i] = '\t';
|
||||||
white_space[i] = '\0';
|
white_space[i] = '\0';
|
||||||
fprintf(f->fp, white_space);
|
fprintf(f->data.fp, white_space);
|
||||||
i = vfprintf(f->fp, fmt, ap);
|
i = vfprintf(f->data.fp, fmt, ap);
|
||||||
|
|
||||||
if (comment) {
|
if (comment) {
|
||||||
/*
|
/*
|
||||||
@@ -90,13 +144,34 @@ static void _out_with_comment(struct formatter *f, const char *comment,
|
|||||||
i++;
|
i++;
|
||||||
|
|
||||||
do
|
do
|
||||||
fputc('\t', f->fp);
|
fputc('\t', f->data.fp);
|
||||||
|
|
||||||
while (++i < COMMENT_TAB);
|
while (++i < COMMENT_TAB);
|
||||||
|
|
||||||
fprintf(f->fp, comment);
|
fprintf(f->data.fp, comment);
|
||||||
}
|
}
|
||||||
fputc('\n', f->fp);
|
fputc('\n', f->data.fp);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _out_with_comment_raw(struct formatter *f, const char *comment,
|
||||||
|
const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
n = vsnprintf(f->data.buf.buf, f->data.buf.size - f->data.buf.used,
|
||||||
|
fmt, ap);
|
||||||
|
|
||||||
|
if (n < 0 || (n > f->data.buf.size - f->data.buf.used - 1))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
f->data.buf.buf += n;
|
||||||
|
f->data.buf.used += n;
|
||||||
|
|
||||||
|
f->nl(f);
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -107,11 +182,11 @@ static void _out_with_comment(struct formatter *f, const char *comment,
|
|||||||
*/
|
*/
|
||||||
static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
|
static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
|
||||||
{
|
{
|
||||||
static char *_units[] = {
|
static const char *_units[] = {
|
||||||
"Kilobytes",
|
"Kilobytes",
|
||||||
"Megabytes",
|
"Megabytes",
|
||||||
"Gigabytes",
|
"Gigabytes",
|
||||||
"Terrabytes",
|
"Terabytes",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -131,43 +206,55 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
|
|||||||
* Appends a comment giving a size in more easily
|
* Appends a comment giving a size in more easily
|
||||||
* readable form (eg, 4M instead of 8096).
|
* readable form (eg, 4M instead of 8096).
|
||||||
*/
|
*/
|
||||||
static void _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
|
static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
int r;
|
||||||
|
|
||||||
_sectors_to_units(size, buffer, sizeof(buffer));
|
if (!_sectors_to_units(size, buffer, sizeof(buffer)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
_out_with_comment(f, buffer, fmt, ap);
|
r = f->out_with_comment(f, buffer, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Appends a comment indicating that the line is
|
* Appends a comment indicating that the line is
|
||||||
* only a hint.
|
* only a hint.
|
||||||
*/
|
*/
|
||||||
static void _out_hint(struct formatter *f, const char *fmt, ...)
|
static int _out_hint(struct formatter *f, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
int r;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
_out_with_comment(f, "# Hint only", fmt, ap);
|
r = f->out_with_comment(f, "# Hint only", fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The normal output function.
|
* The normal output function.
|
||||||
*/
|
*/
|
||||||
static void _out(struct formatter *f, const char *fmt, ...)
|
static int _out(struct formatter *f, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
int r;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
_out_with_comment(f, NULL, fmt, ap);
|
r = f->out_with_comment(f, NULL, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define _outf(args...) do {if (!_out(args)) {stack; return 0;}} while (0)
|
||||||
|
|
||||||
static int _print_header(struct formatter *f,
|
static int _print_header(struct formatter *f,
|
||||||
struct volume_group *vg, const char *desc)
|
struct volume_group *vg, const char *desc)
|
||||||
{
|
{
|
||||||
@@ -175,39 +262,58 @@ static int _print_header(struct formatter *f,
|
|||||||
|
|
||||||
t = time(NULL);
|
t = time(NULL);
|
||||||
|
|
||||||
_out(f,
|
_outf(f, "# Generated by LVM2: %s", ctime(&t));
|
||||||
"# This file was originally generated by the LVM2 library\n"
|
_outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
|
||||||
"# Generated: %s\n", ctime(&t));
|
_outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE);
|
||||||
|
f->nl(f);
|
||||||
|
|
||||||
_out(f, "description = \"%s\"", desc);
|
_outf(f, "description = \"%s\"", desc);
|
||||||
_out(f, "creation_time = %lu\n", t);
|
f->nl(f);
|
||||||
|
_outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
|
||||||
|
_utsname.sysname, _utsname.nodename, _utsname.release,
|
||||||
|
_utsname.version, _utsname.machine);
|
||||||
|
_outf(f, "creation_time = %lu\t# %s", t, ctime(&t));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _print_vg(struct formatter *f, struct volume_group *vg)
|
static int _print_vg(struct formatter *f, struct volume_group *vg)
|
||||||
{
|
{
|
||||||
char buffer[256];
|
char buffer[4096];
|
||||||
|
|
||||||
if (!id_write_format(&vg->id, buffer, sizeof(buffer))) {
|
if (!id_write_format(&vg->id, buffer, sizeof(buffer))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_out(f, "id = \"%s\"", buffer);
|
_outf(f, "id = \"%s\"", buffer);
|
||||||
|
|
||||||
|
_outf(f, "seqno = %u", vg->seqno);
|
||||||
|
|
||||||
_out(f, "seqno = %u", vg->seqno);
|
|
||||||
if (!print_flags(vg->status, VG_FLAGS, buffer, sizeof(buffer))) {
|
if (!print_flags(vg->status, VG_FLAGS, buffer, sizeof(buffer))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
_outf(f, "status = %s", buffer);
|
||||||
|
|
||||||
|
if (!list_empty(&vg->tags)) {
|
||||||
|
if (!print_tags(&vg->tags, buffer, sizeof(buffer))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_outf(f, "tags = %s", buffer);
|
||||||
|
}
|
||||||
|
|
||||||
_out(f, "status = %s", buffer);
|
|
||||||
if (vg->system_id && *vg->system_id)
|
if (vg->system_id && *vg->system_id)
|
||||||
_out(f, "system_id = \"%s\"", vg->system_id);
|
_outf(f, "system_id = \"%s\"", vg->system_id);
|
||||||
_out_size(f, vg->extent_size, "extent_size = %u", vg->extent_size);
|
|
||||||
_out(f, "max_lv = %u", vg->max_lv);
|
if (!_out_size(f, (uint64_t) vg->extent_size, "extent_size = %u",
|
||||||
_out(f, "max_pv = %u", vg->max_pv);
|
vg->extent_size)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_outf(f, "max_lv = %u", vg->max_lv);
|
||||||
|
_outf(f, "max_pv = %u", vg->max_pv);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -227,14 +333,13 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
|||||||
{
|
{
|
||||||
struct list *pvh;
|
struct list *pvh;
|
||||||
struct physical_volume *pv;
|
struct physical_volume *pv;
|
||||||
char buffer[256];
|
char buffer[4096];
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
_out(f, "physical_volumes {");
|
_outf(f, "physical_volumes {");
|
||||||
_inc_indent(f);
|
_inc_indent(f);
|
||||||
|
|
||||||
list_iterate(pvh, &vg->pvs) {
|
list_iterate(pvh, &vg->pvs) {
|
||||||
|
|
||||||
pv = list_item(pvh, struct pv_list)->pv;
|
pv = list_item(pvh, struct pv_list)->pv;
|
||||||
|
|
||||||
if (!(name = _get_pv_name(f, pv))) {
|
if (!(name = _get_pv_name(f, pv))) {
|
||||||
@@ -242,8 +347,8 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_nl(f);
|
f->nl(f);
|
||||||
_out(f, "%s {", name);
|
_outf(f, "%s {", name);
|
||||||
_inc_indent(f);
|
_inc_indent(f);
|
||||||
|
|
||||||
if (!id_write_format(&pv->id, buffer, sizeof(buffer))) {
|
if (!id_write_format(&pv->id, buffer, sizeof(buffer))) {
|
||||||
@@ -251,65 +356,126 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_out(f, "id = \"%s\"", buffer);
|
_outf(f, "id = \"%s\"", buffer);
|
||||||
_out_hint(f, "device = \"%s\"", dev_name(pv->dev));
|
if (!_out_hint(f, "device = \"%s\"", dev_name(pv->dev))) {
|
||||||
_nl(f);
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
f->nl(f);
|
||||||
|
|
||||||
if (!print_flags(pv->status, PV_FLAGS, buffer, sizeof(buffer))) {
|
if (!print_flags(pv->status, PV_FLAGS, buffer, sizeof(buffer))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
_outf(f, "status = %s", buffer);
|
||||||
|
|
||||||
_out(f, "status = %s", buffer);
|
if (!list_empty(&pv->tags)) {
|
||||||
_out(f, "pe_start = %llu", pv->pe_start);
|
if (!print_tags(&pv->tags, buffer, sizeof(buffer))) {
|
||||||
_out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
|
stack;
|
||||||
"pe_count = %u", pv->pe_count);
|
return 0;
|
||||||
|
}
|
||||||
|
_outf(f, "tags = %s", buffer);
|
||||||
|
}
|
||||||
|
|
||||||
_dec_indent(f);
|
_outf(f, "pe_start = %" PRIu64, pv->pe_start);
|
||||||
_out(f, "}");
|
if (!_out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
|
||||||
}
|
"pe_count = %u", pv->pe_count)) {
|
||||||
|
|
||||||
_dec_indent(f);
|
|
||||||
_out(f, "}");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _print_segment(struct formatter *f, struct volume_group *vg,
|
|
||||||
int count, struct stripe_segment *seg)
|
|
||||||
{
|
|
||||||
int s;
|
|
||||||
const char *name;
|
|
||||||
|
|
||||||
_out(f, "segment%u {", count);
|
|
||||||
_inc_indent(f);
|
|
||||||
|
|
||||||
_out(f, "start_extent = %u", seg->le);
|
|
||||||
_out_size(f, seg->len * vg->extent_size, "extent_count = %u", seg->len);
|
|
||||||
_out(f, "stripes = %u", seg->stripes);
|
|
||||||
|
|
||||||
if (seg->stripes > 1)
|
|
||||||
_out_size(f, seg->stripe_size,
|
|
||||||
"stripe_size = %u", seg->stripe_size);
|
|
||||||
|
|
||||||
_nl(f);
|
|
||||||
_out(f, "areas = [");
|
|
||||||
_inc_indent(f);
|
|
||||||
|
|
||||||
for (s = 0; s < seg->stripes; s++) {
|
|
||||||
if (!(name = _get_pv_name(f, seg->area[s].pv))) {
|
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_out(f, "\"%s\", %u%s", name, seg->area[s].pe,
|
_dec_indent(f);
|
||||||
(s == seg->stripes - 1) ? "" : ",");
|
_outf(f, "}");
|
||||||
}
|
}
|
||||||
|
|
||||||
_dec_indent(f);
|
_dec_indent(f);
|
||||||
_out(f, "]");
|
_outf(f, "}");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _print_segment(struct formatter *f, struct volume_group *vg,
|
||||||
|
int count, struct lv_segment *seg)
|
||||||
|
{
|
||||||
|
unsigned int s;
|
||||||
|
const char *name;
|
||||||
|
const char *type;
|
||||||
|
char buffer[4096];
|
||||||
|
|
||||||
|
_outf(f, "segment%u {", count);
|
||||||
|
_inc_indent(f);
|
||||||
|
|
||||||
|
_outf(f, "start_extent = %u", seg->le);
|
||||||
|
if (!_out_size(f, (uint64_t) seg->len * vg->extent_size,
|
||||||
|
"extent_count = %u", seg->len)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
f->nl(f);
|
||||||
|
_outf(f, "type = \"%s\"", get_segtype_string(seg->type));
|
||||||
|
|
||||||
|
if (!list_empty(&seg->tags)) {
|
||||||
|
if (!print_tags(&seg->tags, buffer, sizeof(buffer))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_outf(f, "tags = %s", buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (seg->type) {
|
||||||
|
case SEG_SNAPSHOT:
|
||||||
|
_outf(f, "chunk_size = %u", seg->chunk_size);
|
||||||
|
_outf(f, "origin = \"%s\"", seg->origin->name);
|
||||||
|
_outf(f, "cow_store = \"%s\"", seg->cow->name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEG_MIRRORED:
|
||||||
|
case SEG_STRIPED:
|
||||||
|
type = (seg->type == SEG_MIRRORED) ? "mirror" : "stripe";
|
||||||
|
_outf(f, "%s_count = %u%s", type, seg->area_count,
|
||||||
|
(seg->area_count == 1) ? "\t# linear" : "");
|
||||||
|
|
||||||
|
if ((seg->type == SEG_MIRRORED) && (seg->status & PVMOVE))
|
||||||
|
_out_size(f, (uint64_t) seg->extents_moved,
|
||||||
|
"extents_moved = %u", seg->extents_moved);
|
||||||
|
|
||||||
|
if ((seg->type == SEG_STRIPED) && (seg->area_count > 1))
|
||||||
|
_out_size(f, (uint64_t) seg->stripe_size,
|
||||||
|
"stripe_size = %u", seg->stripe_size);
|
||||||
|
|
||||||
|
f->nl(f);
|
||||||
|
|
||||||
|
_outf(f, "%ss = [", type);
|
||||||
|
_inc_indent(f);
|
||||||
|
|
||||||
|
for (s = 0; s < seg->area_count; s++) {
|
||||||
|
switch (seg->area[s].type) {
|
||||||
|
case AREA_PV:
|
||||||
|
if (!(name = _get_pv_name(f, seg->
|
||||||
|
area[s].u.pv.pv))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_outf(f, "\"%s\", %u%s", name,
|
||||||
|
seg->area[s].u.pv.pe,
|
||||||
|
(s == seg->area_count - 1) ? "" : ",");
|
||||||
|
break;
|
||||||
|
case AREA_LV:
|
||||||
|
_outf(f, "\"%s\", %u%s",
|
||||||
|
seg->area[s].u.lv.lv->name,
|
||||||
|
seg->area[s].u.lv.le,
|
||||||
|
(s == seg->area_count - 1) ? "" : ",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_dec_indent(f);
|
||||||
|
_outf(f, "]");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
_dec_indent(f);
|
_dec_indent(f);
|
||||||
_out(f, "}");
|
_outf(f, "}");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -325,83 +491,51 @@ static int _count_segments(struct logical_volume *lv)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
static int _print_snapshot(struct formatter *f, struct snapshot *snap,
|
||||||
|
unsigned int count)
|
||||||
{
|
{
|
||||||
struct list *lvh, *segh;
|
|
||||||
struct logical_volume *lv;
|
|
||||||
struct stripe_segment *seg;
|
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
int seg_count;
|
struct lv_segment seg;
|
||||||
|
|
||||||
/*
|
f->nl(f);
|
||||||
* Don't bother with an lv section if there are no lvs.
|
|
||||||
*/
|
|
||||||
if (list_empty(&vg->lvs))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
_out(f, "logical_volumes {");
|
_outf(f, "snapshot%u {", count);
|
||||||
_inc_indent(f);
|
_inc_indent(f);
|
||||||
|
|
||||||
list_iterate(lvh, &vg->lvs) {
|
if (!id_write_format(&snap->id, buffer, sizeof(buffer))) {
|
||||||
lv = list_item(lvh, struct lv_list)->lv;
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
_nl(f);
|
_outf(f, "id = \"%s\"", buffer);
|
||||||
_out(f, "%s {", lv->name);
|
if (!print_flags(LVM_READ | LVM_WRITE | VISIBLE_LV, LV_FLAGS,
|
||||||
_inc_indent(f);
|
buffer, sizeof(buffer))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* FIXME: Write full lvid */
|
_outf(f, "status = %s", buffer);
|
||||||
if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) {
|
_outf(f, "segment_count = 1");
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_out(f, "id = \"%s\"", buffer);
|
f->nl(f);
|
||||||
|
|
||||||
if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
|
seg.type = SEG_SNAPSHOT;
|
||||||
stack;
|
seg.le = 0;
|
||||||
return 0;
|
seg.len = snap->origin->le_count;
|
||||||
}
|
seg.origin = snap->origin;
|
||||||
|
seg.cow = snap->cow;
|
||||||
|
seg.chunk_size = snap->chunk_size;
|
||||||
|
|
||||||
_out(f, "status = %s", buffer);
|
/* Can't tag a snapshot independently of its origin */
|
||||||
_out(f, "read_ahead = %u", lv->read_ahead);
|
list_init(&seg.tags);
|
||||||
if (lv->minor >= 0)
|
|
||||||
_out(f, "minor = %d", lv->minor);
|
|
||||||
_out(f, "segment_count = %u", _count_segments(lv));
|
|
||||||
_nl(f);
|
|
||||||
|
|
||||||
seg_count = 1;
|
if (!_print_segment(f, snap->origin->vg, 1, &seg)) {
|
||||||
list_iterate(segh, &lv->segments) {
|
stack;
|
||||||
seg = list_item(segh, struct stripe_segment);
|
return 0;
|
||||||
|
|
||||||
if (!_print_segment(f, vg, seg_count++, seg)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_dec_indent(f);
|
|
||||||
_out(f, "}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_dec_indent(f);
|
_dec_indent(f);
|
||||||
_out(f, "}");
|
_outf(f, "}");
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _print_snapshot(struct formatter *f, struct snapshot *s,
|
|
||||||
unsigned int count)
|
|
||||||
{
|
|
||||||
_nl(f);
|
|
||||||
_out(f, "snapshot%u {", count);
|
|
||||||
_inc_indent(f);
|
|
||||||
|
|
||||||
_out(f, "chunk_size = %u", s->chunk_size);
|
|
||||||
_out(f, "origin = \"%s\"", s->origin->name);
|
|
||||||
_out(f, "cow_store = \"%s\"", s->cow->name);
|
|
||||||
|
|
||||||
_dec_indent(f);
|
|
||||||
_out(f, "}");
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -412,16 +546,6 @@ static int _print_snapshots(struct formatter *f, struct volume_group *vg)
|
|||||||
struct snapshot *s;
|
struct snapshot *s;
|
||||||
unsigned int count = 0;
|
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) {
|
list_iterate(sh, &vg->snapshots) {
|
||||||
s = list_item(sh, struct snapshot_list)->snapshot;
|
s = list_item(sh, struct snapshot_list)->snapshot;
|
||||||
|
|
||||||
@@ -431,8 +555,86 @@ static int _print_snapshots(struct formatter *f, struct volume_group *vg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
||||||
|
{
|
||||||
|
struct list *lvh;
|
||||||
|
struct logical_volume *lv;
|
||||||
|
struct lv_segment *seg;
|
||||||
|
char buffer[4096];
|
||||||
|
int seg_count;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't bother with an lv section if there are no lvs.
|
||||||
|
*/
|
||||||
|
if (list_empty(&vg->lvs))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
_outf(f, "logical_volumes {");
|
||||||
|
_inc_indent(f);
|
||||||
|
|
||||||
|
list_iterate(lvh, &vg->lvs) {
|
||||||
|
lv = list_item(lvh, struct lv_list)->lv;
|
||||||
|
|
||||||
|
f->nl(f);
|
||||||
|
_outf(f, "%s {", lv->name);
|
||||||
|
_inc_indent(f);
|
||||||
|
|
||||||
|
/* FIXME: Write full lvid */
|
||||||
|
if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_outf(f, "id = \"%s\"", buffer);
|
||||||
|
|
||||||
|
if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_outf(f, "status = %s", buffer);
|
||||||
|
|
||||||
|
if (!list_empty(&lv->tags)) {
|
||||||
|
if (!print_tags(&lv->tags, buffer, sizeof(buffer))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_outf(f, "tags = %s", buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lv->alloc != ALLOC_DEFAULT)
|
||||||
|
_outf(f, "allocation_policy = \"%s\"",
|
||||||
|
get_alloc_string(lv->alloc));
|
||||||
|
if (lv->read_ahead)
|
||||||
|
_outf(f, "read_ahead = %u", lv->read_ahead);
|
||||||
|
if (lv->major >= 0)
|
||||||
|
_outf(f, "major = %d", lv->major);
|
||||||
|
if (lv->minor >= 0)
|
||||||
|
_outf(f, "minor = %d", lv->minor);
|
||||||
|
_outf(f, "segment_count = %u", _count_segments(lv));
|
||||||
|
f->nl(f);
|
||||||
|
|
||||||
|
seg_count = 1;
|
||||||
|
list_iterate_items(seg, &lv->segments) {
|
||||||
|
if (!_print_segment(f, vg, seg_count++, seg)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_dec_indent(f);
|
||||||
|
_outf(f, "}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_print_snapshots(f, vg)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
_dec_indent(f);
|
_dec_indent(f);
|
||||||
_out(f, "}");
|
_outf(f, "}");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -462,6 +664,7 @@ static int _build_pv_names(struct formatter *f, struct volume_group *vg)
|
|||||||
list_iterate(pvh, &vg->pvs) {
|
list_iterate(pvh, &vg->pvs) {
|
||||||
pv = list_item(pvh, struct pv_list)->pv;
|
pv = list_item(pvh, struct pv_list)->pv;
|
||||||
|
|
||||||
|
/* FIXME But skip if there's already an LV called pv%d ! */
|
||||||
if (lvm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0) {
|
if (lvm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0) {
|
||||||
stack;
|
stack;
|
||||||
goto bad;
|
goto bad;
|
||||||
@@ -490,19 +693,10 @@ static int _build_pv_names(struct formatter *f, struct volume_group *vg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int text_vg_export(FILE * fp, struct volume_group *vg, const char *desc)
|
static int _text_vg_export(struct formatter *f,
|
||||||
|
struct volume_group *vg, const char *desc)
|
||||||
{
|
{
|
||||||
int r = 0;
|
int r = 0;
|
||||||
struct formatter *f;
|
|
||||||
|
|
||||||
if (!(f = dbg_malloc(sizeof(*f)))) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(f, 0, sizeof(*f));
|
|
||||||
f->fp = fp;
|
|
||||||
f->indent = 0;
|
|
||||||
|
|
||||||
if (!_build_pv_names(f, vg)) {
|
if (!_build_pv_names(f, vg)) {
|
||||||
stack;
|
stack;
|
||||||
@@ -510,32 +704,34 @@ int text_vg_export(FILE * fp, struct volume_group *vg, const char *desc)
|
|||||||
}
|
}
|
||||||
#define fail do {stack; goto out;} while(0)
|
#define fail do {stack; goto out;} while(0)
|
||||||
|
|
||||||
if (!_print_header(f, vg, desc))
|
if (f->header && !_print_header(f, vg, desc))
|
||||||
|
fail;
|
||||||
|
|
||||||
|
if (!_out(f, "%s {", vg->name))
|
||||||
fail;
|
fail;
|
||||||
|
|
||||||
_out(f, "%s {", vg->name);
|
|
||||||
_inc_indent(f);
|
_inc_indent(f);
|
||||||
|
|
||||||
if (!_print_vg(f, vg))
|
if (!_print_vg(f, vg))
|
||||||
fail;
|
fail;
|
||||||
|
|
||||||
_nl(f);
|
f->nl(f);
|
||||||
if (!_print_pvs(f, vg))
|
if (!_print_pvs(f, vg))
|
||||||
fail;
|
fail;
|
||||||
|
|
||||||
_nl(f);
|
f->nl(f);
|
||||||
if (!_print_lvs(f, vg))
|
if (!_print_lvs(f, vg))
|
||||||
fail;
|
fail;
|
||||||
|
|
||||||
_nl(f);
|
_dec_indent(f);
|
||||||
if (!_print_snapshots(f, vg))
|
if (!_out(f, "}"))
|
||||||
|
fail;
|
||||||
|
|
||||||
|
if (!f->header && !_print_header(f, vg, desc))
|
||||||
fail;
|
fail;
|
||||||
|
|
||||||
#undef fail
|
#undef fail
|
||||||
|
r = 1;
|
||||||
_dec_indent(f);
|
|
||||||
_out(f, "}");
|
|
||||||
r = !ferror(f->fp);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (f->mem)
|
if (f->mem)
|
||||||
@@ -544,6 +740,68 @@ int text_vg_export(FILE * fp, struct volume_group *vg, const char *desc)
|
|||||||
if (f->pv_names)
|
if (f->pv_names)
|
||||||
hash_destroy(f->pv_names);
|
hash_destroy(f->pv_names);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp)
|
||||||
|
{
|
||||||
|
struct formatter *f;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
_init();
|
||||||
|
|
||||||
|
if (!(f = dbg_malloc(sizeof(*f)))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(f, 0, sizeof(*f));
|
||||||
|
f->data.fp = fp;
|
||||||
|
f->indent = 0;
|
||||||
|
f->header = 1;
|
||||||
|
f->out_with_comment = &_out_with_comment_file;
|
||||||
|
f->nl = &_nl_file;
|
||||||
|
|
||||||
|
r = _text_vg_export(f, vg, desc);
|
||||||
|
if (r)
|
||||||
|
r = !ferror(f->data.fp);
|
||||||
dbg_free(f);
|
dbg_free(f);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns amount of buffer used incl. terminating NUL */
|
||||||
|
int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
|
||||||
|
uint32_t size)
|
||||||
|
{
|
||||||
|
struct formatter *f;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
_init();
|
||||||
|
|
||||||
|
if (!(f = dbg_malloc(sizeof(*f)))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(f, 0, sizeof(*f));
|
||||||
|
f->data.buf.buf = buf;
|
||||||
|
f->data.buf.size = size;
|
||||||
|
f->indent = 0;
|
||||||
|
f->header = 0;
|
||||||
|
f->out_with_comment = &_out_with_comment_raw;
|
||||||
|
f->nl = &_nl_raw;
|
||||||
|
|
||||||
|
if (!_text_vg_export(f, vg, desc)) {
|
||||||
|
stack;
|
||||||
|
r = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = f->data.buf.used + 1;
|
||||||
|
|
||||||
|
out:
|
||||||
|
dbg_free(f);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef _outf
|
||||||
|
|||||||
@@ -1,10 +1,19 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "log.h"
|
#include "lib.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
#include "import-export.h"
|
#include "import-export.h"
|
||||||
#include "lvm-string.h"
|
#include "lvm-string.h"
|
||||||
@@ -14,14 +23,15 @@
|
|||||||
* converted into arrays of strings.
|
* converted into arrays of strings.
|
||||||
*/
|
*/
|
||||||
struct flag {
|
struct flag {
|
||||||
int mask;
|
const int mask;
|
||||||
char *description;
|
const char *description;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct flag _vg_flags[] = {
|
static struct flag _vg_flags[] = {
|
||||||
{EXPORTED_VG, "EXPORTED"},
|
{EXPORTED_VG, "EXPORTED"},
|
||||||
{RESIZEABLE_VG, "RESIZEABLE"},
|
{RESIZEABLE_VG, "RESIZEABLE"},
|
||||||
{PARTIAL_VG, "PARTIAL"},
|
{PARTIAL_VG, "PARTIAL"},
|
||||||
|
{PVMOVE, "PVMOVE"},
|
||||||
{LVM_READ, "READ"},
|
{LVM_READ, "READ"},
|
||||||
{LVM_WRITE, "WRITE"},
|
{LVM_WRITE, "WRITE"},
|
||||||
{CLUSTERED, "CLUSTERED"},
|
{CLUSTERED, "CLUSTERED"},
|
||||||
@@ -38,10 +48,10 @@ static struct flag _pv_flags[] = {
|
|||||||
static struct flag _lv_flags[] = {
|
static struct flag _lv_flags[] = {
|
||||||
{LVM_READ, "READ"},
|
{LVM_READ, "READ"},
|
||||||
{LVM_WRITE, "WRITE"},
|
{LVM_WRITE, "WRITE"},
|
||||||
{ALLOC_SIMPLE, "ALLOC_SIMPLE"},
|
|
||||||
{ALLOC_STRICT, "ALLOC_STRICT"},
|
|
||||||
{ALLOC_CONTIGUOUS, "ALLOC_CONTIGUOUS"},
|
|
||||||
{FIXED_MINOR, "FIXED_MINOR"},
|
{FIXED_MINOR, "FIXED_MINOR"},
|
||||||
|
{VISIBLE_LV, "VISIBLE"},
|
||||||
|
{PVMOVE, "PVMOVE"},
|
||||||
|
{LOCKED, "LOCKED"},
|
||||||
{0, NULL}
|
{0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -62,23 +72,6 @@ static struct flag *_get_flags(int type)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _emit(char **buffer, size_t * size, const char *fmt, ...)
|
|
||||||
{
|
|
||||||
size_t n;
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
n = vsnprintf(*buffer, *size, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
if (n < 0 || (n == *size))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
*buffer += n;
|
|
||||||
*size -= n;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Converts a bitset to an array of string values,
|
* Converts a bitset to an array of string values,
|
||||||
* using one of the tables defined at the top of
|
* using one of the tables defined at the top of
|
||||||
@@ -94,27 +87,27 @@ int print_flags(uint32_t status, int type, char *buffer, size_t size)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_emit(&buffer, &size, "["))
|
if (!emit_to_buffer(&buffer, &size, "["))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (f = 0; flags[f].mask; f++) {
|
for (f = 0; flags[f].mask; f++) {
|
||||||
if (status & flags[f].mask) {
|
if (status & flags[f].mask) {
|
||||||
if (!first) {
|
if (!first) {
|
||||||
if (!_emit(&buffer, &size, ", "))
|
if (!emit_to_buffer(&buffer, &size, ", "))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
} else
|
} else
|
||||||
first = 0;
|
first = 0;
|
||||||
|
|
||||||
if (!_emit(&buffer, &size, "\"%s\"",
|
if (!emit_to_buffer(&buffer, &size, "\"%s\"",
|
||||||
flags[f].description))
|
flags[f].description))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
status &= ~flags[f].mask;
|
status &= ~flags[f].mask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_emit(&buffer, &size, "]"))
|
if (!emit_to_buffer(&buffer, &size, "]"))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (status)
|
if (status)
|
||||||
@@ -124,7 +117,7 @@ int print_flags(uint32_t status, int type, char *buffer, size_t size)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_flags(uint32_t * status, int type, struct config_value *cv)
|
int read_flags(uint32_t *status, int type, struct config_value *cv)
|
||||||
{
|
{
|
||||||
int f;
|
int f;
|
||||||
uint32_t s = 0;
|
uint32_t s = 0;
|
||||||
@@ -135,6 +128,9 @@ int read_flags(uint32_t * status, int type, struct config_value *cv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cv->type == CFG_EMPTY_ARRAY)
|
||||||
|
goto out;
|
||||||
|
|
||||||
while (cv) {
|
while (cv) {
|
||||||
if (cv->type != CFG_STRING) {
|
if (cv->type != CFG_STRING) {
|
||||||
log_err("Status value is not a string.");
|
log_err("Status value is not a string.");
|
||||||
@@ -155,6 +151,7 @@ int read_flags(uint32_t * status, int type, struct config_value *cv)
|
|||||||
cv = cv->next;
|
cv = cv->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
*status = s;
|
*status = s;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_FORMAT_TEXT_H
|
#ifndef _LVM_FORMAT_TEXT_H
|
||||||
@@ -9,7 +18,7 @@
|
|||||||
|
|
||||||
#include "lvm-types.h"
|
#include "lvm-types.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
#include "uuid-map.h"
|
#include "pool.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Archives a vg config. 'retain_days' is the minimum number of
|
* Archives a vg config. 'retain_days' is the minimum number of
|
||||||
@@ -19,21 +28,34 @@
|
|||||||
*/
|
*/
|
||||||
int archive_vg(struct volume_group *vg,
|
int archive_vg(struct volume_group *vg,
|
||||||
const char *dir,
|
const char *dir,
|
||||||
const char *desc,
|
const char *desc, uint32_t retain_days, uint32_t min_archive);
|
||||||
uint32_t retain_days,
|
|
||||||
uint32_t min_archive);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Displays a list of vg backups in a particular archive directory.
|
* Displays a list of vg backups in a particular archive directory.
|
||||||
*/
|
*/
|
||||||
int archive_list(struct cmd_context *cmd, struct uuid_map *um,
|
int archive_list(struct cmd_context *cmd, const char *dir, const char *vgname);
|
||||||
const char *dir, const char *vg);
|
int backup_list(struct cmd_context *cmd, const char *dir, const char *vgname);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The text format can read and write a volume_group to a file.
|
* The text format can read and write a volume_group to a file.
|
||||||
*/
|
*/
|
||||||
struct format_type *create_text_format(struct cmd_context *cmd);
|
struct format_type *create_text_format(struct cmd_context *cmd);
|
||||||
void *create_text_context(struct format_type *fmt, const char *path,
|
void *create_text_context(struct cmd_context *cmd, const char *path,
|
||||||
const char *desc);
|
const char *desc);
|
||||||
|
|
||||||
|
struct labeller *text_labeller_create(const struct format_type *fmt);
|
||||||
|
|
||||||
|
int pvhdr_read(struct device *dev, char *buf);
|
||||||
|
|
||||||
|
int add_da(const struct format_type *fmt, struct pool *mem, struct list *das,
|
||||||
|
uint64_t start, uint64_t size);
|
||||||
|
void del_das(struct list *das);
|
||||||
|
|
||||||
|
int add_mda(const struct format_type *fmt, struct pool *mem, struct list *mdas,
|
||||||
|
struct device *dev, uint64_t start, uint64_t size);
|
||||||
|
void del_mdas(struct list *mdas);
|
||||||
|
|
||||||
|
int vgname_from_mda(const struct format_type *fmt, struct device_area *dev_area,
|
||||||
|
char *buf, uint32_t size);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_TEXT_IMPORT_EXPORT_H
|
#ifndef _LVM_TEXT_IMPORT_EXPORT_H
|
||||||
@@ -10,24 +19,58 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "lvm-types.h"
|
#include "lvm-types.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
#include "uuid-map.h"
|
#include "pool.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constants to identify files this code can parse.
|
||||||
|
*/
|
||||||
|
#define CONTENTS_FIELD "contents"
|
||||||
|
#define CONTENTS_VALUE "Text Format Volume Group"
|
||||||
|
|
||||||
|
#define FORMAT_VERSION_FIELD "version"
|
||||||
|
#define FORMAT_VERSION_VALUE 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* VGs, PVs and LVs all have status bitsets, we gather together
|
||||||
|
* common code for reading and writing them.
|
||||||
|
*/
|
||||||
enum {
|
enum {
|
||||||
VG_FLAGS,
|
VG_FLAGS,
|
||||||
PV_FLAGS,
|
PV_FLAGS,
|
||||||
LV_FLAGS
|
LV_FLAGS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct text_vg_version_ops {
|
||||||
|
int (*check_version) (struct config_tree * cf);
|
||||||
|
struct volume_group *(*read_vg) (struct format_instance * fid,
|
||||||
|
struct config_tree * cf);
|
||||||
|
void (*read_desc) (struct pool * mem, struct config_tree * cf,
|
||||||
|
time_t *when, char **desc);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct text_vg_version_ops *text_vg_vsn1_init(void);
|
||||||
|
|
||||||
int print_flags(uint32_t status, int type, char *buffer, size_t size);
|
int 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 read_flags(uint32_t *status, int type, struct config_value *cv);
|
||||||
|
|
||||||
|
int print_tags(struct list *tags, char *buffer, size_t size);
|
||||||
|
int read_tags(struct pool *mem, struct list *tags, struct config_value *cv);
|
||||||
|
|
||||||
int text_vg_export(FILE *fp, struct volume_group *vg, const char *desc);
|
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
|
||||||
struct volume_group *text_vg_import(struct format_instance *fid,
|
int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
|
||||||
const char *file,
|
uint32_t size);
|
||||||
struct uuid_map *um,
|
struct volume_group *text_vg_import_file(struct format_instance *fid,
|
||||||
time_t *when, char **desc);
|
const char *file,
|
||||||
|
time_t *when, char **desc);
|
||||||
|
struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||||
|
const char *file,
|
||||||
|
struct device *dev,
|
||||||
|
off_t offset, uint32_t size,
|
||||||
|
off_t offset2, uint32_t size2,
|
||||||
|
checksum_fn_t checksum_fn,
|
||||||
|
uint32_t checksum,
|
||||||
|
time_t *when, char **desc);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,677 +1,91 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
#include "import-export.h"
|
#include "import-export.h"
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
#include "log.h"
|
#include "display.h"
|
||||||
#include "uuid.h"
|
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "toolcontext.h"
|
#include "toolcontext.h"
|
||||||
|
#include "lvmcache.h"
|
||||||
typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
|
|
||||||
struct volume_group * vg, struct config_node * pvn,
|
/* FIXME Use tidier inclusion method */
|
||||||
struct config_node * vgn,
|
static struct text_vg_version_ops *(_text_vsn_list[2]);
|
||||||
struct hash_table * pv_hash, struct uuid_map * um);
|
|
||||||
|
struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||||
#define _read_int32(root, path, result) \
|
const char *file,
|
||||||
get_config_uint32(root, path, '/', result)
|
struct device *dev,
|
||||||
|
off_t offset, uint32_t size,
|
||||||
#define _read_uint32(root, path, result) \
|
off_t offset2, uint32_t size2,
|
||||||
get_config_uint32(root, path, '/', result)
|
checksum_fn_t checksum_fn,
|
||||||
|
uint32_t checksum,
|
||||||
#define _read_int64(root, path, result) \
|
time_t *when, char **desc)
|
||||||
get_config_uint64(root, path, '/', result)
|
|
||||||
|
|
||||||
static int _read_id(struct id *id, struct config_node *cn, const char *path)
|
|
||||||
{
|
|
||||||
struct config_value *cv;
|
|
||||||
|
|
||||||
if (!(cn = find_config_node(cn, path, '/'))) {
|
|
||||||
log_err("Couldn't find uuid.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cv = cn->v;
|
|
||||||
if (!cv || !cv->v.str) {
|
|
||||||
log_err("uuid must be a string.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!id_read_format(id, cv->v.str)) {
|
|
||||||
log_err("Invalid uuid.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _read_pv(struct format_instance *fid, struct pool *mem,
|
|
||||||
struct volume_group *vg, struct config_node *pvn,
|
|
||||||
struct config_node *vgn,
|
|
||||||
struct hash_table *pv_hash, struct uuid_map *um)
|
|
||||||
{
|
|
||||||
struct physical_volume *pv;
|
|
||||||
struct pv_list *pvl;
|
|
||||||
struct config_node *cn;
|
|
||||||
|
|
||||||
if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) ||
|
|
||||||
!(pvl->pv = pool_zalloc(mem, sizeof(*pvl->pv)))) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pv = pvl->pv;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add the pv to the pv hash for quick lookup when we read
|
|
||||||
* the lv segments.
|
|
||||||
*/
|
|
||||||
if (!hash_insert(pv_hash, pvn->key, pv)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(pvn = pvn->child)) {
|
|
||||||
log_err("Empty pv section.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_read_id(&pv->id, pvn, "id")) {
|
|
||||||
log_err("Couldn't read uuid for volume group.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Use the uuid map to convert the uuid into a device.
|
|
||||||
*/
|
|
||||||
if (!(pv->dev = uuid_map_lookup(um, &pv->id))) {
|
|
||||||
char buffer[64];
|
|
||||||
|
|
||||||
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
|
|
||||||
log_err("Couldn't find device.");
|
|
||||||
else
|
|
||||||
log_err("Couldn't find device with uuid '%s'.", buffer);
|
|
||||||
|
|
||||||
if (partial_mode())
|
|
||||||
vg->status |= PARTIAL_VG;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(pv->vg_name = pool_strdup(mem, vg->name))) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(cn = find_config_node(pvn, "status", '/'))) {
|
|
||||||
log_err("Couldn't find status flags for physical volume.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(read_flags(&pv->status, PV_FLAGS, cn->v))) {
|
|
||||||
log_err("Couldn't read status flags for physical volume.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_read_int64(pvn, "pe_start", &pv->pe_start)) {
|
|
||||||
log_err("Couldn't read extent size for volume group.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_read_int32(pvn, "pe_count", &pv->pe_count)) {
|
|
||||||
log_err("Couldn't find extent count (pe_count) for "
|
|
||||||
"physical volume.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* adjust the volume group. */
|
|
||||||
vg->extent_count += pv->pe_count;
|
|
||||||
vg->free_count += pv->pe_count;
|
|
||||||
|
|
||||||
pv->pe_size = vg->extent_size;
|
|
||||||
pv->size = pv->pe_size * (uint64_t) pv->pe_count;
|
|
||||||
pv->pe_alloc_count = 0;
|
|
||||||
pv->fid = fid;
|
|
||||||
|
|
||||||
vg->pv_count++;
|
|
||||||
list_add(&vg->pvs, &pvl->list);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _insert_segment(struct logical_volume *lv,
|
|
||||||
struct stripe_segment *seg)
|
|
||||||
{
|
|
||||||
struct list *segh;
|
|
||||||
struct stripe_segment *comp;
|
|
||||||
|
|
||||||
list_iterate(segh, &lv->segments) {
|
|
||||||
comp = list_item(segh, struct stripe_segment);
|
|
||||||
|
|
||||||
if (comp->le > seg->le) {
|
|
||||||
list_add(&comp->list, &seg->list);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lv->le_count += seg->len;
|
|
||||||
list_add(&lv->segments, &seg->list);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _read_segment(struct pool *mem, struct volume_group *vg,
|
|
||||||
struct logical_volume *lv, struct config_node *sn,
|
|
||||||
struct hash_table *pv_hash)
|
|
||||||
{
|
|
||||||
int s;
|
|
||||||
uint32_t stripes;
|
|
||||||
struct stripe_segment *seg;
|
|
||||||
struct config_node *cn;
|
|
||||||
struct config_value *cv;
|
|
||||||
const char *seg_name = sn->key;
|
|
||||||
|
|
||||||
if (!(sn = sn->child)) {
|
|
||||||
log_err("Empty segment section.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_read_int32(sn, "stripes", &stripes)) {
|
|
||||||
log_err("Couldn't read 'stripes' for segment '%s'.", sn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(seg = pool_zalloc(mem, sizeof(*seg) +
|
|
||||||
(sizeof(seg->area[0]) * stripes)))) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
seg->stripes = stripes;
|
|
||||||
seg->lv = lv;
|
|
||||||
|
|
||||||
if (!_read_int32(sn, "start_extent", &seg->le)) {
|
|
||||||
log_err("Couldn't read 'start_extent' for segment '%s'.",
|
|
||||||
sn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_read_int32(sn, "extent_count", &seg->len)) {
|
|
||||||
log_err("Couldn't read 'extent_count' for segment '%s'.",
|
|
||||||
sn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seg->stripes == 0) {
|
|
||||||
log_err("Zero stripes is *not* allowed for segment '%s'.",
|
|
||||||
sn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((seg->stripes != 1) &&
|
|
||||||
!_read_int32(sn, "stripe_size", &seg->stripe_size)) {
|
|
||||||
log_err("Couldn't read 'stripe_size' for segment '%s'.",
|
|
||||||
sn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(cn = find_config_node(sn, "areas", '/'))) {
|
|
||||||
log_err("Couldn't find 'areas' array for segment '%s'.",
|
|
||||||
sn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read the stripes from the 'areas' array.
|
|
||||||
* FIXME: we could move this to a separate function.
|
|
||||||
*/
|
|
||||||
for (cv = cn->v, s = 0; cv && s < seg->stripes; s++, cv = cv->next) {
|
|
||||||
|
|
||||||
/* first we read the pv */
|
|
||||||
const char *bad = "Badly formed areas array for segment '%s'.";
|
|
||||||
struct physical_volume *pv;
|
|
||||||
uint32_t allocated;
|
|
||||||
|
|
||||||
if (cv->type != CFG_STRING) {
|
|
||||||
log_err(bad, sn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(pv = hash_lookup(pv_hash, cv->v.str))) {
|
|
||||||
log_err("Couldn't find physical volume '%s' for "
|
|
||||||
"segment '%s'.",
|
|
||||||
cn->v->v.str ? cn->v->v.str : "NULL", seg_name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
seg->area[s].pv = pv;
|
|
||||||
|
|
||||||
if (!(cv = cv->next)) {
|
|
||||||
log_err(bad, sn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cv->type != CFG_INT) {
|
|
||||||
log_err(bad, sn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
seg->area[s].pe = cv->v.i;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Adjust the extent counts in the pv and vg.
|
|
||||||
*/
|
|
||||||
allocated = seg->len / seg->stripes;
|
|
||||||
pv->pe_alloc_count += allocated;
|
|
||||||
vg->free_count -= allocated;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check we read the correct number of stripes.
|
|
||||||
*/
|
|
||||||
if (cv || (s < seg->stripes)) {
|
|
||||||
log_err("Incorrect number of stripes in 'area' array "
|
|
||||||
"for segment '%s'.", seg_name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Insert into correct part of segment list.
|
|
||||||
*/
|
|
||||||
_insert_segment(lv, seg);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _read_segments(struct pool *mem, struct volume_group *vg,
|
|
||||||
struct logical_volume *lv, struct config_node *lvn,
|
|
||||||
struct hash_table *pv_hash)
|
|
||||||
{
|
|
||||||
struct config_node *sn;
|
|
||||||
int count = 0, seg_count;
|
|
||||||
|
|
||||||
for (sn = lvn; sn; sn = sn->sib) {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* All sub-sections are assumed to be segments.
|
|
||||||
*/
|
|
||||||
if (!sn->v) {
|
|
||||||
if (!_read_segment(mem, vg, lv, sn, pv_hash)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_read_int32(lvn, "segment_count", &seg_count)) {
|
|
||||||
log_err("Couldn't read segment count for logical volume.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seg_count != count) {
|
|
||||||
log_err("segment_count and actual number of segments "
|
|
||||||
"disagree.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check there are no gaps or overlaps in the lv.
|
|
||||||
*/
|
|
||||||
if (!lv_check_segments(lv)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Merge segments in case someones been editing things by hand.
|
|
||||||
*/
|
|
||||||
if (!lv_merge_segments(lv)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _read_lv(struct format_instance *fid, struct pool *mem,
|
|
||||||
struct volume_group *vg, struct config_node *lvn,
|
|
||||||
struct config_node *vgn, struct hash_table *pv_hash,
|
|
||||||
struct uuid_map *um)
|
|
||||||
{
|
|
||||||
struct logical_volume *lv;
|
|
||||||
struct lv_list *lvl;
|
|
||||||
struct config_node *cn;
|
|
||||||
|
|
||||||
if (!(lvl = pool_zalloc(mem, sizeof(*lvl))) ||
|
|
||||||
!(lvl->lv = pool_zalloc(mem, sizeof(*lvl->lv)))) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
lv = lvl->lv;
|
|
||||||
|
|
||||||
if (!(lv->name = pool_strdup(mem, lvn->key))) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(lvn = lvn->child)) {
|
|
||||||
log_err("Empty logical volume section.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
lv->vg = vg;
|
|
||||||
|
|
||||||
/* FIXME: read full lvid */
|
|
||||||
if (!_read_id(&lv->lvid.id[1], lvn, "id")) {
|
|
||||||
log_err("Couldn't read uuid for logical volume %s.", lv->name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&lv->lvid.id[0], &lv->vg->id, sizeof(lv->lvid.id[0]));
|
|
||||||
|
|
||||||
if (!(cn = find_config_node(lvn, "status", '/'))) {
|
|
||||||
log_err("Couldn't find status flags for logical volume.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(read_flags(&lv->status, LV_FLAGS, cn->v))) {
|
|
||||||
log_err("Couldn't read status flags for logical volume.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
lv->minor = -1;
|
|
||||||
if ((lv->status & FIXED_MINOR) &&
|
|
||||||
!_read_int32(lvn, "minor", &lv->minor)) {
|
|
||||||
log_error("Couldn't read 'minor' value for logical volume.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_read_int32(lvn, "read_ahead", &lv->read_ahead)) {
|
|
||||||
log_err("Couldn't read 'read_ahead' value for "
|
|
||||||
"logical volume.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_init(&lv->segments);
|
|
||||||
if (!_read_segments(mem, vg, lv, lvn, pv_hash)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size;
|
|
||||||
|
|
||||||
vg->lv_count++;
|
|
||||||
list_add(&vg->lvs, &lvl->list);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _read_snapshot(struct format_instance *fid, struct pool *mem,
|
|
||||||
struct volume_group *vg, struct config_node *sn,
|
|
||||||
struct config_node *vgn, struct hash_table *pv_hash,
|
|
||||||
struct uuid_map *um)
|
|
||||||
{
|
|
||||||
uint32_t chunk_size;
|
|
||||||
const char *org_name, *cow_name;
|
|
||||||
struct logical_volume *org, *cow;
|
|
||||||
|
|
||||||
if (!(sn = sn->child)) {
|
|
||||||
log_err("Empty snapshot section.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_read_uint32(sn, "chunk_size", &chunk_size)) {
|
|
||||||
log_err("Couldn't read chunk size for snapshot.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(cow_name = find_config_str(sn, "cow_store", '/', NULL))) {
|
|
||||||
log_err("Snapshot cow storage not specified.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(org_name = find_config_str(sn, "origin", '/', NULL))) {
|
|
||||||
log_err("Snapshot origin not specified.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(cow = find_lv(vg, cow_name))) {
|
|
||||||
log_err("Unknown logical volume specified for "
|
|
||||||
"snapshot cow store.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(org = find_lv(vg, org_name))) {
|
|
||||||
log_err("Unknown logical volume specified for "
|
|
||||||
"snapshot origin.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vg_add_snapshot(org, cow, 1, chunk_size)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _read_sections(struct format_instance *fid,
|
|
||||||
const char *section, section_fn fn,
|
|
||||||
struct pool *mem,
|
|
||||||
struct volume_group *vg, struct config_node *vgn,
|
|
||||||
struct hash_table *pv_hash,
|
|
||||||
struct uuid_map *um, int optional)
|
|
||||||
{
|
|
||||||
struct config_node *n;
|
|
||||||
|
|
||||||
if (!(n = find_config_node(vgn, section, '/'))) {
|
|
||||||
if (!optional) {
|
|
||||||
log_err("Couldn't find section '%s'.", section);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (n = n->child; n; n = n->sib) {
|
|
||||||
if (!fn(fid, mem, vg, n, vgn, pv_hash, um)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct volume_group *_read_vg(struct format_instance *fid,
|
|
||||||
struct config_file *cf,
|
|
||||||
struct uuid_map *um)
|
|
||||||
{
|
|
||||||
struct config_node *vgn, *cn;
|
|
||||||
struct volume_group *vg;
|
|
||||||
struct hash_table *pv_hash = NULL;
|
|
||||||
struct pool *mem = fid->fmt->cmd->mem;
|
|
||||||
|
|
||||||
/* skip any top-level values */
|
|
||||||
for (vgn = cf->root; (vgn && vgn->v); vgn = vgn->sib) ;
|
|
||||||
|
|
||||||
if (!vgn) {
|
|
||||||
log_err("Couldn't find volume group in file.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(vg = pool_zalloc(mem, sizeof(*vg)))) {
|
|
||||||
stack;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
vg->cmd = fid->fmt->cmd;
|
|
||||||
|
|
||||||
/* FIXME Determine format type from file contents */
|
|
||||||
/* eg Set to instance of fmt1 here if reading a format1 backup? */
|
|
||||||
vg->fid = fid;
|
|
||||||
|
|
||||||
if (!(vg->name = pool_strdup(mem, vgn->key))) {
|
|
||||||
stack;
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(vg->system_id = pool_zalloc(mem, NAME_LEN))) {
|
|
||||||
stack;
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
vgn = vgn->child;
|
|
||||||
|
|
||||||
if ((cn = find_config_node(vgn, "system_id", '/')) && cn->v) {
|
|
||||||
if (!cn->v->v.str) {
|
|
||||||
log_error("system_id must be a string");
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
strncpy(vg->system_id, cn->v->v.str, NAME_LEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_read_id(&vg->id, vgn, "id")) {
|
|
||||||
log_err("Couldn't read uuid for volume group %s.", vg->name);
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_read_int32(vgn, "seqno", &vg->seqno)) {
|
|
||||||
log_err("Couldn't read 'seqno' for volume group %s.", vg->name);
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(cn = find_config_node(vgn, "status", '/'))) {
|
|
||||||
log_err("Couldn't find status flags for volume group %s.",
|
|
||||||
vg->name);
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(read_flags(&vg->status, VG_FLAGS, cn->v))) {
|
|
||||||
log_err("Couldn't read status flags for volume group %s.",
|
|
||||||
vg->name);
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_read_int32(vgn, "extent_size", &vg->extent_size)) {
|
|
||||||
log_err("Couldn't read extent size for volume group %s.",
|
|
||||||
vg->name);
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 'extent_count' and 'free_count' get filled in
|
|
||||||
* implicitly when reading in the pv's and lv's.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!_read_int32(vgn, "max_lv", &vg->max_lv)) {
|
|
||||||
log_err("Couldn't read 'max_lv' for volume group %s.",
|
|
||||||
vg->name);
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_read_int32(vgn, "max_pv", &vg->max_pv)) {
|
|
||||||
log_err("Couldn't read 'max_pv' for volume group %s.",
|
|
||||||
vg->name);
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The pv hash memoises the pv section names -> pv
|
|
||||||
* structures.
|
|
||||||
*/
|
|
||||||
if (!(pv_hash = hash_create(32))) {
|
|
||||||
log_err("Couldn't create hash table.");
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_init(&vg->pvs);
|
|
||||||
if (!_read_sections(fid, "physical_volumes", _read_pv, mem, vg,
|
|
||||||
vgn, pv_hash, um, 0)) {
|
|
||||||
log_err("Couldn't find all physical volumes for volume "
|
|
||||||
"group %s.", vg->name);
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_init(&vg->lvs);
|
|
||||||
if (!_read_sections(fid, "logical_volumes", _read_lv, mem, vg,
|
|
||||||
vgn, pv_hash, um, 1)) {
|
|
||||||
log_err("Couldn't read all logical volumes for volume "
|
|
||||||
"group %s.", vg->name);
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_init(&vg->snapshots);
|
|
||||||
if (!_read_sections(fid, "snapshots", _read_snapshot, mem, vg,
|
|
||||||
vgn, pv_hash, um, 1)) {
|
|
||||||
log_err("Couldn't read all snapshots for volume group %s.",
|
|
||||||
vg->name);
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
hash_destroy(pv_hash);
|
|
||||||
|
|
||||||
if (vg->status & PARTIAL_VG) {
|
|
||||||
vg->status &= ~LVM_WRITE;
|
|
||||||
vg->status |= LVM_READ;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Finished.
|
|
||||||
*/
|
|
||||||
return vg;
|
|
||||||
|
|
||||||
bad:
|
|
||||||
if (pv_hash)
|
|
||||||
hash_destroy(pv_hash);
|
|
||||||
|
|
||||||
pool_free(mem, vg);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _read_desc(struct pool *mem,
|
|
||||||
struct config_file *cf, time_t * when, char **desc)
|
|
||||||
{
|
|
||||||
const char *d;
|
|
||||||
unsigned int u = 0u;
|
|
||||||
|
|
||||||
d = find_config_str(cf->root, "description", '/', "");
|
|
||||||
*desc = pool_strdup(mem, d);
|
|
||||||
|
|
||||||
get_config_uint32(cf->root, "creation_time", '/', &u);
|
|
||||||
*when = u;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct volume_group *text_vg_import(struct format_instance *fid,
|
|
||||||
const char *file,
|
|
||||||
struct uuid_map *um,
|
|
||||||
time_t * when, char **desc)
|
|
||||||
{
|
{
|
||||||
struct volume_group *vg = NULL;
|
struct volume_group *vg = NULL;
|
||||||
struct config_file *cf;
|
struct config_tree *cft;
|
||||||
|
struct text_vg_version_ops **vsn;
|
||||||
|
|
||||||
|
static int _initialised = 0;
|
||||||
|
|
||||||
|
if (!_initialised) {
|
||||||
|
_text_vsn_list[0] = text_vg_vsn1_init();
|
||||||
|
_text_vsn_list[1] = NULL;
|
||||||
|
_initialised = 1;
|
||||||
|
}
|
||||||
|
|
||||||
*desc = NULL;
|
*desc = NULL;
|
||||||
*when = 0;
|
*when = 0;
|
||||||
|
|
||||||
if (!(cf = create_config_file())) {
|
if (!(cft = create_config_tree())) {
|
||||||
stack;
|
stack;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!read_config(cf, file)) {
|
if ((!dev && !read_config_file(cft, file)) ||
|
||||||
log_error("Couldn't read volume group file.");
|
(dev && !read_config_fd(cft, dev, offset, size,
|
||||||
|
offset2, size2, checksum_fn, checksum))) {
|
||||||
|
log_error("Couldn't read volume group metadata.");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(vg = _read_vg(fid, cf, um))) {
|
/*
|
||||||
stack;
|
* Find a set of version functions that can read this file
|
||||||
goto out;
|
*/
|
||||||
}
|
for (vsn = &_text_vsn_list[0]; *vsn; vsn++) {
|
||||||
|
if (!(*vsn)->check_version(cft))
|
||||||
|
continue;
|
||||||
|
|
||||||
_read_desc(fid->fmt->cmd->mem, cf, when, desc);
|
if (!(vg = (*vsn)->read_vg(fid, cft))) {
|
||||||
|
stack;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*vsn)->read_desc(fid->fmt->cmd->mem, cft, when, desc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
destroy_config_file(cf);
|
destroy_config_tree(cft);
|
||||||
return vg;
|
return vg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct volume_group *text_vg_import_file(struct format_instance *fid,
|
||||||
|
const char *file,
|
||||||
|
time_t *when, char **desc)
|
||||||
|
{
|
||||||
|
return text_vg_import_fd(fid, file, NULL, 0, 0, 0, 0, NULL, 0,
|
||||||
|
when, desc);
|
||||||
|
}
|
||||||
|
|||||||
854
lib/format_text/import_vsn1.c
Normal file
854
lib/format_text/import_vsn1.c
Normal file
@@ -0,0 +1,854 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
|
#include "metadata.h"
|
||||||
|
#include "import-export.h"
|
||||||
|
#include "pool.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "hash.h"
|
||||||
|
#include "toolcontext.h"
|
||||||
|
#include "lvmcache.h"
|
||||||
|
#include "lv_alloc.h"
|
||||||
|
|
||||||
|
typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
|
||||||
|
struct volume_group * vg, struct config_node * pvn,
|
||||||
|
struct config_node * vgn,
|
||||||
|
struct hash_table * pv_hash);
|
||||||
|
|
||||||
|
#define _read_int32(root, path, result) \
|
||||||
|
get_config_uint32(root, path, result)
|
||||||
|
|
||||||
|
#define _read_uint32(root, path, result) \
|
||||||
|
get_config_uint32(root, path, result)
|
||||||
|
|
||||||
|
#define _read_int64(root, path, result) \
|
||||||
|
get_config_uint64(root, path, result)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Logs an attempt to read an invalid format file.
|
||||||
|
*/
|
||||||
|
static void _invalid_format(const char *str)
|
||||||
|
{
|
||||||
|
log_error("Can't process text format file - %s.", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks that the config file contains vg metadata, and that it
|
||||||
|
* we recognise the version number,
|
||||||
|
*/
|
||||||
|
static int _check_version(struct config_tree *cft)
|
||||||
|
{
|
||||||
|
struct config_node *cn;
|
||||||
|
struct config_value *cv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check the contents field.
|
||||||
|
*/
|
||||||
|
if (!(cn = find_config_node(cft->root, CONTENTS_FIELD))) {
|
||||||
|
_invalid_format("missing contents field");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cv = cn->v;
|
||||||
|
if (!cv || cv->type != CFG_STRING || strcmp(cv->v.str, CONTENTS_VALUE)) {
|
||||||
|
_invalid_format("unrecognised contents field");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check the version number.
|
||||||
|
*/
|
||||||
|
if (!(cn = find_config_node(cft->root, FORMAT_VERSION_FIELD))) {
|
||||||
|
_invalid_format("missing version number");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cv = cn->v;
|
||||||
|
if (!cv || cv->type != CFG_INT || cv->v.i != FORMAT_VERSION_VALUE) {
|
||||||
|
_invalid_format("unrecognised version number");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _read_id(struct id *id, struct config_node *cn, const char *path)
|
||||||
|
{
|
||||||
|
struct config_value *cv;
|
||||||
|
|
||||||
|
if (!(cn = find_config_node(cn, path))) {
|
||||||
|
log_error("Couldn't find uuid.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cv = cn->v;
|
||||||
|
if (!cv || !cv->v.str) {
|
||||||
|
log_error("uuid must be a string.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!id_read_format(id, cv->v.str)) {
|
||||||
|
log_error("Invalid uuid.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _read_pv(struct format_instance *fid, struct pool *mem,
|
||||||
|
struct volume_group *vg, struct config_node *pvn,
|
||||||
|
struct config_node *vgn, struct hash_table *pv_hash)
|
||||||
|
{
|
||||||
|
struct physical_volume *pv;
|
||||||
|
struct pv_list *pvl;
|
||||||
|
struct config_node *cn;
|
||||||
|
|
||||||
|
if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) ||
|
||||||
|
!(pvl->pv = pool_zalloc(mem, sizeof(*pvl->pv)))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pv = pvl->pv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the pv to the pv hash for quick lookup when we read
|
||||||
|
* the lv segments.
|
||||||
|
*/
|
||||||
|
if (!hash_insert(pv_hash, pvn->key, pv)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(pvn = pvn->child)) {
|
||||||
|
log_error("Empty pv section.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_read_id(&pv->id, pvn, "id")) {
|
||||||
|
log_error("Couldn't read uuid for volume group.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert the uuid into a device.
|
||||||
|
*/
|
||||||
|
if (!(pv->dev = device_from_pvid(fid->fmt->cmd, &pv->id))) {
|
||||||
|
char buffer[64];
|
||||||
|
|
||||||
|
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
|
||||||
|
log_error("Couldn't find device.");
|
||||||
|
else
|
||||||
|
log_error("Couldn't find device with uuid '%s'.",
|
||||||
|
buffer);
|
||||||
|
|
||||||
|
if (partial_mode())
|
||||||
|
vg->status |= PARTIAL_VG;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(pv->vg_name = pool_strdup(mem, vg->name))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(cn = find_config_node(pvn, "status"))) {
|
||||||
|
log_error("Couldn't find status flags for physical volume.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(read_flags(&pv->status, PV_FLAGS, cn->v))) {
|
||||||
|
log_error("Couldn't read status flags for physical volume.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_read_int64(pvn, "pe_start", &pv->pe_start)) {
|
||||||
|
log_error("Couldn't read extent size for volume group.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_read_int32(pvn, "pe_count", &pv->pe_count)) {
|
||||||
|
log_error("Couldn't find extent count (pe_count) for "
|
||||||
|
"physical volume.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_init(&pv->tags);
|
||||||
|
|
||||||
|
/* Optional tags */
|
||||||
|
if ((cn = find_config_node(pvn, "tags")) &&
|
||||||
|
!(read_tags(mem, &pv->tags, cn->v))) {
|
||||||
|
log_error("Couldn't read tags for physical volume %s in %s.",
|
||||||
|
dev_name(pv->dev), vg->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* adjust the volume group. */
|
||||||
|
vg->extent_count += pv->pe_count;
|
||||||
|
vg->free_count += pv->pe_count;
|
||||||
|
|
||||||
|
pv->pe_size = vg->extent_size;
|
||||||
|
pv->size = vg->extent_size * (uint64_t) pv->pe_count;
|
||||||
|
pv->pe_alloc_count = 0;
|
||||||
|
pv->fmt = fid->fmt;
|
||||||
|
|
||||||
|
vg->pv_count++;
|
||||||
|
list_add(&vg->pvs, &pvl->list);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _insert_segment(struct logical_volume *lv, struct lv_segment *seg)
|
||||||
|
{
|
||||||
|
struct list *segh;
|
||||||
|
struct lv_segment *comp;
|
||||||
|
|
||||||
|
list_iterate(segh, &lv->segments) {
|
||||||
|
comp = list_item(segh, struct lv_segment);
|
||||||
|
|
||||||
|
if (comp->le > seg->le) {
|
||||||
|
list_add(&comp->list, &seg->list);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lv->le_count += seg->len;
|
||||||
|
list_add(&lv->segments, &seg->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _read_segment(struct pool *mem, struct volume_group *vg,
|
||||||
|
struct logical_volume *lv, struct config_node *sn,
|
||||||
|
struct hash_table *pv_hash)
|
||||||
|
{
|
||||||
|
unsigned int s;
|
||||||
|
uint32_t area_count = 0;
|
||||||
|
struct lv_segment *seg;
|
||||||
|
struct config_node *cn;
|
||||||
|
struct config_value *cv;
|
||||||
|
const char *seg_name = sn->key;
|
||||||
|
uint32_t start_extent, extent_count;
|
||||||
|
uint32_t chunk_size, extents_moved = 0u, seg_status = 0u;
|
||||||
|
const char *org_name, *cow_name;
|
||||||
|
struct logical_volume *org, *cow, *lv1;
|
||||||
|
segment_type_t segtype;
|
||||||
|
|
||||||
|
if (!(sn = sn->child)) {
|
||||||
|
log_error("Empty segment section.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_read_int32(sn, "start_extent", &start_extent)) {
|
||||||
|
log_error("Couldn't read 'start_extent' for segment '%s'.",
|
||||||
|
sn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_read_int32(sn, "extent_count", &extent_count)) {
|
||||||
|
log_error("Couldn't read 'extent_count' for segment '%s'.",
|
||||||
|
sn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
segtype = SEG_STRIPED; /* Default */
|
||||||
|
if ((cn = find_config_node(sn, "type"))) {
|
||||||
|
cv = cn->v;
|
||||||
|
if (!cv || !cv->v.str) {
|
||||||
|
log_error("Segment type must be a string.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
segtype = get_segtype_from_string(cv->v.str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (segtype == SEG_STRIPED) {
|
||||||
|
if (!_read_int32(sn, "stripe_count", &area_count)) {
|
||||||
|
log_error("Couldn't read 'stripe_count' for "
|
||||||
|
"segment '%s'.", sn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (segtype == SEG_MIRRORED) {
|
||||||
|
if (!_read_int32(sn, "mirror_count", &area_count)) {
|
||||||
|
log_error("Couldn't read 'mirror_count' for "
|
||||||
|
"segment '%s'.", sn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (find_config_node(sn, "extents_moved")) {
|
||||||
|
if (_read_uint32(sn, "extents_moved", &extents_moved))
|
||||||
|
seg_status |= PVMOVE;
|
||||||
|
else {
|
||||||
|
log_error("Couldn't read 'extents_moved' for "
|
||||||
|
"segment '%s'.", sn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(seg = alloc_lv_segment(mem, area_count))) {
|
||||||
|
log_error("Segment allocation failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
seg->lv = lv;
|
||||||
|
seg->le = start_extent;
|
||||||
|
seg->len = extent_count;
|
||||||
|
seg->area_len = extent_count;
|
||||||
|
seg->type = segtype;
|
||||||
|
seg->status = seg_status;
|
||||||
|
seg->extents_moved = extents_moved;
|
||||||
|
|
||||||
|
/* Optional tags */
|
||||||
|
if ((cn = find_config_node(sn, "tags")) &&
|
||||||
|
!(read_tags(mem, &seg->tags, cn->v))) {
|
||||||
|
log_error("Couldn't read tags for a segment of %s/%s.",
|
||||||
|
vg->name, lv->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (segtype) {
|
||||||
|
case SEG_SNAPSHOT:
|
||||||
|
lv->status |= SNAPSHOT;
|
||||||
|
|
||||||
|
if (!_read_uint32(sn, "chunk_size", &chunk_size)) {
|
||||||
|
log_error("Couldn't read chunk size for snapshot.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_suppress(1);
|
||||||
|
|
||||||
|
if (!(cow_name = find_config_str(sn, "cow_store", NULL))) {
|
||||||
|
log_suppress(0);
|
||||||
|
log_error("Snapshot cow storage not specified.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(org_name = find_config_str(sn, "origin", NULL))) {
|
||||||
|
log_suppress(0);
|
||||||
|
log_error("Snapshot origin not specified.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_suppress(0);
|
||||||
|
|
||||||
|
if (!(cow = find_lv(vg, cow_name))) {
|
||||||
|
log_error("Unknown logical volume specified for "
|
||||||
|
"snapshot cow store.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(org = find_lv(vg, org_name))) {
|
||||||
|
log_error("Unknown logical volume specified for "
|
||||||
|
"snapshot origin.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vg_add_snapshot(org, cow, 1, &lv->lvid.id[1], chunk_size)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEG_STRIPED:
|
||||||
|
if ((area_count != 1) &&
|
||||||
|
!_read_int32(sn, "stripe_size", &seg->stripe_size)) {
|
||||||
|
log_error("Couldn't read stripe_size for segment '%s'.",
|
||||||
|
sn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(cn = find_config_node(sn, "stripes"))) {
|
||||||
|
log_error("Couldn't find stripes array for segment "
|
||||||
|
"'%s'.", sn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
seg->area_len /= area_count;
|
||||||
|
|
||||||
|
case SEG_MIRRORED:
|
||||||
|
seg->area_count = area_count;
|
||||||
|
|
||||||
|
if (!seg->area_count) {
|
||||||
|
log_error("Zero areas not allowed for segment '%s'",
|
||||||
|
sn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((seg->type == SEG_MIRRORED) &&
|
||||||
|
!(cn = find_config_node(sn, "mirrors"))) {
|
||||||
|
log_error("Couldn't find mirrors array for segment "
|
||||||
|
"'%s'.", sn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cv = cn->v, s = 0; cv && s < seg->area_count;
|
||||||
|
s++, cv = cv->next) {
|
||||||
|
|
||||||
|
/* first we read the pv */
|
||||||
|
const char *bad = "Badly formed areas array for "
|
||||||
|
"segment '%s'.";
|
||||||
|
struct physical_volume *pv;
|
||||||
|
|
||||||
|
if (cv->type != CFG_STRING) {
|
||||||
|
log_error(bad, sn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cv->next) {
|
||||||
|
log_error(bad, sn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cv->next->type != CFG_INT) {
|
||||||
|
log_error(bad, sn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME Cope if LV not yet read in */
|
||||||
|
if ((pv = hash_lookup(pv_hash, cv->v.str))) {
|
||||||
|
seg->area[s].type = AREA_PV;
|
||||||
|
seg->area[s].u.pv.pv = pv;
|
||||||
|
seg->area[s].u.pv.pe = cv->next->v.i;
|
||||||
|
/*
|
||||||
|
* Adjust extent counts in the pv and vg.
|
||||||
|
*/
|
||||||
|
pv->pe_alloc_count += seg->area_len;
|
||||||
|
vg->free_count -= seg->area_len;
|
||||||
|
|
||||||
|
} else if ((lv1 = find_lv(vg, cv->v.str))) {
|
||||||
|
seg->area[s].type = AREA_LV;
|
||||||
|
seg->area[s].u.lv.lv = lv1;
|
||||||
|
seg->area[s].u.lv.le = cv->next->v.i;
|
||||||
|
} else {
|
||||||
|
log_error("Couldn't find volume '%s' "
|
||||||
|
"for segment '%s'.",
|
||||||
|
cv->v.str ? cv->v.str : "NULL",
|
||||||
|
seg_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cv = cv->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check we read the correct number of stripes.
|
||||||
|
*/
|
||||||
|
if (cv || (s < seg->area_count)) {
|
||||||
|
log_error("Incorrect number of areas in area array "
|
||||||
|
"for segment '%s'.", seg_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert into correct part of segment list.
|
||||||
|
*/
|
||||||
|
_insert_segment(lv, seg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _read_segments(struct pool *mem, struct volume_group *vg,
|
||||||
|
struct logical_volume *lv, struct config_node *lvn,
|
||||||
|
struct hash_table *pv_hash)
|
||||||
|
{
|
||||||
|
struct config_node *sn;
|
||||||
|
int count = 0, seg_count;
|
||||||
|
|
||||||
|
for (sn = lvn; sn; sn = sn->sib) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All sub-sections are assumed to be segments.
|
||||||
|
*/
|
||||||
|
if (!sn->v) {
|
||||||
|
if (!_read_segment(mem, vg, lv, sn, pv_hash)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
/* FIXME Remove this restriction */
|
||||||
|
if ((lv->status & SNAPSHOT) && count > 1) {
|
||||||
|
log_error("Only one segment permitted for snapshot");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_read_int32(lvn, "segment_count", &seg_count)) {
|
||||||
|
log_error("Couldn't read segment count for logical volume.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seg_count != count) {
|
||||||
|
log_error("segment_count and actual number of segments "
|
||||||
|
"disagree.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check there are no gaps or overlaps in the lv.
|
||||||
|
*/
|
||||||
|
if (!lv_check_segments(lv)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Merge segments in case someones been editing things by hand.
|
||||||
|
*/
|
||||||
|
if (!lv_merge_segments(lv)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _read_lvnames(struct format_instance *fid, struct pool *mem,
|
||||||
|
struct volume_group *vg, struct config_node *lvn,
|
||||||
|
struct config_node *vgn, struct hash_table *pv_hash)
|
||||||
|
{
|
||||||
|
struct logical_volume *lv;
|
||||||
|
struct lv_list *lvl;
|
||||||
|
struct config_node *cn;
|
||||||
|
|
||||||
|
if (!(lvl = pool_zalloc(mem, sizeof(*lvl))) ||
|
||||||
|
!(lvl->lv = pool_zalloc(mem, sizeof(*lvl->lv)))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lv = lvl->lv;
|
||||||
|
|
||||||
|
if (!(lv->name = pool_strdup(mem, lvn->key))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(lvn = lvn->child)) {
|
||||||
|
log_error("Empty logical volume section.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(cn = find_config_node(lvn, "status"))) {
|
||||||
|
log_error("Couldn't find status flags for logical volume.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(read_flags(&lv->status, LV_FLAGS, cn->v))) {
|
||||||
|
log_error("Couldn't read status flags for logical volume.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lv->alloc = ALLOC_DEFAULT;
|
||||||
|
if ((cn = find_config_node(lvn, "allocation_policy"))) {
|
||||||
|
struct config_value *cv = cn->v;
|
||||||
|
if (!cv || !cv->v.str) {
|
||||||
|
log_error("allocation_policy must be a string.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lv->alloc = get_alloc_from_string(cv->v.str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read_ahead defaults to 0 */
|
||||||
|
if (!_read_int32(lvn, "read_ahead", &lv->read_ahead))
|
||||||
|
lv->read_ahead = 0;
|
||||||
|
|
||||||
|
list_init(&lv->segments);
|
||||||
|
list_init(&lv->tags);
|
||||||
|
|
||||||
|
/* Optional tags */
|
||||||
|
if ((cn = find_config_node(lvn, "tags")) &&
|
||||||
|
!(read_tags(mem, &lv->tags, cn->v))) {
|
||||||
|
log_error("Couldn't read tags for logical volume %s/%s.",
|
||||||
|
vg->name, lv->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lv->vg = vg;
|
||||||
|
vg->lv_count++;
|
||||||
|
list_add(&vg->lvs, &lvl->list);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _read_lvsegs(struct format_instance *fid, struct pool *mem,
|
||||||
|
struct volume_group *vg, struct config_node *lvn,
|
||||||
|
struct config_node *vgn, struct hash_table *pv_hash)
|
||||||
|
{
|
||||||
|
struct logical_volume *lv;
|
||||||
|
struct lv_list *lvl;
|
||||||
|
|
||||||
|
if (!(lvl = find_lv_in_vg(vg, lvn->key))) {
|
||||||
|
log_error("Lost logical volume reference %s", lvn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lv = lvl->lv;
|
||||||
|
|
||||||
|
if (!(lvn = lvn->child)) {
|
||||||
|
log_error("Empty logical volume section.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: read full lvid */
|
||||||
|
if (!_read_id(&lv->lvid.id[1], lvn, "id")) {
|
||||||
|
log_error("Couldn't read uuid for logical volume %s.",
|
||||||
|
lv->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&lv->lvid.id[0], &lv->vg->id, sizeof(lv->lvid.id[0]));
|
||||||
|
|
||||||
|
if (!_read_segments(mem, vg, lv, lvn, pv_hash)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size;
|
||||||
|
|
||||||
|
/* Skip this for now for snapshots */
|
||||||
|
if (!(lv->status & SNAPSHOT)) {
|
||||||
|
lv->minor = -1;
|
||||||
|
if ((lv->status & FIXED_MINOR) &&
|
||||||
|
!_read_int32(lvn, "minor", &lv->minor)) {
|
||||||
|
log_error("Couldn't read minor number for logical "
|
||||||
|
"volume %s.", lv->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
lv->major = -1;
|
||||||
|
if ((lv->status & FIXED_MINOR) &&
|
||||||
|
!_read_int32(lvn, "major", &lv->major)) {
|
||||||
|
log_error("Couldn't read major number for logical "
|
||||||
|
"volume %s.", lv->name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vg->lv_count--;
|
||||||
|
list_del(&lvl->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _read_sections(struct format_instance *fid,
|
||||||
|
const char *section, section_fn fn,
|
||||||
|
struct pool *mem,
|
||||||
|
struct volume_group *vg, struct config_node *vgn,
|
||||||
|
struct hash_table *pv_hash, int optional)
|
||||||
|
{
|
||||||
|
struct config_node *n;
|
||||||
|
|
||||||
|
if (!(n = find_config_node(vgn, section))) {
|
||||||
|
if (!optional) {
|
||||||
|
log_error("Couldn't find section '%s'.", section);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (n = n->child; n; n = n->sib) {
|
||||||
|
if (!fn(fid, mem, vg, n, vgn, pv_hash)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct volume_group *_read_vg(struct format_instance *fid,
|
||||||
|
struct config_tree *cft)
|
||||||
|
{
|
||||||
|
struct config_node *vgn, *cn;
|
||||||
|
struct volume_group *vg;
|
||||||
|
struct hash_table *pv_hash = NULL;
|
||||||
|
struct pool *mem = fid->fmt->cmd->mem;
|
||||||
|
|
||||||
|
/* skip any top-level values */
|
||||||
|
for (vgn = cft->root; (vgn && vgn->v); vgn = vgn->sib) ;
|
||||||
|
|
||||||
|
if (!vgn) {
|
||||||
|
log_error("Couldn't find volume group in file.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(vg = pool_zalloc(mem, sizeof(*vg)))) {
|
||||||
|
stack;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
vg->cmd = fid->fmt->cmd;
|
||||||
|
|
||||||
|
/* FIXME Determine format type from file contents */
|
||||||
|
/* eg Set to instance of fmt1 here if reading a format1 backup? */
|
||||||
|
vg->fid = fid;
|
||||||
|
|
||||||
|
if (!(vg->name = pool_strdup(mem, vgn->key))) {
|
||||||
|
stack;
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(vg->system_id = pool_zalloc(mem, NAME_LEN))) {
|
||||||
|
stack;
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
vgn = vgn->child;
|
||||||
|
|
||||||
|
if ((cn = find_config_node(vgn, "system_id")) && cn->v) {
|
||||||
|
if (!cn->v->v.str) {
|
||||||
|
log_error("system_id must be a string");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
strncpy(vg->system_id, cn->v->v.str, NAME_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_read_id(&vg->id, vgn, "id")) {
|
||||||
|
log_error("Couldn't read uuid for volume group %s.", vg->name);
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_read_int32(vgn, "seqno", &vg->seqno)) {
|
||||||
|
log_error("Couldn't read 'seqno' for volume group %s.",
|
||||||
|
vg->name);
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(cn = find_config_node(vgn, "status"))) {
|
||||||
|
log_error("Couldn't find status flags for volume group %s.",
|
||||||
|
vg->name);
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(read_flags(&vg->status, VG_FLAGS, cn->v))) {
|
||||||
|
log_error("Couldn't read status flags for volume group %s.",
|
||||||
|
vg->name);
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_read_int32(vgn, "extent_size", &vg->extent_size)) {
|
||||||
|
log_error("Couldn't read extent size for volume group %s.",
|
||||||
|
vg->name);
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 'extent_count' and 'free_count' get filled in
|
||||||
|
* implicitly when reading in the pv's and lv's.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!_read_int32(vgn, "max_lv", &vg->max_lv)) {
|
||||||
|
log_error("Couldn't read 'max_lv' for volume group %s.",
|
||||||
|
vg->name);
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_read_int32(vgn, "max_pv", &vg->max_pv)) {
|
||||||
|
log_error("Couldn't read 'max_pv' for volume group %s.",
|
||||||
|
vg->name);
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The pv hash memoises the pv section names -> pv
|
||||||
|
* structures.
|
||||||
|
*/
|
||||||
|
if (!(pv_hash = hash_create(32))) {
|
||||||
|
log_error("Couldn't create hash table.");
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_init(&vg->pvs);
|
||||||
|
if (!_read_sections(fid, "physical_volumes", _read_pv, mem, vg,
|
||||||
|
vgn, pv_hash, 0)) {
|
||||||
|
log_error("Couldn't find all physical volumes for volume "
|
||||||
|
"group %s.", vg->name);
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_init(&vg->lvs);
|
||||||
|
list_init(&vg->snapshots);
|
||||||
|
list_init(&vg->tags);
|
||||||
|
|
||||||
|
/* Optional tags */
|
||||||
|
if ((cn = find_config_node(vgn, "tags")) &&
|
||||||
|
!(read_tags(mem, &vg->tags, cn->v))) {
|
||||||
|
log_error("Couldn't read tags for volume group %s.", vg->name);
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_read_sections(fid, "logical_volumes", _read_lvnames, mem, vg,
|
||||||
|
vgn, pv_hash, 1)) {
|
||||||
|
log_error("Couldn't read all logical volume names for volume "
|
||||||
|
"group %s.", vg->name);
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_read_sections(fid, "logical_volumes", _read_lvsegs, mem, vg,
|
||||||
|
vgn, pv_hash, 1)) {
|
||||||
|
log_error("Couldn't read all logical volumes for "
|
||||||
|
"volume group %s.", vg->name);
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_destroy(pv_hash);
|
||||||
|
|
||||||
|
if (vg->status & PARTIAL_VG) {
|
||||||
|
vg->status &= ~LVM_WRITE;
|
||||||
|
vg->status |= LVM_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finished.
|
||||||
|
*/
|
||||||
|
return vg;
|
||||||
|
|
||||||
|
bad:
|
||||||
|
if (pv_hash)
|
||||||
|
hash_destroy(pv_hash);
|
||||||
|
|
||||||
|
pool_free(mem, vg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _read_desc(struct pool *mem,
|
||||||
|
struct config_tree *cft, time_t *when, char **desc)
|
||||||
|
{
|
||||||
|
const char *d;
|
||||||
|
unsigned int u = 0u;
|
||||||
|
|
||||||
|
log_suppress(1);
|
||||||
|
d = find_config_str(cft->root, "description", "");
|
||||||
|
log_suppress(0);
|
||||||
|
*desc = pool_strdup(mem, d);
|
||||||
|
|
||||||
|
get_config_uint32(cft->root, "creation_time", &u);
|
||||||
|
*when = u;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct text_vg_version_ops _vsn1_ops = {
|
||||||
|
check_version:_check_version,
|
||||||
|
read_vg:_read_vg,
|
||||||
|
read_desc:_read_desc
|
||||||
|
};
|
||||||
|
|
||||||
|
struct text_vg_version_ops *text_vg_vsn1_init(void)
|
||||||
|
{
|
||||||
|
return &_vsn1_ops;
|
||||||
|
};
|
||||||
85
lib/format_text/layout.h
Normal file
85
lib/format_text/layout.h
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LVM_TEXT_LAYOUT_H
|
||||||
|
#define _LVM_TEXT_LAYOUT_H
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "lvm-types.h"
|
||||||
|
#include "metadata.h"
|
||||||
|
#include "uuid.h"
|
||||||
|
|
||||||
|
/* On disk */
|
||||||
|
struct disk_locn {
|
||||||
|
uint64_t offset; /* Offset in bytes to start sector */
|
||||||
|
uint64_t size; /* Bytes */
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
/* Data areas (holding PEs) */
|
||||||
|
struct data_area_list {
|
||||||
|
struct list list;
|
||||||
|
struct disk_locn disk_locn;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Fields with the suffix _xl should be xlate'd wherever they appear */
|
||||||
|
/* On disk */
|
||||||
|
struct pv_header {
|
||||||
|
uint8_t pv_uuid[ID_LEN];
|
||||||
|
uint64_t device_size_xl; /* Bytes */
|
||||||
|
|
||||||
|
/* NULL-terminated list of data areas followed by */
|
||||||
|
/* NULL-terminated list of metadata area headers */
|
||||||
|
struct disk_locn disk_areas_xl[0]; /* Two lists */
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
/* On disk */
|
||||||
|
struct raw_locn {
|
||||||
|
uint64_t offset; /* Offset in bytes to start sector */
|
||||||
|
uint64_t size; /* Bytes */
|
||||||
|
uint32_t checksum;
|
||||||
|
uint32_t filler;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
/* On disk */
|
||||||
|
/* Structure size limited to one sector */
|
||||||
|
struct mda_header {
|
||||||
|
uint32_t checksum_xl; /* Checksum of rest of mda_header */
|
||||||
|
uint8_t magic[16]; /* To aid scans for metadata */
|
||||||
|
uint32_t version;
|
||||||
|
uint64_t start; /* Absolute start byte of mda_header */
|
||||||
|
uint64_t size; /* Size of metadata area */
|
||||||
|
|
||||||
|
struct raw_locn raw_locns[0]; /* NULL-terminated list */
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct mda_lists {
|
||||||
|
struct list dirs;
|
||||||
|
struct list raws;
|
||||||
|
struct metadata_area_ops *file_ops;
|
||||||
|
struct metadata_area_ops *raw_ops;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mda_context {
|
||||||
|
struct device_area area;
|
||||||
|
struct raw_locn rlocn; /* Store inbetween write and commit */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* FIXME Convert this at runtime */
|
||||||
|
#define FMTT_MAGIC "\040\114\126\115\062\040\170\133\065\101\045\162\060\116\052\076"
|
||||||
|
#define FMTT_VERSION 1
|
||||||
|
#define MDA_HEADER_SIZE 512
|
||||||
|
#define LVM2_LABEL "LVM2 001"
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
# An example volume group
|
|
||||||
|
|
||||||
# YYYY-MM-DD HH:MM:SS
|
|
||||||
output_date = "2001-12-11 11:35:12"
|
|
||||||
|
|
||||||
sample_volume_group {
|
|
||||||
|
|
||||||
id = "ksjdlfksjldskjlsk"
|
|
||||||
status = ["ACTIVE"]
|
|
||||||
|
|
||||||
extent_size = 8192 # 4 Megabytes
|
|
||||||
|
|
||||||
max_lv = 99
|
|
||||||
max_pv = 255
|
|
||||||
|
|
||||||
physical_volumes {
|
|
||||||
|
|
||||||
pv1 {
|
|
||||||
id = "lksjdflksdlsk"
|
|
||||||
device = "/dev/hda1" # Hint only
|
|
||||||
|
|
||||||
status = ["ALLOCATABLE"]
|
|
||||||
pe_start = 8192
|
|
||||||
pe_count = 2048 # 8 Gigabytes
|
|
||||||
}
|
|
||||||
|
|
||||||
pv2 {
|
|
||||||
id = "lksjdflksdlsk"
|
|
||||||
device = "/dev/hda2" # Hint only
|
|
||||||
|
|
||||||
status = ["ALLOCATABLE"]
|
|
||||||
pe_start = 8192
|
|
||||||
pe_count = 1024 # 4 Gigabytes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logical_volumes {
|
|
||||||
|
|
||||||
music {
|
|
||||||
status = ["ACTIVE"]
|
|
||||||
read_ahead = 1024
|
|
||||||
|
|
||||||
segment_count = 2
|
|
||||||
|
|
||||||
segment1 {
|
|
||||||
start_extent = 0
|
|
||||||
extent_count = 1024 # 4 Gigabytes
|
|
||||||
stripes = 1
|
|
||||||
|
|
||||||
areas = [
|
|
||||||
"pv1", 0
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
segment2 {
|
|
||||||
start_extent = 1024
|
|
||||||
extent_count = 2048 # 8 Gigabytes
|
|
||||||
stripes = 2
|
|
||||||
stripe_size = 32 # 16 Kilobytes
|
|
||||||
|
|
||||||
areas = [
|
|
||||||
"pv1", 1024,
|
|
||||||
"pv2", 0
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
76
lib/format_text/tags.c
Normal file
76
lib/format_text/tags.c
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
|
#include "metadata.h"
|
||||||
|
#include "import-export.h"
|
||||||
|
#include "pool.h"
|
||||||
|
#include "str_list.h"
|
||||||
|
#include "lvm-string.h"
|
||||||
|
|
||||||
|
int print_tags(struct list *tags, char *buffer, size_t size)
|
||||||
|
{
|
||||||
|
struct str_list *sl;
|
||||||
|
int first = 1;
|
||||||
|
|
||||||
|
if (!emit_to_buffer(&buffer, &size, "[")) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_iterate_items(sl, tags) {
|
||||||
|
if (!first) {
|
||||||
|
if (!emit_to_buffer(&buffer, &size, ", ")) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
first = 0;
|
||||||
|
|
||||||
|
if (!emit_to_buffer(&buffer, &size, "\"%s\"", sl->str)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!emit_to_buffer(&buffer, &size, "]")) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_tags(struct pool *mem, struct list *tags, struct config_value *cv)
|
||||||
|
{
|
||||||
|
if (cv->type == CFG_EMPTY_ARRAY)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
while (cv) {
|
||||||
|
if (cv->type != CFG_STRING) {
|
||||||
|
log_error("Found a tag that is not a string");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!str_list_add(mem, tags, pool_strdup(mem, cv->v.str))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cv = cv->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
289
lib/format_text/text_label.c
Normal file
289
lib/format_text/text_label.c
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
|
#include "format-text.h"
|
||||||
|
#include "layout.h"
|
||||||
|
#include "label.h"
|
||||||
|
#include "xlate.h"
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
static int _can_handle(struct labeller *l, char *buf, uint64_t sector)
|
||||||
|
{
|
||||||
|
struct label_header *lh = (struct label_header *) buf;
|
||||||
|
|
||||||
|
if (!strncmp(lh->type, LVM2_LABEL, sizeof(lh->type)))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _write(struct label *label, char *buf)
|
||||||
|
{
|
||||||
|
struct label_header *lh = (struct label_header *) buf;
|
||||||
|
struct pv_header *pvhdr;
|
||||||
|
struct lvmcache_info *info;
|
||||||
|
struct disk_locn *pvh_dlocn_xl;
|
||||||
|
struct list *mdash, *dash;
|
||||||
|
struct metadata_area *mda;
|
||||||
|
struct mda_context *mdac;
|
||||||
|
struct data_area_list *da;
|
||||||
|
|
||||||
|
/* FIXME Move to where label is created */
|
||||||
|
strncpy(label->type, LVM2_LABEL, sizeof(label->type));
|
||||||
|
|
||||||
|
strncpy(lh->type, label->type, sizeof(label->type));
|
||||||
|
|
||||||
|
pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl));
|
||||||
|
info = (struct lvmcache_info *) label->info;
|
||||||
|
pvhdr->device_size_xl = xlate64(info->device_size);
|
||||||
|
memcpy(pvhdr->pv_uuid, &info->dev->pvid, sizeof(struct id));
|
||||||
|
|
||||||
|
pvh_dlocn_xl = &pvhdr->disk_areas_xl[0];
|
||||||
|
|
||||||
|
/* List of data areas (holding PEs) */
|
||||||
|
list_iterate(dash, &info->das) {
|
||||||
|
da = list_item(dash, struct data_area_list);
|
||||||
|
|
||||||
|
pvh_dlocn_xl->offset = xlate64(da->disk_locn.offset);
|
||||||
|
pvh_dlocn_xl->size = xlate64(da->disk_locn.size);
|
||||||
|
pvh_dlocn_xl++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NULL-termination */
|
||||||
|
pvh_dlocn_xl->offset = xlate64(UINT64_C(0));
|
||||||
|
pvh_dlocn_xl->size = xlate64(UINT64_C(0));
|
||||||
|
pvh_dlocn_xl++;
|
||||||
|
|
||||||
|
/* List of metadata area header locations */
|
||||||
|
list_iterate(mdash, &info->mdas) {
|
||||||
|
mda = list_item(mdash, struct metadata_area);
|
||||||
|
mdac = (struct mda_context *) mda->metadata_locn;
|
||||||
|
|
||||||
|
if (mdac->area.dev != info->dev)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pvh_dlocn_xl->offset = xlate64(mdac->area.start);
|
||||||
|
pvh_dlocn_xl->size = xlate64(mdac->area.size);
|
||||||
|
pvh_dlocn_xl++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NULL-termination */
|
||||||
|
pvh_dlocn_xl->offset = xlate64(UINT64_C(0));
|
||||||
|
pvh_dlocn_xl->size = xlate64(UINT64_C(0));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int add_da(const struct format_type *fmt, struct pool *mem, struct list *das,
|
||||||
|
uint64_t start, uint64_t size)
|
||||||
|
{
|
||||||
|
struct data_area_list *dal;
|
||||||
|
|
||||||
|
if (!mem) {
|
||||||
|
if (!(dal = dbg_malloc(sizeof(*dal)))) {
|
||||||
|
log_error("struct data_area_list allocation failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!(dal = pool_alloc(mem, sizeof(*dal)))) {
|
||||||
|
log_error("struct data_area_list allocation failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dal->disk_locn.offset = start;
|
||||||
|
dal->disk_locn.size = size;
|
||||||
|
|
||||||
|
list_add(das, &dal->list);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void del_das(struct list *das)
|
||||||
|
{
|
||||||
|
struct list *dah, *tmp;
|
||||||
|
struct data_area_list *da;
|
||||||
|
|
||||||
|
list_iterate_safe(dah, tmp, das) {
|
||||||
|
da = list_item(dah, struct data_area_list);
|
||||||
|
list_del(&da->list);
|
||||||
|
dbg_free(da);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int add_mda(const struct format_type *fmt, struct pool *mem, struct list *mdas,
|
||||||
|
struct device *dev, uint64_t start, uint64_t size)
|
||||||
|
{
|
||||||
|
/* FIXME List size restricted by pv_header SECTOR_SIZE */
|
||||||
|
struct metadata_area *mdal;
|
||||||
|
struct mda_lists *mda_lists = (struct mda_lists *) fmt->private;
|
||||||
|
struct mda_context *mdac;
|
||||||
|
|
||||||
|
if (!mem) {
|
||||||
|
if (!(mdal = dbg_malloc(sizeof(struct metadata_area)))) {
|
||||||
|
log_error("struct mda_list allocation failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(mdac = dbg_malloc(sizeof(struct mda_context)))) {
|
||||||
|
log_error("struct mda_context allocation failed");
|
||||||
|
dbg_free(mdal);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!(mdal = pool_alloc(mem, sizeof(struct metadata_area)))) {
|
||||||
|
log_error("struct mda_list allocation failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(mdac = pool_alloc(mem, sizeof(struct mda_context)))) {
|
||||||
|
log_error("struct mda_context allocation failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mdal->ops = mda_lists->raw_ops;
|
||||||
|
mdal->metadata_locn = mdac;
|
||||||
|
|
||||||
|
mdac->area.dev = dev;
|
||||||
|
mdac->area.start = start;
|
||||||
|
mdac->area.size = size;
|
||||||
|
memset(&mdac->rlocn, 0, sizeof(mdac->rlocn));
|
||||||
|
|
||||||
|
list_add(mdas, &mdal->list);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void del_mdas(struct list *mdas)
|
||||||
|
{
|
||||||
|
struct list *mdah, *tmp;
|
||||||
|
struct metadata_area *mda;
|
||||||
|
|
||||||
|
list_iterate_safe(mdah, tmp, mdas) {
|
||||||
|
mda = list_item(mdah, struct metadata_area);
|
||||||
|
dbg_free(mda->metadata_locn);
|
||||||
|
list_del(&mda->list);
|
||||||
|
dbg_free(mda);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _initialise_label(struct labeller *l, struct label *label)
|
||||||
|
{
|
||||||
|
strncpy(label->type, LVM2_LABEL, sizeof(label->type));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||||
|
struct label **label)
|
||||||
|
{
|
||||||
|
struct label_header *lh = (struct label_header *) buf;
|
||||||
|
struct pv_header *pvhdr;
|
||||||
|
struct lvmcache_info *info;
|
||||||
|
struct disk_locn *dlocn_xl;
|
||||||
|
uint64_t offset;
|
||||||
|
struct list *mdah;
|
||||||
|
struct metadata_area *mda;
|
||||||
|
char vgnamebuf[NAME_LEN + 2];
|
||||||
|
struct mda_context *mdac;
|
||||||
|
|
||||||
|
pvhdr = (struct pv_header *) ((void *) buf + xlate32(lh->offset_xl));
|
||||||
|
|
||||||
|
if (!(info = lvmcache_add(l, pvhdr->pv_uuid, dev, NULL, NULL)))
|
||||||
|
return 0;
|
||||||
|
*label = info->label;
|
||||||
|
|
||||||
|
info->device_size = xlate64(pvhdr->device_size_xl);
|
||||||
|
|
||||||
|
if (info->das.n)
|
||||||
|
del_das(&info->das);
|
||||||
|
list_init(&info->das);
|
||||||
|
|
||||||
|
if (info->mdas.n)
|
||||||
|
del_mdas(&info->mdas);
|
||||||
|
list_init(&info->mdas);
|
||||||
|
|
||||||
|
/* Data areas holding the PEs */
|
||||||
|
dlocn_xl = pvhdr->disk_areas_xl;
|
||||||
|
while ((offset = xlate64(dlocn_xl->offset))) {
|
||||||
|
add_da(info->fmt, NULL, &info->das, offset,
|
||||||
|
xlate64(dlocn_xl->size));
|
||||||
|
dlocn_xl++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Metadata area headers */
|
||||||
|
dlocn_xl++;
|
||||||
|
while ((offset = xlate64(dlocn_xl->offset))) {
|
||||||
|
add_mda(info->fmt, NULL, &info->mdas, dev, offset,
|
||||||
|
xlate64(dlocn_xl->size));
|
||||||
|
dlocn_xl++;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_iterate(mdah, &info->mdas) {
|
||||||
|
mda = list_item(mdah, struct metadata_area);
|
||||||
|
mdac = (struct mda_context *) mda->metadata_locn;
|
||||||
|
if (vgname_from_mda(info->fmt, &mdac->area, vgnamebuf,
|
||||||
|
sizeof(vgnamebuf))) {
|
||||||
|
lvmcache_update_vgname(info, vgnamebuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info->status &= ~CACHE_INVALID;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _destroy_label(struct labeller *l, struct label *label)
|
||||||
|
{
|
||||||
|
struct lvmcache_info *info = (struct lvmcache_info *) label->info;
|
||||||
|
|
||||||
|
if (info->mdas.n)
|
||||||
|
del_mdas(&info->mdas);
|
||||||
|
if (info->das.n)
|
||||||
|
del_das(&info->das);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _destroy(struct labeller *l)
|
||||||
|
{
|
||||||
|
dbg_free(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct label_ops _text_ops = {
|
||||||
|
can_handle:_can_handle,
|
||||||
|
write:_write,
|
||||||
|
read:_read,
|
||||||
|
verify:_can_handle,
|
||||||
|
initialise_label:_initialise_label,
|
||||||
|
destroy_label:_destroy_label,
|
||||||
|
destroy:_destroy
|
||||||
|
};
|
||||||
|
|
||||||
|
struct labeller *text_labeller_create(const struct format_type *fmt)
|
||||||
|
{
|
||||||
|
struct labeller *l;
|
||||||
|
|
||||||
|
if (!(l = dbg_malloc(sizeof(*l)))) {
|
||||||
|
log_err("Couldn't allocate labeller object.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
l->ops = &_text_ops;
|
||||||
|
l->private = (const void *) fmt;
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
@@ -1,13 +1,30 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2002 Sistina Software
|
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
#include "label.h"
|
#include "label.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "dbg_malloc.h"
|
#include "crc.h"
|
||||||
#include "log.h"
|
#include "xlate.h"
|
||||||
|
#include "lvmcache.h"
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/* FIXME Allow for larger labels? Restricted to single sector currently */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal labeller struct.
|
* Internal labeller struct.
|
||||||
@@ -58,6 +75,7 @@ void label_exit(void)
|
|||||||
for (c = _labellers.n; c != &_labellers; c = n) {
|
for (c = _labellers.n; c != &_labellers; c = n) {
|
||||||
n = c->n;
|
n = c->n;
|
||||||
li = list_item(c, struct labeller_i);
|
li = list_item(c, struct labeller_i);
|
||||||
|
li->l->ops->destroy(li->l);
|
||||||
_free_li(li);
|
_free_li(li);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,64 +107,264 @@ struct labeller *label_get_handler(const char *name)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct labeller *_find_labeller(struct device *dev)
|
static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||||
|
uint64_t *label_sector)
|
||||||
{
|
{
|
||||||
struct list *lih;
|
struct list *lih;
|
||||||
struct labeller_i *li;
|
struct labeller_i *li;
|
||||||
|
struct labeller *r = NULL;
|
||||||
|
struct label_header *lh;
|
||||||
|
uint64_t sector;
|
||||||
|
int found = 0;
|
||||||
|
char readbuf[LABEL_SCAN_SIZE];
|
||||||
|
|
||||||
list_iterate(lih, &_labellers) {
|
if (!dev_open(dev)) {
|
||||||
li = list_item(lih, struct labeller_i);
|
stack;
|
||||||
if (li->l->ops->can_handle(li->l, dev))
|
return NULL;
|
||||||
return li->l;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug("No label on device '%s'.", dev_name(dev));
|
if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) {
|
||||||
return NULL;
|
log_debug("%s: Failed to read label area", dev_name(dev));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scan first few sectors for a valid label */
|
||||||
|
for (sector = 0; sector < LABEL_SCAN_SECTORS;
|
||||||
|
sector += LABEL_SIZE >> SECTOR_SHIFT) {
|
||||||
|
lh = (struct label_header *) (readbuf +
|
||||||
|
(sector << SECTOR_SHIFT));
|
||||||
|
|
||||||
|
if (!strncmp(lh->id, LABEL_ID, sizeof(lh->id))) {
|
||||||
|
if (found) {
|
||||||
|
log_error("Ignoring additional label on %s at "
|
||||||
|
"sector %" PRIu64, dev_name(dev),
|
||||||
|
sector);
|
||||||
|
}
|
||||||
|
if (xlate64(lh->sector_xl) != sector) {
|
||||||
|
log_info("%s: Label for sector %" PRIu64
|
||||||
|
" found at sector %" PRIu64
|
||||||
|
" - ignoring", dev_name(dev),
|
||||||
|
xlate64(lh->sector_xl), sector);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (calc_crc(INITIAL_CRC, &lh->offset_xl, LABEL_SIZE -
|
||||||
|
((void *) &lh->offset_xl - (void *) lh)) !=
|
||||||
|
xlate32(lh->crc_xl)) {
|
||||||
|
log_info("Label checksum incorrect on %s - "
|
||||||
|
"ignoring", dev_name(dev));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (found)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_iterate(lih, &_labellers) {
|
||||||
|
li = list_item(lih, struct labeller_i);
|
||||||
|
if (li->l->ops->can_handle(li->l, (char *) lh, sector)) {
|
||||||
|
log_very_verbose("%s: %s label detected",
|
||||||
|
dev_name(dev), li->name);
|
||||||
|
if (found) {
|
||||||
|
log_error("Ignoring additional label "
|
||||||
|
"on %s at sector %" PRIu64,
|
||||||
|
dev_name(dev), sector);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
r = li->l;
|
||||||
|
memcpy(buf, lh, LABEL_SIZE);
|
||||||
|
if (label_sector)
|
||||||
|
*label_sector = sector;
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
log_very_verbose("%s: No label detected", dev_name(dev));
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (!dev_close(dev))
|
||||||
|
stack;
|
||||||
|
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FIXME Also wipe associated metadata area headers? */
|
||||||
int label_remove(struct device *dev)
|
int label_remove(struct device *dev)
|
||||||
{
|
{
|
||||||
struct labeller *l;
|
char buf[LABEL_SIZE];
|
||||||
|
char readbuf[LABEL_SCAN_SIZE];
|
||||||
|
int r = 1;
|
||||||
|
uint64_t sector;
|
||||||
|
int wipe;
|
||||||
|
struct list *lih;
|
||||||
|
struct labeller_i *li;
|
||||||
|
struct label_header *lh;
|
||||||
|
|
||||||
if (!(l = _find_labeller(dev))) {
|
memset(buf, 0, LABEL_SIZE);
|
||||||
|
|
||||||
|
log_very_verbose("Scanning for labels to wipe from %s", dev_name(dev));
|
||||||
|
|
||||||
|
if (!dev_open(dev)) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return l->ops->remove(l, dev);
|
/*
|
||||||
}
|
* We flush the device just in case someone is stupid
|
||||||
|
* enough to be trying to import an open pv into lvm.
|
||||||
|
*/
|
||||||
|
dev_flush(dev);
|
||||||
|
|
||||||
int label_read(struct device *dev, struct label **result)
|
if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) {
|
||||||
{
|
log_debug("%s: Failed to read label area", dev_name(dev));
|
||||||
int r;
|
goto out;
|
||||||
struct list *lih;
|
}
|
||||||
struct labeller_i *li;
|
|
||||||
|
|
||||||
list_iterate(lih, &_labellers) {
|
/* Scan first few sectors for anything looking like a label */
|
||||||
li = list_item(lih, struct labeller_i);
|
for (sector = 0; sector < LABEL_SCAN_SECTORS;
|
||||||
if ((r = li->l->ops->read(li->l, dev, result))) {
|
sector += LABEL_SIZE >> SECTOR_SHIFT) {
|
||||||
(*result)->labeller = li->l;
|
lh = (struct label_header *) (readbuf +
|
||||||
return r;
|
(sector << SECTOR_SHIFT));
|
||||||
|
|
||||||
|
wipe = 0;
|
||||||
|
|
||||||
|
if (!strncmp(lh->id, LABEL_ID, sizeof(lh->id))) {
|
||||||
|
if (xlate64(lh->sector_xl) == sector)
|
||||||
|
wipe = 1;
|
||||||
|
} else {
|
||||||
|
list_iterate(lih, &_labellers) {
|
||||||
|
li = list_item(lih, struct labeller_i);
|
||||||
|
if (li->l->ops->can_handle(li->l, (char *) lh,
|
||||||
|
sector)) {
|
||||||
|
wipe = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wipe) {
|
||||||
|
log_info("%s: Wiping label at sector %" PRIu64,
|
||||||
|
dev_name(dev), sector);
|
||||||
|
if (!dev_write(dev, sector << SECTOR_SHIFT, LABEL_SIZE,
|
||||||
|
buf)) {
|
||||||
|
log_error("Failed to remove label from %s at "
|
||||||
|
"sector %" PRIu64, dev_name(dev),
|
||||||
|
sector);
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug("No label on device '%s'.", dev_name(dev));
|
out:
|
||||||
return 0;
|
if (!dev_close(dev))
|
||||||
|
stack;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME Avoid repeated re-reading if cache lock held */
|
||||||
|
int label_read(struct device *dev, struct label **result)
|
||||||
|
{
|
||||||
|
char buf[LABEL_SIZE];
|
||||||
|
struct labeller *l;
|
||||||
|
uint64_t sector;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!(l = _find_labeller(dev, buf, §or))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((r = l->ops->read(l, dev, buf, result)) && result && *result)
|
||||||
|
(*result)->sector = sector;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Caller may need to use label_get_handler to create label struct! */
|
||||||
|
int label_write(struct device *dev, struct label *label)
|
||||||
|
{
|
||||||
|
char buf[LABEL_SIZE];
|
||||||
|
struct label_header *lh = (struct label_header *) buf;
|
||||||
|
int r = 1;
|
||||||
|
|
||||||
|
if (!label->labeller->ops->write) {
|
||||||
|
log_err("Label handler does not support label writes");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((LABEL_SIZE + (label->sector << SECTOR_SHIFT)) > LABEL_SCAN_SIZE) {
|
||||||
|
log_error("Label sector %" PRIu64 " beyond range (%ld)",
|
||||||
|
label->sector, LABEL_SCAN_SECTORS);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(buf, 0, LABEL_SIZE);
|
||||||
|
|
||||||
|
strncpy(lh->id, LABEL_ID, sizeof(lh->id));
|
||||||
|
lh->sector_xl = xlate64(label->sector);
|
||||||
|
lh->offset_xl = xlate32(sizeof(*lh));
|
||||||
|
|
||||||
|
if (!label->labeller->ops->write(label, buf)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lh->crc_xl = xlate32(calc_crc(INITIAL_CRC, &lh->offset_xl, LABEL_SIZE -
|
||||||
|
((void *) &lh->offset_xl - (void *) lh)));
|
||||||
|
|
||||||
|
if (!dev_open(dev)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("%s: Writing label to sector %" PRIu64, dev_name(dev),
|
||||||
|
label->sector);
|
||||||
|
if (!dev_write(dev, label->sector << SECTOR_SHIFT, LABEL_SIZE, buf)) {
|
||||||
|
log_debug("Failed to write label to %s", dev_name(dev));
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dev_close(dev))
|
||||||
|
stack;
|
||||||
|
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int label_verify(struct device *dev)
|
int label_verify(struct device *dev)
|
||||||
{
|
{
|
||||||
struct labeller *l;
|
struct labeller *l;
|
||||||
|
char buf[LABEL_SIZE];
|
||||||
|
uint64_t sector;
|
||||||
|
|
||||||
if (!(l = _find_labeller(dev))) {
|
if (!(l = _find_labeller(dev, buf, §or))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return l->ops->verify(l, dev);
|
return ((l->ops->verify) ? l->ops->verify(l, buf, sector) : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void label_destroy(struct label *lab)
|
void label_destroy(struct label *label)
|
||||||
{
|
{
|
||||||
lab->labeller->ops->destroy_label(lab->labeller, lab);
|
label->labeller->ops->destroy_label(label->labeller, label);
|
||||||
|
dbg_free(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct label *label_create(struct labeller *labeller)
|
||||||
|
{
|
||||||
|
struct label *label;
|
||||||
|
|
||||||
|
if (!(label = dbg_malloc(sizeof(*label)))) {
|
||||||
|
log_error("label allocaction failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(label, 0, sizeof(*label));
|
||||||
|
|
||||||
|
label->labeller = labeller;
|
||||||
|
|
||||||
|
labeller->ops->initialise_label(labeller, label);
|
||||||
|
|
||||||
|
return label;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,45 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2002 Sistina Software (UK) Limited.
|
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||||
|
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* This file is released under the LGPL.
|
* This file is part of LVM2.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use,
|
||||||
|
* modify, copy, or redistribute it subject to the terms and conditions
|
||||||
|
* of the GNU General Public License v.2.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LVM_LABEL_H
|
#ifndef _LVM_LABEL_H
|
||||||
#define _LVM_LABEL_H
|
#define _LVM_LABEL_H
|
||||||
|
|
||||||
|
#include "lvmcache.h"
|
||||||
#include "uuid.h"
|
#include "uuid.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
|
||||||
|
#define LABEL_ID "LABELONE"
|
||||||
|
#define LABEL_SIZE SECTOR_SIZE /* Think very carefully before changing this */
|
||||||
|
#define LABEL_SCAN_SECTORS 4L
|
||||||
|
#define LABEL_SCAN_SIZE (LABEL_SCAN_SECTORS << SECTOR_SHIFT)
|
||||||
|
|
||||||
|
/* On disk - 32 bytes */
|
||||||
|
struct label_header {
|
||||||
|
uint8_t id[8]; /* LABELONE */
|
||||||
|
uint64_t sector_xl; /* Sector number of this label */
|
||||||
|
uint32_t crc_xl; /* From next field to end of sector */
|
||||||
|
uint32_t offset_xl; /* Offset from start of struct to contents */
|
||||||
|
uint8_t type[8]; /* LVM2 001 */
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
/* In core */
|
||||||
struct label {
|
struct label {
|
||||||
struct id id;
|
char type[8];
|
||||||
|
uint64_t sector;
|
||||||
char volume_type[32];
|
|
||||||
uint32_t version[3];
|
|
||||||
|
|
||||||
void *extra_info;
|
|
||||||
|
|
||||||
struct labeller *labeller;
|
struct labeller *labeller;
|
||||||
|
void *info;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct labeller;
|
struct labeller;
|
||||||
@@ -27,47 +48,45 @@ struct label_ops {
|
|||||||
/*
|
/*
|
||||||
* Is the device labelled with this format ?
|
* Is the device labelled with this format ?
|
||||||
*/
|
*/
|
||||||
int (*can_handle)(struct labeller *l, struct device *dev);
|
int (*can_handle) (struct labeller * l, char *buf, uint64_t sector);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write a label to a volume.
|
* Write a label to a volume.
|
||||||
*/
|
*/
|
||||||
int (*write)(struct labeller *l,
|
int (*write) (struct label * label, char *buf);
|
||||||
struct device *dev, struct label *label);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Remove a label from a device.
|
|
||||||
*/
|
|
||||||
int (*remove)(struct labeller *l, struct device *dev);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read a label from a volume.
|
* Read a label from a volume.
|
||||||
*/
|
*/
|
||||||
int (*read)(struct labeller *l,
|
int (*read) (struct labeller * l, struct device * dev,
|
||||||
struct device *dev, struct label **label);
|
char *buf, struct label ** label);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Additional consistency checks for the paranoid.
|
* Additional consistency checks for the paranoid.
|
||||||
*/
|
*/
|
||||||
int (*verify)(struct labeller *l, struct device *dev);
|
int (*verify) (struct labeller * l, char *buf, uint64_t sector);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Populate label_type etc.
|
||||||
|
*/
|
||||||
|
int (*initialise_label) (struct labeller * l, struct label * label);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Destroy a previously read label.
|
* Destroy a previously read label.
|
||||||
*/
|
*/
|
||||||
void (*destroy_label)(struct labeller *l, struct label *label);
|
void (*destroy_label) (struct labeller * l, struct label * label);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Destructor.
|
* Destructor.
|
||||||
*/
|
*/
|
||||||
void (*destroy)(struct labeller *l);
|
void (*destroy) (struct labeller * l);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct labeller {
|
struct labeller {
|
||||||
struct label_ops *ops;
|
struct label_ops *ops;
|
||||||
void *private;
|
const void *private;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
int label_init(void);
|
int label_init(void);
|
||||||
void label_exit(void);
|
void label_exit(void);
|
||||||
|
|
||||||
@@ -77,14 +96,9 @@ struct labeller *label_get_handler(const char *name);
|
|||||||
|
|
||||||
int label_remove(struct device *dev);
|
int label_remove(struct device *dev);
|
||||||
int label_read(struct device *dev, struct label **result);
|
int label_read(struct device *dev, struct label **result);
|
||||||
|
int label_write(struct device *dev, struct label *label);
|
||||||
int label_verify(struct device *dev);
|
int label_verify(struct device *dev);
|
||||||
void label_destroy(struct label *lab);
|
struct label *label_create(struct labeller *labeller);
|
||||||
|
void label_destroy(struct label *label);
|
||||||
/*
|
|
||||||
* We'll support two label types: the 'pretend the
|
|
||||||
* LVM1 pv structure at the begining of the disk
|
|
||||||
* is a label' hack, and pjc's 1 sector labels at
|
|
||||||
* the front and back of the device.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,569 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2001-2002 Sistina Software
|
|
||||||
*
|
|
||||||
* This file is released under the LGPL.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "device.h"
|
|
||||||
#include "dev-cache.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "pool.h"
|
|
||||||
#include "dbg_malloc.h"
|
|
||||||
#include "filter.h"
|
|
||||||
#include "label.h"
|
|
||||||
#include "lvm2_label.h"
|
|
||||||
#include "xlate.h"
|
|
||||||
|
|
||||||
/* Label Magic is "LnXl" - error: imagination failure */
|
|
||||||
#define LABEL_MAGIC 0x6c586e4c
|
|
||||||
|
|
||||||
/* Size of blocks that dev_get_size() returns the number of */
|
|
||||||
#define BLOCK_SIZE 512
|
|
||||||
|
|
||||||
/* This is just the "struct lvm2_label" with the data pointer removed */
|
|
||||||
struct label_ondisk {
|
|
||||||
uint32_t magic;
|
|
||||||
uint32_t crc;
|
|
||||||
uint64_t label1_loc;
|
|
||||||
uint64_t label2_loc;
|
|
||||||
uint16_t datalen;
|
|
||||||
uint16_t pad;
|
|
||||||
|
|
||||||
uint32_t version[3];
|
|
||||||
char disk_type[32];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct filter_private {
|
|
||||||
void *mem;
|
|
||||||
char disk_type[32];
|
|
||||||
uint32_t version[3];
|
|
||||||
int version_match;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Calculate CRC32 of a buffer */
|
|
||||||
static uint32_t crc32(uint32_t initial, const unsigned char *databuf,
|
|
||||||
size_t datalen)
|
|
||||||
{
|
|
||||||
static const u_int crctab[] = {
|
|
||||||
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
|
|
||||||
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
|
|
||||||
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
|
|
||||||
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
|
|
||||||
};
|
|
||||||
uint32_t idx, crc = initial;
|
|
||||||
|
|
||||||
for (idx = 0; idx < datalen; idx++) {
|
|
||||||
crc ^= *databuf++;
|
|
||||||
crc = (crc >> 4) ^ crctab[crc & 0xf];
|
|
||||||
crc = (crc >> 4) ^ crctab[crc & 0xf];
|
|
||||||
}
|
|
||||||
return crc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculate crc */
|
|
||||||
static uint32_t calc_crc(struct label_ondisk *label, char *data)
|
|
||||||
{
|
|
||||||
uint32_t crcval = 0xffffffff;
|
|
||||||
|
|
||||||
crcval = crc32(crcval, (char *) &label->magic, sizeof(label->magic));
|
|
||||||
crcval =
|
|
||||||
crc32(crcval, (char *) &label->label1_loc,
|
|
||||||
sizeof(label->label1_loc));
|
|
||||||
crcval =
|
|
||||||
crc32(crcval, (char *) &label->label2_loc,
|
|
||||||
sizeof(label->label2_loc));
|
|
||||||
crcval =
|
|
||||||
crc32(crcval, (char *) &label->datalen, sizeof(label->datalen));
|
|
||||||
crcval =
|
|
||||||
crc32(crcval, (char *) &label->version, sizeof(label->version));
|
|
||||||
crcval =
|
|
||||||
crc32(crcval, (char *) label->disk_type, strlen(label->disk_type));
|
|
||||||
crcval = crc32(crcval, (char *) data, label->datalen);
|
|
||||||
|
|
||||||
return crcval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculate the locations we should find the labels in */
|
|
||||||
static inline void get_label_locations(uint64_t size, uint32_t sectsize,
|
|
||||||
long *first, long *second)
|
|
||||||
{
|
|
||||||
*first = sectsize;
|
|
||||||
*second = size * BLOCK_SIZE - sectsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read a label off disk */
|
|
||||||
static int lvm2_label_read(struct labeller *l, struct device *dev,
|
|
||||||
struct label **label)
|
|
||||||
{
|
|
||||||
uint64_t size;
|
|
||||||
uint32_t sectsize;
|
|
||||||
char *block;
|
|
||||||
struct label_ondisk *ondisk;
|
|
||||||
int status;
|
|
||||||
int iter;
|
|
||||||
long offset[2];
|
|
||||||
|
|
||||||
if (!dev_get_size(dev, &size))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!dev_get_sectsize(dev, §size))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!dev_open(dev, O_RDONLY))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
block = dbg_malloc(sectsize);
|
|
||||||
if (!block) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
ondisk = (struct label_ondisk *) block;
|
|
||||||
get_label_locations(size, sectsize, &offset[0], &offset[1]);
|
|
||||||
|
|
||||||
/* If the first label is bad then use the second */
|
|
||||||
for (iter = 0; iter <= 1; iter++) {
|
|
||||||
status = dev_read(dev, offset[iter], sectsize, block);
|
|
||||||
if (status) {
|
|
||||||
struct label *incore;
|
|
||||||
int i;
|
|
||||||
int found_nul;
|
|
||||||
|
|
||||||
/* If the MAGIC doesn't match there's no point in
|
|
||||||
carrying on */
|
|
||||||
if (xlate32(ondisk->magic) != LABEL_MAGIC)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Look for a NUL in the disk_type string so we don't
|
|
||||||
SEGV is something has gone horribly wrong */
|
|
||||||
found_nul = 0;
|
|
||||||
for (i = 0; i < sizeof(ondisk->disk_type); i++)
|
|
||||||
if (ondisk->disk_type[i] == '\0')
|
|
||||||
found_nul = 1;
|
|
||||||
|
|
||||||
if (!found_nul)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
incore = dbg_malloc(sizeof(struct label));
|
|
||||||
if (incore == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy and convert endianness */
|
|
||||||
strncpy(incore->volume_type, ondisk->disk_type,
|
|
||||||
sizeof(incore->volume_type));
|
|
||||||
incore->version[0] = xlate32(ondisk->version[0]);
|
|
||||||
incore->version[1] = xlate32(ondisk->version[1]);
|
|
||||||
incore->version[2] = xlate32(ondisk->version[2]);
|
|
||||||
incore->extra_len = xlate16(ondisk->datalen);
|
|
||||||
incore->extra_info =
|
|
||||||
block + sizeof(struct label_ondisk);
|
|
||||||
|
|
||||||
/* Make sure datalen is a sensible size too */
|
|
||||||
if (incore->extra_len > sectsize)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Check Crc */
|
|
||||||
if (xlate32(ondisk->crc) !=
|
|
||||||
calc_crc(ondisk, incore->extra_info)) {
|
|
||||||
log_error
|
|
||||||
("Crc %d on device %s does not match. got %x, expected %x",
|
|
||||||
iter, dev_name(dev), xlate32(ondisk->crc),
|
|
||||||
calc_crc(ondisk, incore->extra_info));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check label locations match our view of the device */
|
|
||||||
if (xlate64(ondisk->label1_loc) != offset[0])
|
|
||||||
log_error
|
|
||||||
("Label 1 location is wrong in label %d - check block size of the device\n",
|
|
||||||
iter);
|
|
||||||
if (xlate64(ondisk->label2_loc) != offset[1])
|
|
||||||
log_error
|
|
||||||
("Label 2 location is wrong in label %d - the size of the device must have changed\n",
|
|
||||||
iter);
|
|
||||||
|
|
||||||
/* Copy to user's data area */
|
|
||||||
*label = incore;
|
|
||||||
incore->extra_info = dbg_malloc(incore->extra_len);
|
|
||||||
if (!incore->extra_info) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
memcpy(incore->extra_info,
|
|
||||||
block + sizeof(struct label_ondisk),
|
|
||||||
incore->extra_len);
|
|
||||||
|
|
||||||
dbg_free(block);
|
|
||||||
dev_close(dev);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dbg_free(block);
|
|
||||||
dev_close(dev);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write a label to a device */
|
|
||||||
static int lvm2_label_write(struct labeller *l, struct device *dev,
|
|
||||||
struct label *label)
|
|
||||||
{
|
|
||||||
uint64_t size;
|
|
||||||
uint32_t sectsize;
|
|
||||||
char *block;
|
|
||||||
struct label_ondisk *ondisk;
|
|
||||||
int status1, status2;
|
|
||||||
long offset[2];
|
|
||||||
|
|
||||||
if (!dev_get_size(dev, &size))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!dev_get_sectsize(dev, §size))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Can the metata fit in the remaining space ? */
|
|
||||||
if (label->extra_len > sectsize - sizeof(struct label_ondisk))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
block = dbg_malloc(sizeof(struct label_ondisk) + label->extra_len);
|
|
||||||
if (!block) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
ondisk = (struct label_ondisk *) block;
|
|
||||||
|
|
||||||
get_label_locations(size, sectsize, &offset[0], &offset[1]);
|
|
||||||
|
|
||||||
/* Make into ondisk format */
|
|
||||||
ondisk->magic = xlate32(LABEL_MAGIC);
|
|
||||||
ondisk->version[0] = xlate32(label->version[0]);
|
|
||||||
ondisk->version[1] = xlate32(label->version[1]);
|
|
||||||
ondisk->version[2] = xlate32(label->version[2]);
|
|
||||||
ondisk->label1_loc = xlate64(offset[0]);
|
|
||||||
ondisk->label2_loc = xlate64(offset[1]);
|
|
||||||
ondisk->datalen = xlate16(label->extra_len);
|
|
||||||
strncpy(ondisk->disk_type, label->volume_type,
|
|
||||||
sizeof(ondisk->disk_type));
|
|
||||||
memcpy(block + sizeof(struct label_ondisk), label->extra_info,
|
|
||||||
label->extra_len);
|
|
||||||
ondisk->crc = xlate32(calc_crc(ondisk, label->extra_info));
|
|
||||||
|
|
||||||
/* Write metadata to disk */
|
|
||||||
if (!dev_open(dev, O_RDWR)) {
|
|
||||||
dbg_free(block);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
status1 =
|
|
||||||
dev_write(dev, offset[0],
|
|
||||||
sizeof(struct label_ondisk) + label->extra_len, block);
|
|
||||||
if (!status1)
|
|
||||||
log_error("Error writing label 1\n");
|
|
||||||
|
|
||||||
/* Write another at the end of the device */
|
|
||||||
status2 =
|
|
||||||
dev_write(dev, offset[1],
|
|
||||||
sizeof(struct label_ondisk) + label->extra_len, block);
|
|
||||||
if (!status2) {
|
|
||||||
char zerobuf[sizeof(struct label_ondisk)];
|
|
||||||
log_error("Error writing label 2\n");
|
|
||||||
|
|
||||||
/* Wipe the first label so it doesn't get confusing */
|
|
||||||
memset(zerobuf, 0, sizeof(struct label_ondisk));
|
|
||||||
if (!dev_write
|
|
||||||
(dev, offset[0], sizeof(struct label_ondisk),
|
|
||||||
zerobuf)) log_error("Error erasing label 1\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
dbg_free(block);
|
|
||||||
dev_close(dev);
|
|
||||||
|
|
||||||
return ((status1 != 0) && (status2 != 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return 1 for Yes, 0 for No */
|
|
||||||
static int lvm2_is_labelled(struct labeller *l, struct device *dev)
|
|
||||||
{
|
|
||||||
struct label *label;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
status = lvm2_label_read(l, dev, &label);
|
|
||||||
if (status)
|
|
||||||
label_free(label);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check the device is labelled and has the right format_type */
|
|
||||||
static int _accept_format(struct dev_filter *f, struct device *dev)
|
|
||||||
{
|
|
||||||
struct label *l;
|
|
||||||
int status;
|
|
||||||
struct filter_private *fp = (struct filter_private *) f->private;
|
|
||||||
|
|
||||||
status = lvm2_label_read(NULL, dev, &l);
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
if (strcmp(l->volume_type, fp->disk_type) == 0) {
|
|
||||||
switch (fp->version_match) {
|
|
||||||
case VERSION_MATCH_EQUAL:
|
|
||||||
if (l->version[0] == fp->version[0] &&
|
|
||||||
l->version[1] == fp->version[1] &&
|
|
||||||
l->version[2] == fp->version[2])
|
|
||||||
return 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VERSION_MATCH_LESSTHAN:
|
|
||||||
if (l->version[0] == fp->version[0] &&
|
|
||||||
l->version[1] < fp->version[1])
|
|
||||||
return 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VERSION_MATCH_LESSEQUAL:
|
|
||||||
if (l->version[0] == fp->version[0] &&
|
|
||||||
l->version[1] <= fp->version[1])
|
|
||||||
return 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VERSION_MATCH_ANY:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
label_free(l);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We just want to know if it's labelled or not */
|
|
||||||
static int _accept_label(struct dev_filter *f, struct device *dev)
|
|
||||||
{
|
|
||||||
return lvm2_is_labelled(NULL, dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _destroy(struct dev_filter *f)
|
|
||||||
{
|
|
||||||
struct filter_private *fp = (struct filter_private *) f->private;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* A filter to find devices with a particular label type on them */
|
|
||||||
struct dev_filter *lvm2_label_format_filter_create(char *disk_type,
|
|
||||||
uint32_t version[3],
|
|
||||||
int match_type)
|
|
||||||
{
|
|
||||||
struct pool *mem;
|
|
||||||
struct filter_private *fp;
|
|
||||||
struct dev_filter *f;
|
|
||||||
|
|
||||||
/* Validate the match type */
|
|
||||||
if (match_type != VERSION_MATCH_EQUAL &&
|
|
||||||
match_type != VERSION_MATCH_LESSTHAN &&
|
|
||||||
match_type != VERSION_MATCH_LESSEQUAL &&
|
|
||||||
match_type != VERSION_MATCH_ANY)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
mem = pool_create(10 * 1024);
|
|
||||||
if (!mem) {
|
|
||||||
stack;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(f = pool_zalloc(mem, sizeof(*f)))) {
|
|
||||||
stack;
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(fp = pool_zalloc(mem, sizeof(*fp)))) {
|
|
||||||
stack;
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp->mem = mem;
|
|
||||||
strcpy(fp->disk_type, disk_type);
|
|
||||||
fp->version[0] = version[0];
|
|
||||||
fp->version[1] = version[1];
|
|
||||||
fp->version[2] = version[2];
|
|
||||||
fp->version_match = match_type;
|
|
||||||
f->passes_filter = _accept_format;
|
|
||||||
f->destroy = _destroy;
|
|
||||||
f->private = fp;
|
|
||||||
|
|
||||||
return f;
|
|
||||||
|
|
||||||
bad:
|
|
||||||
pool_destroy(mem);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* A filter to find devices with any label on them */
|
|
||||||
struct dev_filter *lvm2_label_filter_create()
|
|
||||||
{
|
|
||||||
struct pool *mem = pool_create(10 * 1024);
|
|
||||||
struct filter_private *fp;
|
|
||||||
struct dev_filter *f;
|
|
||||||
|
|
||||||
if (!mem) {
|
|
||||||
stack;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(f = pool_zalloc(mem, sizeof(*f)))) {
|
|
||||||
stack;
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(fp = pool_zalloc(mem, sizeof(*fp)))) {
|
|
||||||
stack;
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp->mem = mem;
|
|
||||||
f->passes_filter = _accept_label;
|
|
||||||
f->destroy = _destroy;
|
|
||||||
f->private = fp;
|
|
||||||
|
|
||||||
return f;
|
|
||||||
|
|
||||||
bad:
|
|
||||||
pool_destroy(mem);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return 1 if both labels are identical, 0 if not or there was an error */
|
|
||||||
static int lvm2_labels_match(struct labeller *l, struct device *dev)
|
|
||||||
{
|
|
||||||
uint64_t size;
|
|
||||||
uint32_t sectsize;
|
|
||||||
char *block1;
|
|
||||||
char *block2;
|
|
||||||
struct label_ondisk *ondisk1;
|
|
||||||
struct label_ondisk *ondisk2;
|
|
||||||
int status = 0;
|
|
||||||
long offset[2];
|
|
||||||
|
|
||||||
if (!dev_get_size(dev, &size))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!dev_get_sectsize(dev, §size))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Allocate some space for the blocks we are going to read in */
|
|
||||||
block1 = dbg_malloc(sectsize);
|
|
||||||
if (!block1) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
block2 = dbg_malloc(sectsize);
|
|
||||||
if (!block2) {
|
|
||||||
stack;
|
|
||||||
dbg_free(block1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
ondisk1 = (struct label_ondisk *) block1;
|
|
||||||
ondisk2 = (struct label_ondisk *) block2;
|
|
||||||
|
|
||||||
get_label_locations(size, sectsize, &offset[0], &offset[1]);
|
|
||||||
|
|
||||||
/* Fetch em */
|
|
||||||
if (!dev_open(dev, O_RDONLY))
|
|
||||||
goto finish;
|
|
||||||
|
|
||||||
if (!dev_read(dev, offset[0], sectsize, block1))
|
|
||||||
goto finish;
|
|
||||||
|
|
||||||
if (!dev_read(dev, offset[1], sectsize, block2))
|
|
||||||
goto finish;
|
|
||||||
|
|
||||||
dev_close(dev);
|
|
||||||
|
|
||||||
/* Is it labelled? */
|
|
||||||
if (xlate32(ondisk1->magic) != LABEL_MAGIC)
|
|
||||||
goto finish;
|
|
||||||
|
|
||||||
/* Compare the whole structs */
|
|
||||||
if (memcmp(ondisk1, ondisk2, sizeof(struct label_ondisk)) != 0)
|
|
||||||
goto finish;
|
|
||||||
|
|
||||||
/* OK, check the data area */
|
|
||||||
if (memcmp(block1 + sizeof(struct label_ondisk),
|
|
||||||
block2 + sizeof(struct label_ondisk),
|
|
||||||
xlate16(ondisk1->datalen)) != 0)
|
|
||||||
goto finish;
|
|
||||||
|
|
||||||
/* They match !! */
|
|
||||||
status = 1;
|
|
||||||
|
|
||||||
finish:
|
|
||||||
dbg_free(block2);
|
|
||||||
dbg_free(block1);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lvm2_label_remove(struct labeller *l, struct device *dev)
|
|
||||||
{
|
|
||||||
uint64_t size;
|
|
||||||
uint32_t sectsize;
|
|
||||||
char block[BLOCK_SIZE];
|
|
||||||
int status1, status2;
|
|
||||||
long offset[2];
|
|
||||||
|
|
||||||
if (!dev_get_size(dev, &size))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!dev_get_sectsize(dev, §size))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!dev_open(dev, O_RDWR)) {
|
|
||||||
dbg_free(block);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
get_label_locations(size, sectsize, &offset[0], &offset[1]);
|
|
||||||
memset(block, 0, BLOCK_SIZE);
|
|
||||||
|
|
||||||
/* Blank out the first label */
|
|
||||||
status1 = dev_write(dev, offset[0], BLOCK_SIZE, block);
|
|
||||||
if (!status1)
|
|
||||||
log_error("Error erasing label 1\n");
|
|
||||||
|
|
||||||
/* ...and the other at the end of the device */
|
|
||||||
status2 = dev_write(dev, offset[1], BLOCK_SIZE, block);
|
|
||||||
if (!status2)
|
|
||||||
log_error("Error erasing label 2\n");
|
|
||||||
|
|
||||||
dev_close(dev);
|
|
||||||
|
|
||||||
return ((status1 != 0) && (status2 != 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void lvm2_label_destroy(struct labeller *l)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct label_ops handler_ops = {
|
|
||||||
can_handle: lvm2_is_labelled,
|
|
||||||
write: lvm2_label_write,
|
|
||||||
remove: lvm2_label_remove,
|
|
||||||
read: lvm2_label_read,
|
|
||||||
verify: lvm2_labels_match,
|
|
||||||
destroy: lvm2_label_destroy,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct labeller this_labeller = {
|
|
||||||
private: NULL,
|
|
||||||
ops: &handler_ops,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Don't know how this gets called... */
|
|
||||||
void lvm2_label_init()
|
|
||||||
{
|
|
||||||
label_register_handler("LVM2", &this_labeller);
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
|
||||||
*
|
|
||||||
* This file is released under the GPL.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct lvm2_label
|
|
||||||
{
|
|
||||||
uint32_t magic;
|
|
||||||
uint32_t crc;
|
|
||||||
uint64_t label1_loc;
|
|
||||||
uint64_t label2_loc;
|
|
||||||
uint16_t datalen;
|
|
||||||
|
|
||||||
char disk_type[32];
|
|
||||||
uint32_t version[3];
|
|
||||||
|
|
||||||
char *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define VERSION_MATCH_EQUAL 1
|
|
||||||
#define VERSION_MATCH_LESSTHAN 2
|
|
||||||
#define VERSION_MATCH_LESSEQUAL 3
|
|
||||||
#define VERSION_MATCH_ANY 4
|
|
||||||
|
|
||||||
extern struct dev_filter *lvm2_label_filter_create();
|
|
||||||
extern struct dev_filter *lvm2_label_format_filter_create(char *disk_type, uint32_t version[3], int match_type);
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user