mirror of
git://sourceware.org/git/lvm2.git
synced 2025-10-26 07:33:16 +03:00
Compare commits
509 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
235f940cde | ||
|
|
803d61fcbc | ||
|
|
ffbd7d8de4 | ||
|
|
4ed924d7c7 | ||
|
|
798dc9948b | ||
|
|
13515f7ee4 | ||
|
|
ef80824c26 | ||
|
|
c8503fd65e | ||
|
|
b3c454fb1c | ||
|
|
1d7723e873 | ||
|
|
77100b2365 | ||
|
|
259a788134 | ||
|
|
39511455cb | ||
|
|
b04c16178e | ||
|
|
49a959c06e | ||
|
|
096a8932b4 | ||
|
|
e39e66df93 | ||
|
|
513633f49a | ||
|
|
eb3740daaf | ||
|
|
f7947b148a | ||
|
|
9a2a702f3f | ||
|
|
c65d95bf29 | ||
|
|
753a5edc4f | ||
|
|
0b3f853c2d | ||
|
|
3527fcf1d5 | ||
|
|
4544a89c7a | ||
|
|
ffeae9005e | ||
|
|
47217bcfb7 | ||
|
|
80ff58b57a | ||
|
|
d15dd368f1 | ||
|
|
8a2ec32bd8 | ||
|
|
410496ed52 | ||
|
|
b7b07552e5 | ||
|
|
44486e80d9 | ||
|
|
7890c527d8 | ||
|
|
2c82ab79a7 | ||
|
|
e3ebe5fc53 | ||
|
|
0ac430892e | ||
|
|
a7739c942c | ||
|
|
24581482d0 | ||
|
|
0571c3b453 | ||
|
|
73e7f5a0b0 | ||
|
|
20c0adb961 | ||
|
|
a01e03562f | ||
|
|
d184ed0130 | ||
|
|
089e1c2aee | ||
|
|
ebab0e91ee | ||
|
|
858a2b1b88 | ||
|
|
02bd59827c | ||
|
|
4991428510 | ||
|
|
3b245f5dc1 | ||
|
|
c9c81da901 | ||
|
|
4919cdc3fb | ||
|
|
e90e1f577d | ||
|
|
afd4284403 | ||
|
|
150b350d31 | ||
|
|
2818520bd1 | ||
|
|
2819952292 | ||
|
|
5af71af51c | ||
|
|
07a55b51df | ||
|
|
66dd68b49d | ||
|
|
9812657777 | ||
|
|
0b09312fc6 | ||
|
|
d0a7ac6b74 | ||
|
|
ff9a238fbd | ||
|
|
359fffa5f1 | ||
|
|
5bf92ced1a | ||
|
|
340bcc7b45 | ||
|
|
ef03742bd4 | ||
|
|
20431ec16d | ||
|
|
becba8157b | ||
|
|
51fd3bb0eb | ||
|
|
4bbd3acb4e | ||
|
|
3bc930ea7b | ||
|
|
d1b26f8e86 | ||
|
|
fdf15caaff | ||
|
|
c7b4a53c0b | ||
|
|
af78dc0308 | ||
|
|
5ad39493c4 | ||
|
|
61f597b408 | ||
|
|
2162825240 | ||
|
|
2b780e70d1 | ||
|
|
a3823f818e | ||
|
|
1f7c47bcaf | ||
|
|
ec53c365a2 | ||
|
|
793ad1f2d4 | ||
|
|
9bc733b76c | ||
|
|
21b28f0217 | ||
|
|
d3e23caa52 | ||
|
|
9e7518de67 | ||
|
|
679f0047aa | ||
|
|
d77d5ce14b | ||
|
|
33ec22a2af | ||
|
|
353053225f | ||
|
|
b7f3d6f7f7 | ||
|
|
e34577499d | ||
|
|
4cf8960c0c | ||
|
|
1f93ea0675 | ||
|
|
25b705c3a8 | ||
|
|
0725588731 | ||
|
|
fc5c61cc8b | ||
|
|
ac282e63c6 | ||
|
|
c3941941ce | ||
|
|
46cdd53323 | ||
|
|
3ff3e302c3 | ||
|
|
f2ceecf95c | ||
|
|
9314c7c881 | ||
|
|
54abb2c572 | ||
|
|
8fa3bdd025 | ||
|
|
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 | ||
|
|
eff96d839e | ||
|
|
aa34c23807 | ||
|
|
195acdac8c | ||
|
|
903e03c56c | ||
|
|
0892767b8a | ||
|
|
83ebfa772c | ||
|
|
1583641322 | ||
|
|
9510e2c256 | ||
|
|
a9dbabe07e | ||
|
|
12884008fa | ||
|
|
02543bad1c | ||
|
|
a8c56a5251 | ||
|
|
4e5a855f3f | ||
|
|
7e497a951e | ||
|
|
cd08eabbfa | ||
|
|
f7e62d9f81 | ||
|
|
9a3761e86e | ||
|
|
3619a68693 | ||
|
|
efaf3c3bf9 | ||
|
|
0e4e6a6f67 | ||
|
|
42458e6278 | ||
|
|
41ec995377 | ||
|
|
4f37599326 | ||
|
|
4144520e5c | ||
|
|
6c4800546c | ||
|
|
733733c8a7 | ||
|
|
2aa67cc946 | ||
|
|
9385981a9d | ||
|
|
fff780035d | ||
|
|
46127e673d | ||
|
|
70df59b224 | ||
|
|
0fdbaa803f | ||
|
|
6af1830eff | ||
|
|
6f860e2bd5 | ||
|
|
20a492f7ee | ||
|
|
63875e7591 | ||
|
|
0ad98cabde | ||
|
|
668879d2e1 |
21
INSTALL
21
INSTALL
@@ -6,8 +6,8 @@ LVM2 installation
|
||||
Ensure the device-mapper has been installed on the machine.
|
||||
|
||||
The device-mapper should be in the kernel (look for 'device-mapper'
|
||||
messages in the kernel logs) and /usr/include/libdevmapper.h should
|
||||
be present.
|
||||
messages in the kernel logs) and /usr/include/libdevmapper.h
|
||||
and libdevmapper.so should be present.
|
||||
|
||||
The device-mapper is available from:
|
||||
ftp://ftp.sistina.com/pub/LVM2/device-mapper/
|
||||
@@ -17,9 +17,15 @@ LVM2 installation
|
||||
|
||||
Run the 'configure' script from the top directory.
|
||||
|
||||
If you do not have GNU readline (http://www.gnu.org/directory/readline.html)
|
||||
installed use
|
||||
./configure --disable-readline
|
||||
If you wish to use the built-in LVM2 shell and have GNU readline
|
||||
installed (http://www.gnu.org/directory/readline.html) use:
|
||||
./configure --enable-readline
|
||||
|
||||
If you don't want to include the LVM1 backwards-compatibility code use:
|
||||
./configure --with-lvm1=none
|
||||
|
||||
To separate the LVM1 support into a shared library loaded by lvm.conf use:
|
||||
./configure --with-lvm1=shared
|
||||
|
||||
|
||||
3) Build and install LVM2.
|
||||
@@ -31,6 +37,9 @@ LVM2 installation
|
||||
|
||||
The tools will work fine without a configuration file being
|
||||
present, but you ought to review the example file in doc/example.conf.
|
||||
For example, specifying the devices that LVM2 is to use should
|
||||
For example, specifying the devices that LVM2 is to use can
|
||||
make the tools run more efficiently - and avoid scanning /dev/cdrom!
|
||||
|
||||
Please also refer to the WHATS_NEW file and the manual pages for the
|
||||
individual commands.
|
||||
|
||||
|
||||
18
INTRO
18
INTRO
@@ -1,18 +0,0 @@
|
||||
An introduction to LVM2
|
||||
=======================
|
||||
|
||||
Background
|
||||
|
||||
|
||||
Compatibility with LVM1
|
||||
|
||||
|
||||
New features
|
||||
|
||||
|
||||
Missing features
|
||||
|
||||
|
||||
Future enhancements
|
||||
|
||||
|
||||
50
Makefile.in
50
Makefile.in
@@ -1,34 +1,52 @@
|
||||
#
|
||||
# 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
|
||||
# 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 file is part of the LVM2.
|
||||
#
|
||||
# This LVM library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Library General Public License for more details.
|
||||
# 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 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
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
SUBDIRS = include man lib tools
|
||||
SUBDIRS = doc include man
|
||||
|
||||
ifeq ("@INTL@", "yes")
|
||||
SUBDIRS += po
|
||||
endif
|
||||
|
||||
SUBDIRS += lib tools daemons
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS += test/mm test/device test/format1 test/regex test/filters
|
||||
SUBDIRS += daemons/clvmd \
|
||||
lib/format1 \
|
||||
lib/format_pool \
|
||||
lib/locking \
|
||||
lib/mirror \
|
||||
lib/snapshot \
|
||||
po \
|
||||
test/mm test/device test/format1 test/regex test/filters
|
||||
endif
|
||||
|
||||
include make.tmpl
|
||||
|
||||
daemons: lib
|
||||
lib: include
|
||||
tools: include lib
|
||||
tools: lib
|
||||
po: tools daemons
|
||||
|
||||
ifeq ("@INTL@", "yes")
|
||||
lib.pofile: include.pofile
|
||||
tools.pofile: lib.pofile
|
||||
daemons.pofile: lib.pofile
|
||||
po.pofile: tools.pofile daemons.pofile
|
||||
pofile: po.pofile
|
||||
endif
|
||||
|
||||
|
||||
22
README
22
README
@@ -1,25 +1,23 @@
|
||||
This directory contains a beta release of LMV2, the new version of
|
||||
the userland LVM tools designed for the new device-mapper for
|
||||
the Linux kernel.
|
||||
This directory contains LVM2, the new version of the userland LVM
|
||||
tools designed for the new device-mapper for the Linux kernel.
|
||||
|
||||
The device-mapper needs to be installed before compiling these LVM2 tools.
|
||||
|
||||
For more information about LVM2 read the INTRO file.
|
||||
For more information about LVM2 read the WHATS_NEW file.
|
||||
Installation instructions are in INSTALL.
|
||||
|
||||
This is beta-quality software, released for testing purposes only.
|
||||
There is no warranty - see COPYING and COPYING.LIB.
|
||||
|
||||
Tarballs are available from:
|
||||
ftp://ftp.sistina.com/pub/LVM2/tools/
|
||||
ftp://ftp.sistina.com/pub/LVM2/device-mapper/
|
||||
ftp://sources.redhat.com/pub/lvm2/
|
||||
ftp://sources.redhat.com/pub/dm/
|
||||
|
||||
To access the CVS tree use:
|
||||
cvs -d :pserver:cvs@tech.sistina.com:/data/cvs login
|
||||
CVS password: cvs1
|
||||
cvs -d :pserver:cvs@tech.sistina.com:/data/cvs checkout LVM2
|
||||
cvs -d :pserver:cvs@sources.redhat.com:/cvs/lvm2 login
|
||||
CVS password: cvs
|
||||
cvs -d :pserver:cvs@sources.redhat.com:/cvs/lvm2 co LVM2
|
||||
|
||||
Mailing list for discussion/bug reports etc.
|
||||
lvm-devel@sistina.com
|
||||
Subscribe from http://lists.sistina.com/mailman/listinfo/lvm-devel
|
||||
linux-lvm@redhat.com
|
||||
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
|
||||
281
WHATS_NEW
Normal file
281
WHATS_NEW
Normal file
@@ -0,0 +1,281 @@
|
||||
Version 2.00.23 - 15th September 2004
|
||||
=====================================
|
||||
Export dm name build & split functions.
|
||||
Use O_NOATIME on devices if available.
|
||||
Write log message when each segtype/format gets initialised.
|
||||
New commands 'segtypes' and 'formats'.
|
||||
Suppress pvmove abort message in test mode.
|
||||
Improve pvcreate/remove device not found error message.
|
||||
Allow pvmove to move data within the same PV.
|
||||
Describe how pvmove works on man page.
|
||||
Test for incompatible format/segtype combinations in lv_extend.
|
||||
Fix lvchange example on man page.
|
||||
|
||||
Version 2.00.22 - 3rd September 2004
|
||||
====================================
|
||||
Fix /dev/vgname perms.
|
||||
Restructure xlate.h.
|
||||
Add clvmd man page.
|
||||
|
||||
Version 2.00.21 - 19th August 2004
|
||||
==================================
|
||||
Update cnxman-socket.h from cman.
|
||||
Recognise iseries/vd devices.
|
||||
Use 'make install_cluster' to install cluster extensions only.
|
||||
Cope with DT_UNKNOWN in sysfs.
|
||||
Fix extents_moved metadata size comment.
|
||||
Remove duplicate line in pvremove help text.
|
||||
Support variable mirror region size.
|
||||
Support PE ranges in pvmove source PV.
|
||||
Fixes to as-yet-unused LV segment splitting code.
|
||||
Change alloc_areas to pe_ranges and allow suppression of availability checks.
|
||||
Add dev_size column to pvs.
|
||||
Add report columns for in-kernel device number.
|
||||
|
||||
Version 2.00.20 - 3 July 2004
|
||||
=============================
|
||||
More autoconf fixes.
|
||||
Fix device number handling for 2.6 kernels.
|
||||
|
||||
Version 2.00.19 - 29 June 2004
|
||||
==============================
|
||||
Reduce severity of setlocale failure message.
|
||||
Recognise argv[0] "initrd-lvm" (pld-linux).
|
||||
Make -O2 configurable.
|
||||
Added --disable-selinux to configure script.
|
||||
LD_FLAGS->LDFLAGS & LD_DEPS->LDDEPS in configure script.
|
||||
Add init_debug to clvmd.
|
||||
|
||||
Version 2.00.18 - 24 June 2004
|
||||
==============================
|
||||
Fix vgchange activation.
|
||||
Add cluster support.
|
||||
|
||||
Version 2.00.17 - 20 June 2004
|
||||
==============================
|
||||
configure --enable-fsadm to try out fsadm. fsadm is not tested yet.
|
||||
Display all filtered devices, not just PVs, with pvs -a.
|
||||
Fix sync_dir() when no / in filename
|
||||
vgcfgbackup -f accepts template with %s for VG name.
|
||||
Extend hash functions to handle non-null-terminated data.
|
||||
Add local activation support.
|
||||
Tidy relative paths in makefile includes.
|
||||
fsadm support for fsck and resizing - needs testing.
|
||||
Add read-only GFS pool support.
|
||||
Add lvm2create_initrd script from http://poochiereds.net/svn/lvm2/
|
||||
Fix rounding of large diplayed sizes.
|
||||
Suppress decimal point when using units of sectors/bytes.
|
||||
Additional kernel target checks before pvmove & snapshot creation.
|
||||
Add i2o_block.
|
||||
|
||||
Version 2.00.16 - 24 May 2004
|
||||
=============================
|
||||
Set area_count within alloc_lv_segment.
|
||||
Remove error labels from lvresize.
|
||||
Fix a pvs error path.
|
||||
xxchange -ae for exclusive activation.
|
||||
Don't return non-zero status if there aren't any volume groups.
|
||||
Add --alloc argument to tools.
|
||||
Rename allocation policies to contiguous, normal, anywhere, inherit.
|
||||
nextfree becomes normal; anywhere isn't implemented yet.
|
||||
LV inherits allocation policy from VG. Defaults: LV - inherit; VG - normal
|
||||
Additional status character added to vgs to indicate allocation policy.
|
||||
Add reset_fn to external_locking.
|
||||
Ensure presence of virtual targets before attempting activating.
|
||||
Attempt to fix resizing of snapshot origins.
|
||||
Restructure lvresize, bringing it closer to lvcreate.
|
||||
A quick sanity check on vg_disk struct when read in. More checks needed.
|
||||
Only include visible LVs in active/open counts.
|
||||
Add virtual segment types, zero and error. A large sparse device can be
|
||||
constructed as a writeable snapshot of a large zero segment.
|
||||
Add --type to lvcreate/resize.
|
||||
Push lv_create & alloc policy up to tool level.
|
||||
Fix pvdisplay return code.
|
||||
Detect invalid LV names in arg lists.
|
||||
Reporting uses line-at-a-time output.
|
||||
lvm2 format sets unlimited_vols format flag.
|
||||
Internal-only metadata flag support.
|
||||
Basic checking for presence of device-mapper targets.
|
||||
Separate out polldaemon.
|
||||
Revise internal locking semantics.
|
||||
Move find_pv_by_name to library.
|
||||
Rename move->copy.
|
||||
Add devices to segments report.
|
||||
Begin separating out segment code. There's a lot of change here.
|
||||
Compress any (obsolete) long LVM1 pvids encountered.
|
||||
Support for tagged config files.
|
||||
Don't abort operations if selinux present but disabled.
|
||||
Fix typo in configure which left HAVE_LIBDL unset.
|
||||
|
||||
Version 2.00.15 - 19 Apr 2004
|
||||
=============================
|
||||
configure --with-owner= --with-group= to avoid -o and -g args to 'install'
|
||||
|
||||
Version 2.00.14 - 16 Apr 2004
|
||||
=============================
|
||||
Use 64-bit file functions by default.
|
||||
|
||||
Version 2.00.13 - 16 Apr 2004
|
||||
=============================
|
||||
Set devices/md_component_detection = 1 to ignore devices containing md
|
||||
superblocks. [Luca Berra]
|
||||
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!
|
||||
|
||||
75
WHATS_NEW_DM
Normal file
75
WHATS_NEW_DM
Normal file
@@ -0,0 +1,75 @@
|
||||
Version 1.00.20 -
|
||||
=============================
|
||||
|
||||
Version 1.00.19 - 3 July 2004
|
||||
=============================
|
||||
More autoconf fixes.
|
||||
Fix a dmsetup newline.
|
||||
Fix device number handling for 2.6 kernels.
|
||||
|
||||
Version 1.00.18 - 20 Jun 2004
|
||||
=============================
|
||||
Fix a uuid free in libdm-iface.
|
||||
Fix a targets string size calc in driver.
|
||||
Add -c to dmsetup for column-based output.
|
||||
Add target message-passing ioctl.
|
||||
|
||||
Version 1.00.17 - 17 Apr 2004
|
||||
=============================
|
||||
configure --with-owner= --with-group= to avoid -o and -g args to 'install'
|
||||
Fix library selinux linking.
|
||||
|
||||
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
|
||||
# Configuration validation subroutine script, version 1.1.
|
||||
# Copyright (C) 1991, 92-97, 1998, 1999 Free Software Foundation, Inc.
|
||||
# Configuration validation subroutine script.
|
||||
# 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.
|
||||
# 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.
|
||||
@@ -25,6 +29,9 @@
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# 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.
|
||||
# Supply the specified configuration type as an argument.
|
||||
# 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
|
||||
# It is wrong to echo any other type of specification.
|
||||
|
||||
if [ x$1 = x ]
|
||||
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
|
||||
me=`echo "$0" | sed -e 's,.*/,,'`
|
||||
|
||||
# First pass through any local machine types.
|
||||
case $1 in
|
||||
*local*)
|
||||
echo $1
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
usage="\
|
||||
Usage: $0 [OPTION] CPU-MFR-OPSYS
|
||||
$0 [OPTION] ALIAS
|
||||
|
||||
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
|
||||
|
||||
# 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.
|
||||
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
|
||||
case $maybe_os in
|
||||
linux-gnu*)
|
||||
nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
|
||||
os=-$maybe_os
|
||||
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
|
||||
;;
|
||||
@@ -94,7 +144,7 @@ case $os in
|
||||
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
|
||||
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
|
||||
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
|
||||
-apple)
|
||||
-apple | -axis)
|
||||
os=
|
||||
basic_machine=$1
|
||||
;;
|
||||
@@ -105,9 +155,17 @@ case $os in
|
||||
-scout)
|
||||
;;
|
||||
-wrs)
|
||||
os=vxworks
|
||||
os=-vxworks
|
||||
basic_machine=$1
|
||||
;;
|
||||
-chorusos*)
|
||||
os=-chorusos
|
||||
basic_machine=$1
|
||||
;;
|
||||
-chorusrdb)
|
||||
os=-chorusrdb
|
||||
basic_machine=$1
|
||||
;;
|
||||
-hiux*)
|
||||
os=-hiuxwe2
|
||||
;;
|
||||
@@ -156,33 +214,72 @@ case $os in
|
||||
-psos*)
|
||||
os=-psos
|
||||
;;
|
||||
-mint | -mint[0-9]*)
|
||||
basic_machine=m68k-atari
|
||||
os=-mint
|
||||
;;
|
||||
esac
|
||||
|
||||
# Decode aliases for certain CPU-COMPANY combinations.
|
||||
case $basic_machine in
|
||||
# Recognize the basic CPU types without company name.
|
||||
# Some are omitted here because they have special meanings below.
|
||||
tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
|
||||
| arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \
|
||||
| 580 | i960 | h8300 \
|
||||
| hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
|
||||
| alpha | alphaev[4-7] | alphaev56 | alphapca5[67] \
|
||||
| we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \
|
||||
| 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \
|
||||
| mips64orion | mips64orionel | mipstx39 | mipstx39el \
|
||||
| mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
|
||||
| mips64vr5000 | miprs64vr5000el | mcore \
|
||||
| sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \
|
||||
| thumb | d10v)
|
||||
1750a | 580 \
|
||||
| a29k \
|
||||
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
|
||||
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
|
||||
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
|
||||
| c4x | clipper \
|
||||
| d10v | d30v | dlx | dsp16xx \
|
||||
| fr30 | frv \
|
||||
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
|
||||
| i370 | i860 | i960 | ia64 \
|
||||
| ip2k \
|
||||
| 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
|
||||
;;
|
||||
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'
|
||||
# because (1) that's what they normally are, and
|
||||
# (2) the word "unknown" tends to confuse beginning users.
|
||||
i[34567]86)
|
||||
i*86 | x86_64)
|
||||
basic_machine=$basic_machine-pc
|
||||
;;
|
||||
# Object if more than one company name word.
|
||||
@@ -191,24 +288,60 @@ case $basic_machine in
|
||||
exit 1
|
||||
;;
|
||||
# Recognize the basic CPU types with company name.
|
||||
# FIXME: clean up the formatting here.
|
||||
vax-* | tahoe-* | i[34567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \
|
||||
| m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
|
||||
| mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
|
||||
| power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
|
||||
| xmp-* | ymp-* \
|
||||
| hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* | hppa2.0n-* \
|
||||
| alpha-* | alphaev[4-7]-* | alphaev56-* | alphapca5[67]-* \
|
||||
| we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
|
||||
| clipper-* | orion-* \
|
||||
| sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
|
||||
| sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \
|
||||
| mips64el-* | mips64orion-* | mips64orionel-* \
|
||||
| mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
|
||||
| mipstx39-* | mipstx39el-* | mcore-* \
|
||||
| f301-* | armv*-* | t3e-* \
|
||||
| m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
|
||||
| thumb-* | v850-* | d30v-* | tic30-* | c30-* )
|
||||
580-* \
|
||||
| a29k-* \
|
||||
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
|
||||
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
|
||||
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
|
||||
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
|
||||
| avr-* \
|
||||
| bs2000-* \
|
||||
| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
|
||||
| clipper-* | cydra-* \
|
||||
| d10v-* | d30v-* | dlx-* \
|
||||
| elxsi-* \
|
||||
| f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
|
||||
| h8300-* | h8500-* \
|
||||
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
|
||||
| i*86-* | i860-* | i960-* | ia64-* \
|
||||
| ip2k-* \
|
||||
| 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
|
||||
# for a CPU type and a company and sometimes even an OS.
|
||||
@@ -240,19 +373,22 @@ case $basic_machine in
|
||||
basic_machine=a29k-none
|
||||
os=-bsd
|
||||
;;
|
||||
amd64)
|
||||
basic_machine=x86_64-pc
|
||||
;;
|
||||
amdahl)
|
||||
basic_machine=580-amdahl
|
||||
os=-sysv
|
||||
;;
|
||||
amiga | amiga-*)
|
||||
basic_machine=m68k-cbm
|
||||
basic_machine=m68k-unknown
|
||||
;;
|
||||
amigaos | amigados)
|
||||
basic_machine=m68k-cbm
|
||||
basic_machine=m68k-unknown
|
||||
os=-amigaos
|
||||
;;
|
||||
amigaunix | amix)
|
||||
basic_machine=m68k-cbm
|
||||
basic_machine=m68k-unknown
|
||||
os=-sysv4
|
||||
;;
|
||||
apollo68)
|
||||
@@ -271,6 +407,10 @@ case $basic_machine in
|
||||
basic_machine=ns32k-sequent
|
||||
os=-dynix
|
||||
;;
|
||||
c90)
|
||||
basic_machine=c90-cray
|
||||
os=-unicos
|
||||
;;
|
||||
convex-c1)
|
||||
basic_machine=c1-convex
|
||||
os=-bsd
|
||||
@@ -291,27 +431,30 @@ case $basic_machine in
|
||||
basic_machine=c38-convex
|
||||
os=-bsd
|
||||
;;
|
||||
cray | ymp)
|
||||
basic_machine=ymp-cray
|
||||
os=-unicos
|
||||
;;
|
||||
cray2)
|
||||
basic_machine=cray2-cray
|
||||
os=-unicos
|
||||
;;
|
||||
[ctj]90-cray)
|
||||
basic_machine=c90-cray
|
||||
cray | j90)
|
||||
basic_machine=j90-cray
|
||||
os=-unicos
|
||||
;;
|
||||
crds | unos)
|
||||
basic_machine=m68k-crds
|
||||
;;
|
||||
cris | cris-* | etrax*)
|
||||
basic_machine=cris-axis
|
||||
;;
|
||||
da30 | da30-*)
|
||||
basic_machine=m68k-da30
|
||||
;;
|
||||
decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
|
||||
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 \
|
||||
| 3300-motorola | delta-motorola)
|
||||
basic_machine=m68k-motorola
|
||||
@@ -353,6 +496,10 @@ case $basic_machine in
|
||||
basic_machine=tron-gmicro
|
||||
os=-sysv
|
||||
;;
|
||||
go32)
|
||||
basic_machine=i386-pc
|
||||
os=-go32
|
||||
;;
|
||||
h3050r* | hiux*)
|
||||
basic_machine=hppa1.1-hitachi
|
||||
os=-hiuxwe2
|
||||
@@ -426,22 +573,21 @@ case $basic_machine in
|
||||
;;
|
||||
i370-ibm* | ibm*)
|
||||
basic_machine=i370-ibm
|
||||
os=-mvs
|
||||
;;
|
||||
# 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/'`
|
||||
os=-sysv32
|
||||
;;
|
||||
i[34567]86v4*)
|
||||
i*86v4*)
|
||||
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
|
||||
os=-sysv4
|
||||
;;
|
||||
i[34567]86v)
|
||||
i*86v)
|
||||
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
|
||||
os=-sysv
|
||||
;;
|
||||
i[34567]86sol2)
|
||||
i*86sol2)
|
||||
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
|
||||
os=-solaris2
|
||||
;;
|
||||
@@ -453,14 +599,6 @@ case $basic_machine in
|
||||
basic_machine=i386-unknown
|
||||
os=-vsta
|
||||
;;
|
||||
i386-go32 | go32)
|
||||
basic_machine=i386-unknown
|
||||
os=-go32
|
||||
;;
|
||||
i386-mingw32 | mingw32)
|
||||
basic_machine=i386-unknown
|
||||
os=-mingw32
|
||||
;;
|
||||
iris | iris4d)
|
||||
basic_machine=mips-sgi
|
||||
case $os in
|
||||
@@ -486,35 +624,43 @@ case $basic_machine in
|
||||
basic_machine=ns32k-utek
|
||||
os=-sysv
|
||||
;;
|
||||
mingw32)
|
||||
basic_machine=i386-pc
|
||||
os=-mingw32
|
||||
;;
|
||||
miniframe)
|
||||
basic_machine=m68000-convergent
|
||||
;;
|
||||
*mint | *MiNT)
|
||||
*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
|
||||
basic_machine=m68k-atari
|
||||
os=-mint
|
||||
;;
|
||||
mipsel*-linux*)
|
||||
basic_machine=mipsel-unknown
|
||||
os=-linux-gnu
|
||||
;;
|
||||
mips*-linux*)
|
||||
basic_machine=mips-unknown
|
||||
os=-linux-gnu
|
||||
;;
|
||||
mips3*-*)
|
||||
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
|
||||
;;
|
||||
mips3*)
|
||||
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
|
||||
;;
|
||||
mmix*)
|
||||
basic_machine=mmix-knuth
|
||||
os=-mmixware
|
||||
;;
|
||||
monitor)
|
||||
basic_machine=m68k-rom68k
|
||||
os=-coff
|
||||
;;
|
||||
morphos)
|
||||
basic_machine=powerpc-unknown
|
||||
os=-morphos
|
||||
;;
|
||||
msdos)
|
||||
basic_machine=i386-unknown
|
||||
basic_machine=i386-pc
|
||||
os=-msdos
|
||||
;;
|
||||
mvs)
|
||||
basic_machine=i370-ibm
|
||||
os=-mvs
|
||||
;;
|
||||
ncr3000)
|
||||
basic_machine=i486-ncr
|
||||
os=-sysv4
|
||||
@@ -524,7 +670,7 @@ case $basic_machine in
|
||||
os=-netbsd
|
||||
;;
|
||||
netwinder)
|
||||
basic_machine=armv4l-corel
|
||||
basic_machine=armv4l-rebel
|
||||
os=-linux
|
||||
;;
|
||||
news | news700 | news800 | news900)
|
||||
@@ -572,13 +718,28 @@ case $basic_machine in
|
||||
basic_machine=i960-intel
|
||||
os=-mon960
|
||||
;;
|
||||
nonstopux)
|
||||
basic_machine=mips-compaq
|
||||
os=-nonstopux
|
||||
;;
|
||||
np1)
|
||||
basic_machine=np1-gould
|
||||
;;
|
||||
nv1)
|
||||
basic_machine=nv1-cray
|
||||
os=-unicosmp
|
||||
;;
|
||||
nsr-tandem)
|
||||
basic_machine=nsr-tandem
|
||||
;;
|
||||
op50n-* | op60c-*)
|
||||
basic_machine=hppa1.1-oki
|
||||
os=-proelf
|
||||
;;
|
||||
or32 | or32-*)
|
||||
basic_machine=or32-unknown
|
||||
os=-coff
|
||||
;;
|
||||
OSE68000 | ose68000)
|
||||
basic_machine=m68000-ericsson
|
||||
os=-ose
|
||||
@@ -601,45 +762,65 @@ case $basic_machine in
|
||||
pbb)
|
||||
basic_machine=m68k-tti
|
||||
;;
|
||||
pc532 | pc532-*)
|
||||
pc532 | pc532-*)
|
||||
basic_machine=ns32k-pc532
|
||||
;;
|
||||
pentium | p5 | k5 | k6 | nexen)
|
||||
pentium | p5 | k5 | k6 | nexgen | viac3)
|
||||
basic_machine=i586-pc
|
||||
;;
|
||||
pentiumpro | p6 | 6x86)
|
||||
pentiumpro | p6 | 6x86 | athlon | athlon_*)
|
||||
basic_machine=i686-pc
|
||||
;;
|
||||
pentiumii | pentium2)
|
||||
pentiumii | pentium2 | pentiumiii | pentium3)
|
||||
basic_machine=i686-pc
|
||||
;;
|
||||
pentium4)
|
||||
basic_machine=i786-pc
|
||||
;;
|
||||
pentium-* | p5-* | k5-* | k6-* | nexen-*)
|
||||
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
|
||||
basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
pentiumpro-* | p6-* | 6x86-*)
|
||||
pentiumpro-* | p6-* | 6x86-* | athlon-*)
|
||||
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/^[^-]*-//'`
|
||||
;;
|
||||
pn)
|
||||
basic_machine=pn-gould
|
||||
;;
|
||||
power) basic_machine=rs6000-ibm
|
||||
power) basic_machine=power-ibm
|
||||
;;
|
||||
ppc) basic_machine=powerpc-unknown
|
||||
;;
|
||||
;;
|
||||
ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
ppcle | powerpclittle | ppc-le | powerpc-little)
|
||||
basic_machine=powerpcle-unknown
|
||||
;;
|
||||
;;
|
||||
ppcle-* | powerpclittle-*)
|
||||
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)
|
||||
basic_machine=i386-ibm
|
||||
;;
|
||||
pw32)
|
||||
basic_machine=i586-unknown
|
||||
os=-pw32
|
||||
;;
|
||||
rom68k)
|
||||
basic_machine=m68k-rom68k
|
||||
os=-coff
|
||||
@@ -650,10 +831,26 @@ case $basic_machine in
|
||||
rtpc | rtpc-*)
|
||||
basic_machine=romp-ibm
|
||||
;;
|
||||
s390 | s390-*)
|
||||
basic_machine=s390-ibm
|
||||
;;
|
||||
s390x | s390x-*)
|
||||
basic_machine=s390x-ibm
|
||||
;;
|
||||
sa29200)
|
||||
basic_machine=a29k-amd
|
||||
os=-udi
|
||||
;;
|
||||
sb1)
|
||||
basic_machine=mipsisa64sb1-unknown
|
||||
;;
|
||||
sb1el)
|
||||
basic_machine=mipsisa64sb1el-unknown
|
||||
;;
|
||||
sei)
|
||||
basic_machine=mips-sei
|
||||
os=-seiux
|
||||
;;
|
||||
sequent)
|
||||
basic_machine=i386-sequent
|
||||
;;
|
||||
@@ -661,7 +858,10 @@ case $basic_machine in
|
||||
basic_machine=sh-hitachi
|
||||
os=-hms
|
||||
;;
|
||||
sparclite-wrs)
|
||||
sh64)
|
||||
basic_machine=sh64-unknown
|
||||
;;
|
||||
sparclite-wrs | simso-wrs)
|
||||
basic_machine=sparclite-wrs
|
||||
os=-vxworks
|
||||
;;
|
||||
@@ -719,20 +919,44 @@ case $basic_machine in
|
||||
sun386 | sun386i | roadrunner)
|
||||
basic_machine=i386-sun
|
||||
;;
|
||||
sv1)
|
||||
basic_machine=sv1-cray
|
||||
os=-unicos
|
||||
;;
|
||||
symmetry)
|
||||
basic_machine=i386-sequent
|
||||
os=-dynix
|
||||
;;
|
||||
t3e)
|
||||
basic_machine=t3e-cray
|
||||
basic_machine=alphaev5-cray
|
||||
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)
|
||||
basic_machine=mipstx39-unknown
|
||||
;;
|
||||
tx39el)
|
||||
basic_machine=mipstx39el-unknown
|
||||
;;
|
||||
toad1)
|
||||
basic_machine=pdp10-xkl
|
||||
os=-tops20
|
||||
;;
|
||||
tower | tower-32)
|
||||
basic_machine=m68k-ncr
|
||||
;;
|
||||
@@ -757,8 +981,8 @@ case $basic_machine in
|
||||
os=-vms
|
||||
;;
|
||||
vpp*|vx|vx-*)
|
||||
basic_machine=f301-fujitsu
|
||||
;;
|
||||
basic_machine=f301-fujitsu
|
||||
;;
|
||||
vxworks960)
|
||||
basic_machine=i960-wrs
|
||||
os=-vxworks
|
||||
@@ -779,13 +1003,13 @@ case $basic_machine in
|
||||
basic_machine=hppa1.1-winbond
|
||||
os=-proelf
|
||||
;;
|
||||
xmp)
|
||||
basic_machine=xmp-cray
|
||||
os=-unicos
|
||||
;;
|
||||
xps | xps100)
|
||||
xps | xps100)
|
||||
basic_machine=xps100-honeywell
|
||||
;;
|
||||
ymp)
|
||||
basic_machine=ymp-cray
|
||||
os=-unicos
|
||||
;;
|
||||
z8k-*-coff)
|
||||
basic_machine=z8k-unknown
|
||||
os=-sim
|
||||
@@ -806,13 +1030,6 @@ case $basic_machine in
|
||||
op60c)
|
||||
basic_machine=hppa1.1-oki
|
||||
;;
|
||||
mips)
|
||||
if [ x$os = x-linux-gnu ]; then
|
||||
basic_machine=mips-unknown
|
||||
else
|
||||
basic_machine=mips-mips
|
||||
fi
|
||||
;;
|
||||
romp)
|
||||
basic_machine=romp-ibm
|
||||
;;
|
||||
@@ -822,16 +1039,26 @@ case $basic_machine in
|
||||
vax)
|
||||
basic_machine=vax-dec
|
||||
;;
|
||||
pdp10)
|
||||
# there are many clones, so DEC is not a safe bet
|
||||
basic_machine=pdp10-unknown
|
||||
;;
|
||||
pdp11)
|
||||
basic_machine=pdp11-dec
|
||||
;;
|
||||
we32k)
|
||||
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
|
||||
;;
|
||||
cydra)
|
||||
cydra)
|
||||
basic_machine=cydra-cydrome
|
||||
;;
|
||||
orion)
|
||||
@@ -846,9 +1073,8 @@ case $basic_machine in
|
||||
pmac | pmac-mpw)
|
||||
basic_machine=powerpc-apple
|
||||
;;
|
||||
c4x*)
|
||||
basic_machine=c4x-none
|
||||
os=-coff
|
||||
*-unknown)
|
||||
# Make sure to match an already-canonicalized machine name.
|
||||
;;
|
||||
*)
|
||||
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* \
|
||||
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
|
||||
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
|
||||
| -chorusos* | -chorusrdb* \
|
||||
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
|
||||
| -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.
|
||||
;;
|
||||
-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* \
|
||||
| -windows* | -osx | -abug | -netware* | -os9* | -beos* \
|
||||
| -macos* | -mpw* | -magic* | -mon960* | -lnews*)
|
||||
| -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
|
||||
;;
|
||||
-mac*)
|
||||
os=`echo $os | sed -e 's|mac|macos|'`
|
||||
@@ -927,6 +1173,12 @@ case $os in
|
||||
-sunos6*)
|
||||
os=`echo $os | sed -e 's|sunos6|solaris3|'`
|
||||
;;
|
||||
-opened*)
|
||||
os=-openedition
|
||||
;;
|
||||
-wince*)
|
||||
os=-wince
|
||||
;;
|
||||
-osfrose*)
|
||||
os=-osfrose
|
||||
;;
|
||||
@@ -942,14 +1194,23 @@ case $os in
|
||||
-acis*)
|
||||
os=-aos
|
||||
;;
|
||||
-atheos*)
|
||||
os=-atheos
|
||||
;;
|
||||
-386bsd)
|
||||
os=-bsd
|
||||
;;
|
||||
-ctix* | -uts*)
|
||||
os=-sysv
|
||||
;;
|
||||
-nova*)
|
||||
os=-rtmk-nova
|
||||
;;
|
||||
-ns2 )
|
||||
os=-nextstep2
|
||||
os=-nextstep2
|
||||
;;
|
||||
-nsk*)
|
||||
os=-nsk
|
||||
;;
|
||||
# Preserve the version number of sinix5.
|
||||
-sinix5.*)
|
||||
@@ -985,8 +1246,14 @@ case $os in
|
||||
-xenix)
|
||||
os=-xenix
|
||||
;;
|
||||
-*mint | -*MiNT)
|
||||
os=-mint
|
||||
-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
|
||||
os=-mint
|
||||
;;
|
||||
-aros*)
|
||||
os=-aros
|
||||
;;
|
||||
-kaos*)
|
||||
os=-kaos
|
||||
;;
|
||||
-none)
|
||||
;;
|
||||
@@ -1013,13 +1280,20 @@ case $basic_machine in
|
||||
*-acorn)
|
||||
os=-riscix1.2
|
||||
;;
|
||||
arm*-corel)
|
||||
arm*-rebel)
|
||||
os=-linux
|
||||
;;
|
||||
arm*-semi)
|
||||
os=-aout
|
||||
;;
|
||||
pdp11-*)
|
||||
c4x-* | tic4x-*)
|
||||
os=-coff
|
||||
;;
|
||||
# This must come before the *-dec entry.
|
||||
pdp10-*)
|
||||
os=-tops20
|
||||
;;
|
||||
pdp11-*)
|
||||
os=-none
|
||||
;;
|
||||
*-dec | vax-*)
|
||||
@@ -1046,6 +1320,9 @@ case $basic_machine in
|
||||
mips*-*)
|
||||
os=-elf
|
||||
;;
|
||||
or32-*)
|
||||
os=-coff
|
||||
;;
|
||||
*-tti) # must be before sparc entry or we get the wrong os.
|
||||
os=-sysv3
|
||||
;;
|
||||
@@ -1109,25 +1386,25 @@ case $basic_machine in
|
||||
*-next)
|
||||
os=-nextstep3
|
||||
;;
|
||||
*-gould)
|
||||
*-gould)
|
||||
os=-sysv
|
||||
;;
|
||||
*-highlevel)
|
||||
*-highlevel)
|
||||
os=-bsd
|
||||
;;
|
||||
*-encore)
|
||||
os=-bsd
|
||||
;;
|
||||
*-sgi)
|
||||
*-sgi)
|
||||
os=-irix
|
||||
;;
|
||||
*-siemens)
|
||||
*-siemens)
|
||||
os=-sysv4
|
||||
;;
|
||||
*-masscomp)
|
||||
os=-rtu
|
||||
;;
|
||||
f301-fujitsu)
|
||||
f30[01]-fujitsu | f700-fujitsu)
|
||||
os=-uxpv
|
||||
;;
|
||||
*-rom68k)
|
||||
@@ -1187,13 +1464,13 @@ case $basic_machine in
|
||||
-genix*)
|
||||
vendor=ns
|
||||
;;
|
||||
-mvs*)
|
||||
-mvs* | -opened*)
|
||||
vendor=ibm
|
||||
;;
|
||||
-ptx*)
|
||||
vendor=sequent
|
||||
;;
|
||||
-vxsim* | -vxworks*)
|
||||
-vxsim* | -vxworks* | -windiss*)
|
||||
vendor=wrs
|
||||
;;
|
||||
-aux*)
|
||||
@@ -1205,12 +1482,23 @@ case $basic_machine in
|
||||
-mpw* | -macos*)
|
||||
vendor=apple
|
||||
;;
|
||||
-*mint | -*MiNT)
|
||||
-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
|
||||
vendor=atari
|
||||
;;
|
||||
-vos*)
|
||||
vendor=stratus
|
||||
;;
|
||||
esac
|
||||
basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
|
||||
;;
|
||||
esac
|
||||
|
||||
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
|
||||
#
|
||||
# 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
|
||||
# documentation for any purpose is hereby granted without fee, provided that
|
||||
# the above copyright notice appear in all copies and that both that
|
||||
# copyright notice and this permission notice appear in supporting
|
||||
# documentation, and that the name of M.I.T. not be used in advertising or
|
||||
# publicity pertaining to distribution of the software without specific,
|
||||
# written prior permission. M.I.T. makes no representations about the
|
||||
# suitability of this software for any purpose. It is provided "as is"
|
||||
# without express or implied warranty.
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# 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
|
||||
# `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
|
||||
# shared with many OS's install programs.
|
||||
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit="${DOITPROG-}"
|
||||
|
||||
|
||||
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||
|
||||
mvprog="${MVPROG-mv}"
|
||||
@@ -41,211 +58,229 @@ stripprog="${STRIPPROG-strip}"
|
||||
rmprog="${RMPROG-rm}"
|
||||
mkdirprog="${MKDIRPROG-mkdir}"
|
||||
|
||||
transformbasename=""
|
||||
transform_arg=""
|
||||
transformbasename=
|
||||
transform_arg=
|
||||
instcmd="$mvprog"
|
||||
chmodcmd="$chmodprog 0755"
|
||||
chowncmd=""
|
||||
chgrpcmd=""
|
||||
stripcmd=""
|
||||
chowncmd=
|
||||
chgrpcmd=
|
||||
stripcmd=
|
||||
rmcmd="$rmprog -f"
|
||||
mvcmd="$mvprog"
|
||||
src=""
|
||||
dst=""
|
||||
dir_arg=""
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
|
||||
while [ x"$1" != x ]; do
|
||||
case $1 in
|
||||
-c) instcmd="$cpprog"
|
||||
shift
|
||||
continue;;
|
||||
usage="Usage: $0 [OPTION]... SRCFILE DSTFILE
|
||||
or: $0 -d DIR1 DIR2...
|
||||
|
||||
-d) dir_arg=true
|
||||
shift
|
||||
continue;;
|
||||
In the first form, install SRCFILE to DSTFILE, removing SRCFILE by default.
|
||||
In the second, create the directory path DIR.
|
||||
|
||||
-m) chmodcmd="$chmodprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
Options:
|
||||
-b=TRANSFORMBASENAME
|
||||
-c copy source (using $cpprog) instead of moving (using $mvprog).
|
||||
-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"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
while test -n "$1"; do
|
||||
case $1 in
|
||||
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-s) stripcmd="$stripprog"
|
||||
shift
|
||||
continue;;
|
||||
-c) instcmd=$cpprog
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
||||
shift
|
||||
continue;;
|
||||
-d) dir_arg=true
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||
shift
|
||||
continue;;
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
*) if [ x"$src" = x ]
|
||||
then
|
||||
src=$1
|
||||
else
|
||||
# this colon is to work around a 386BSD /bin/sh bug
|
||||
:
|
||||
dst=$1
|
||||
fi
|
||||
shift
|
||||
continue;;
|
||||
esac
|
||||
--help) echo "$usage"; exit 0;;
|
||||
|
||||
-m) chmodcmd="$chmodprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift
|
||||
shift
|
||||
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
|
||||
|
||||
if [ x"$src" = x ]
|
||||
then
|
||||
echo "install: no input file specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
if test -z "$src"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]; then
|
||||
dst=$src
|
||||
src=""
|
||||
|
||||
if [ -d $dst ]; then
|
||||
instcmd=:
|
||||
chmodcmd=""
|
||||
else
|
||||
instcmd=mkdir
|
||||
fi
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
src=
|
||||
|
||||
if test -d "$dst"; then
|
||||
instcmd=:
|
||||
chmodcmd=
|
||||
else
|
||||
instcmd=$mkdirprog
|
||||
fi
|
||||
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
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test -z "$dst"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -f $src -o -d $src ]
|
||||
then
|
||||
true
|
||||
else
|
||||
echo "install: $src does not exist"
|
||||
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
|
||||
# If destination is a directory, append the input filename; won't work
|
||||
# if double slashes aren't ignored.
|
||||
if test -d "$dst"; then
|
||||
dst=$dst/`basename "$src"`
|
||||
fi
|
||||
fi
|
||||
|
||||
## 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.
|
||||
# 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.
|
||||
if [ ! -d "$dstdir" ]; then
|
||||
defaultIFS='
|
||||
'
|
||||
IFS="${IFS-${defaultIFS}}"
|
||||
if test ! -d "$dstdir"; then
|
||||
defaultIFS='
|
||||
'
|
||||
IFS="${IFS-$defaultIFS}"
|
||||
|
||||
oIFS="${IFS}"
|
||||
# Some sh's can't handle IFS=/ for some reason.
|
||||
IFS='%'
|
||||
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||
IFS="${oIFS}"
|
||||
oIFS=$IFS
|
||||
# Some sh's can't handle IFS=/ for some reason.
|
||||
IFS='%'
|
||||
set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||
IFS=$oIFS
|
||||
|
||||
pathcomp=''
|
||||
pathcomp=
|
||||
|
||||
while [ $# -ne 0 ] ; do
|
||||
pathcomp="${pathcomp}${1}"
|
||||
shift
|
||||
|
||||
if [ ! -d "${pathcomp}" ] ;
|
||||
then
|
||||
$mkdirprog "${pathcomp}"
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
pathcomp="${pathcomp}/"
|
||||
done
|
||||
while test $# -ne 0 ; do
|
||||
pathcomp=$pathcomp$1
|
||||
shift
|
||||
test -d "$pathcomp" || $mkdirprog "$pathcomp"
|
||||
pathcomp=$pathcomp/
|
||||
done
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]
|
||||
then
|
||||
$doit $instcmd $dst &&
|
||||
if test -n "$dir_arg"; then
|
||||
$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
|
||||
# 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 ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
dstfile=`basename $dst $transformbasename |
|
||||
sed $transformarg`$transformbasename
|
||||
fi
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=$dstdir/_inst.$$_
|
||||
rmtmp=$dstdir/_rm.$$_
|
||||
|
||||
# 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 ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
true
|
||||
fi
|
||||
# Move or copy the file name to the temp name
|
||||
$doit $instcmd "$src" "$dsttmp" &&
|
||||
|
||||
# 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.$$#
|
||||
|
||||
# Move or copy the file name to the temp name
|
||||
|
||||
$doit $instcmd $src $dsttmp &&
|
||||
|
||||
trap "rm -f ${dsttmp}" 0 &&
|
||||
|
||||
# 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.
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;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 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
|
||||
# the destination file might be busy for other reasons. In this case,
|
||||
# the final cleanup might fail but the new file should still install
|
||||
# successfully.
|
||||
{
|
||||
if test -f "$dstdir/$dstfile"; then
|
||||
$doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
|
||||
|| $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
|
||||
|| {
|
||||
echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
|
||||
(exit 1); exit
|
||||
}
|
||||
else
|
||||
:
|
||||
fi
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
|
||||
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:
|
||||
|
||||
536
configure.in
536
configure.in
@@ -1,30 +1,64 @@
|
||||
################################################################################
|
||||
##
|
||||
## Copyright 1999-2000 Sistina Software, Inc.
|
||||
## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved.
|
||||
## Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
##
|
||||
## This is free software released under the GNU General Public License.
|
||||
## There is no warranty for this software. See the file COPYING for
|
||||
## details.
|
||||
## This file is part of the LVM2.
|
||||
##
|
||||
## See the file CONTRIBUTORS for a list of contributors.
|
||||
## 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.
|
||||
##
|
||||
## This file is maintained by:
|
||||
## AJ Lewis <lewis@sistina.com>
|
||||
##
|
||||
## File name: configure.in
|
||||
##
|
||||
## Description: Input file for autoconf. Generates the configure script
|
||||
## that tries to keep everything nice and portable. It also
|
||||
## simplifies distribution package building considerably.
|
||||
## 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
|
||||
################################################################################
|
||||
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_PREREQ(2.53)
|
||||
################################################################################
|
||||
dnl -- Process this file with autoconf to produce a configure script.
|
||||
AC_INIT(lib/device/dev-cache.h)
|
||||
|
||||
dnl setup the directory where autoconf has auxilary files
|
||||
################################################################################
|
||||
dnl -- Setup the directory where autoconf has auxilary files
|
||||
AC_CONFIG_AUX_DIR(autoconf)
|
||||
|
||||
dnl Checks for programs.
|
||||
################################################################################
|
||||
dnl -- Get system type
|
||||
AC_CANONICAL_SYSTEM
|
||||
|
||||
case "$host_os" in
|
||||
linux*)
|
||||
CFLAGS="$CFLAGS"
|
||||
COPTIMISE_FLAG="-O2"
|
||||
CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym"
|
||||
CLDWHOLEARCHIVE="-Wl,-whole-archive"
|
||||
CLDNOWHOLEARCHIVE="-Wl,-no-whole-archive"
|
||||
LDDEPS="$LDDEPS .export.sym"
|
||||
LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
|
||||
SOFLAG="-shared"
|
||||
DEVMAPPER=yes
|
||||
ODIRECT=yes
|
||||
SELINUX=yes
|
||||
CLUSTER=internal
|
||||
FSADM=no ;;
|
||||
darwin*)
|
||||
CFLAGS="$CFLAGS -no-cpp-precomp -fno-common"
|
||||
COPTIMISE_FLAG="-O2"
|
||||
CLDFLAGS="$CLDFLAGS"
|
||||
CLDWHOLEARCHIVE="-all_load"
|
||||
CLDNOWHOLEARCHIVE=
|
||||
LDDEPS="$LDDEPS"
|
||||
LDFLAGS="$LDFLAGS"
|
||||
SOFLAG="-dynamiclib"
|
||||
DEVMAPPER=no
|
||||
ODIRECT=no
|
||||
SELINUX=no
|
||||
CLUSTER=none
|
||||
FSADM=no ;;
|
||||
esac
|
||||
|
||||
################################################################################
|
||||
dnl -- Checks for programs.
|
||||
AC_PROG_AWK
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
@@ -32,57 +66,304 @@ AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_RANLIB
|
||||
|
||||
dnl Checks for header files.
|
||||
################################################################################
|
||||
dnl -- Checks for header files.
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS(fcntl.h malloc.h sys/ioctl.h unistd.h)
|
||||
AC_HEADER_SYS_WAIT
|
||||
AC_HEADER_TIME
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_CHECK_HEADERS(fcntl.h limits.h locale.h stddef.h syslog.h sys/file.h sys/ioctl.h sys/param.h sys/time.h,,AC_MSG_ERROR(bailing out))
|
||||
AC_CHECK_HEADERS(assert.h ctype.h libgen.h signal.h stdio.h sys/mman.h sys/resource.h sys/stat.h sys/types.h sys/utsname.h sys/wait.h time.h,,AC_MSG_ERROR(bailing out))
|
||||
|
||||
case "$host_os" in
|
||||
linux*)
|
||||
AC_CHECK_HEADERS(asm/byteorder.h linux/fs.h malloc.h,,AC_MSG_ERROR(bailing out)) ;;
|
||||
darwin*)
|
||||
AC_CHECK_HEADERS(machine/endian.h sys/disk.h,,AC_MSG_ERROR(bailing out)) ;;
|
||||
esac
|
||||
|
||||
################################################################################
|
||||
dnl -- Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_C_INLINE
|
||||
AC_TYPE_OFF_T
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_MODE_T
|
||||
AC_STRUCT_ST_RDEV
|
||||
AC_HEADER_TIME
|
||||
AC_STRUCT_TM
|
||||
|
||||
dnl -- prefix is /usr by default, the exec_prefix default is setup later
|
||||
################################################################################
|
||||
dnl -- Check for functions
|
||||
AC_CHECK_FUNCS(gethostname getpagesize memset munmap setlocale strcasecmp strchr strdup strncasecmp strerror strrchr strstr strtol strtoul,,AC_MSG_ERROR(bailing out))
|
||||
AC_FUNC_ALLOCA
|
||||
AC_FUNC_CLOSEDIR_VOID
|
||||
AC_FUNC_FORK
|
||||
AC_FUNC_LSTAT
|
||||
AC_FUNC_MALLOC
|
||||
AC_FUNC_MEMCMP
|
||||
AC_FUNC_MMAP
|
||||
AC_FUNC_STAT
|
||||
AC_FUNC_STRTOD
|
||||
|
||||
################################################################################
|
||||
dnl -- Prefix is /usr by default, the exec_prefix default is setup later
|
||||
AC_PREFIX_DEFAULT(/usr)
|
||||
|
||||
dnl -- setup the ownership of the files
|
||||
################################################################################
|
||||
dnl -- Parallel make jobs?
|
||||
AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=-j2)
|
||||
|
||||
################################################################################
|
||||
dnl -- Setup the ownership of the files
|
||||
AC_MSG_CHECKING(file owner)
|
||||
OWNER="root"
|
||||
|
||||
AC_ARG_WITH(user,
|
||||
[ --with-user=USER Set the owner of installed files ],
|
||||
[ OWNER="$withval" ],
|
||||
[ OWNER="root" ])
|
||||
[ OWNER="$withval" ])
|
||||
AC_MSG_RESULT($OWNER)
|
||||
|
||||
dnl -- setup the group ownership of the files
|
||||
if test x$OWNER != x; then
|
||||
OWNER="-o $OWNER"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Setup the group ownership of the files
|
||||
AC_MSG_CHECKING(group owner)
|
||||
GROUP="root"
|
||||
AC_ARG_WITH(group,
|
||||
[ --with-group=GROUP Set the group owner of installed files ],
|
||||
[ GROUP="$withval" ],
|
||||
[ GROUP="root" ])
|
||||
[ GROUP="$withval" ])
|
||||
AC_MSG_RESULT($GROUP)
|
||||
|
||||
AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=)
|
||||
if test x$GROUP != x; then
|
||||
GROUP="-g $GROUP"
|
||||
fi
|
||||
|
||||
dnl Enables staticly linked tools
|
||||
AC_ARG_ENABLE(static_link, [ --enable-static_link Use this to link the tools to the liblvm library
|
||||
################################################################################
|
||||
dnl -- LVM1 tool fallback option
|
||||
AC_MSG_CHECKING(whether to enable lvm1 fallback)
|
||||
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)
|
||||
AC_MSG_RESULT($LVM1_FALLBACK)
|
||||
|
||||
if test x$LVM1_FALLBACK = xyes; then
|
||||
CFLAGS="$CFLAGS -DLVM1_FALLBACK"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- format1 inclusion type
|
||||
AC_MSG_CHECKING(whether to include support for lvm1 metadata)
|
||||
AC_ARG_WITH(lvm1,
|
||||
[ --with-lvm1=TYPE LVM1 metadata support: internal/shared/none
|
||||
[TYPE=internal] ],
|
||||
[ LVM1="$withval" ],
|
||||
[ LVM1="internal" ])
|
||||
AC_MSG_RESULT($LVM1)
|
||||
|
||||
if [[ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]];
|
||||
then AC_MSG_ERROR(
|
||||
--with-lvm1 parameter invalid
|
||||
)
|
||||
fi;
|
||||
|
||||
if test x$LVM1 = xinternal; then
|
||||
CFLAGS="$CFLAGS -DLVM1_INTERNAL"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- format_pool inclusion type
|
||||
AC_MSG_CHECKING(whether to include support for GFS pool metadata)
|
||||
AC_ARG_WITH(pool,
|
||||
[ --with-pool=TYPE GFS pool read-only support: internal/shared/none
|
||||
[TYPE=internal] ],
|
||||
[ POOL="$withval" ],
|
||||
[ POOL="internal" ])
|
||||
AC_MSG_RESULT($POOL)
|
||||
|
||||
if [[ "x$POOL" != xnone -a "x$POOL" != xinternal -a "x$POOL" != xshared ]];
|
||||
then AC_MSG_ERROR(
|
||||
--with-pool parameter invalid
|
||||
)
|
||||
fi;
|
||||
|
||||
if test x$POOL = xinternal; then
|
||||
CFLAGS="$CFLAGS -DPOOL_INTERNAL"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- cluster_locking inclusion type
|
||||
AC_MSG_CHECKING(whether to include support for cluster locking)
|
||||
AC_ARG_WITH(cluster,
|
||||
[ --with-cluster=TYPE Cluster LVM locking support: internal/shared/none
|
||||
[TYPE=internal] ],
|
||||
[ CLUSTER="$withval" ])
|
||||
AC_MSG_RESULT($CLUSTER)
|
||||
|
||||
if [[ "x$CLUSTER" != xnone -a "x$CLUSTER" != xinternal -a "x$CLUSTER" != xshared ]];
|
||||
then AC_MSG_ERROR(
|
||||
--with-cluster parameter invalid
|
||||
)
|
||||
fi;
|
||||
|
||||
if test x$CLUSTER = xinternal; then
|
||||
CFLAGS="$CFLAGS -DCLUSTER_LOCKING_INTERNAL"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- snapshots inclusion type
|
||||
AC_MSG_CHECKING(whether to include snapshots)
|
||||
AC_ARG_WITH(snapshots,
|
||||
[ --with-snapshots=TYPE Snapshot support: internal/shared/none
|
||||
[TYPE=internal] ],
|
||||
[ SNAPSHOTS="$withval" ],
|
||||
[ SNAPSHOTS="internal" ])
|
||||
AC_MSG_RESULT($SNAPSHOTS)
|
||||
|
||||
if [[ "x$SNAPSHOTS" != xnone -a "x$SNAPSHOTS" != xinternal -a "x$SNAPSHOTS" != xshared ]];
|
||||
then AC_MSG_ERROR(
|
||||
--with-snapshots parameter invalid
|
||||
)
|
||||
fi;
|
||||
|
||||
if test x$SNAPSHOTS = xinternal; then
|
||||
CFLAGS="$CFLAGS -DSNAPSHOT_INTERNAL"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- mirrors inclusion type
|
||||
AC_MSG_CHECKING(whether to include mirrors)
|
||||
AC_ARG_WITH(mirrors,
|
||||
[ --with-mirrors=TYPE Mirror support: internal/shared/none
|
||||
[TYPE=internal] ],
|
||||
[ MIRRORS="$withval" ],
|
||||
[ MIRRORS="internal" ])
|
||||
AC_MSG_RESULT($MIRRORS)
|
||||
|
||||
if [[ "x$MIRRORS" != xnone -a "x$MIRRORS" != xinternal -a "x$MIRRORS" != xshared ]];
|
||||
then AC_MSG_ERROR(
|
||||
--with-mirrors parameter invalid
|
||||
)
|
||||
fi;
|
||||
|
||||
if test x$MIRRORS = xinternal; then
|
||||
CFLAGS="$CFLAGS -DMIRRORED_INTERNAL"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Enables staticly-linked tools
|
||||
AC_MSG_CHECKING(whether to use static linking)
|
||||
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)
|
||||
AC_MSG_RESULT($STATIC_LINK)
|
||||
|
||||
dnl Disable readline
|
||||
AC_ARG_ENABLE(readline, [ --disable-readline Disable readline support], \
|
||||
READLINE=$enableval, READLINE=yes)
|
||||
################################################################################
|
||||
dnl -- Enable readline
|
||||
AC_MSG_CHECKING(whether to enable readline)
|
||||
AC_ARG_ENABLE(readline, [ --enable-readline Enable readline support],
|
||||
READLINE=$enableval, READLINE=no)
|
||||
AC_MSG_RESULT($READLINE)
|
||||
|
||||
dnl Mess with default exec_prefix
|
||||
if test x$READLINE = xyes; then
|
||||
CFLAGS="$CFLAGS -DREADLINE_SUPPORT"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable selinux
|
||||
AC_MSG_CHECKING(whether to enable selinux support)
|
||||
AC_ARG_ENABLE(selinux, [ --disable-selinux Disable selinux support],
|
||||
SELINUX=$enableval)
|
||||
AC_MSG_RESULT($SELINUX)
|
||||
|
||||
################################################################################
|
||||
dnl -- Build cluster LVM daemon
|
||||
AC_MSG_CHECKING(whether to build cluster LVM daemon)
|
||||
AC_ARG_WITH(clvmd, [ --with-clvmd Build cluster LVM Daemon],
|
||||
CLVMD=$withval, CLVMD=no)
|
||||
AC_MSG_RESULT($CLVMD)
|
||||
|
||||
dnl -- If clvmd enabled without cluster locking, automagically include it
|
||||
if test x$CLVMD = xyes && test x$CLUSTER = xnone; then
|
||||
CLUSTER=internal
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable debugging
|
||||
AC_MSG_CHECKING(whether to enable debugging)
|
||||
AC_ARG_ENABLE(debug, [ --enable-debug Enable debugging],
|
||||
DEBUG=$enableval, DEBUG=no)
|
||||
AC_MSG_RESULT($DEBUG)
|
||||
|
||||
dnl -- Normally turn off optimisation for debug builds
|
||||
if test x$DEBUG = xyes; then
|
||||
COPTIMISE_FLAG=
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Override optimisation
|
||||
AC_MSG_CHECKING(for C optimisation flag)
|
||||
AC_ARG_WITH(optimisation,
|
||||
[ --with-optimisation=OPT C optimisation flag [OPT=-O2] ],
|
||||
[ COPTIMISE_FLAG="$withval" ])
|
||||
AC_MSG_RESULT($COPTIMISE_FLAG)
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable devmapper
|
||||
AC_MSG_CHECKING(whether to use device-mapper)
|
||||
AC_ARG_ENABLE(devmapper, [ --disable-devmapper Disable device-mapper interaction],
|
||||
DEVMAPPER=$enableval)
|
||||
AC_MSG_RESULT($DEVMAPPER)
|
||||
|
||||
if test x$DEVMAPPER = xyes; then
|
||||
CFLAGS="$CFLAGS -DDEVMAPPER_SUPPORT"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable O_DIRECT
|
||||
AC_MSG_CHECKING(whether to enable O_DIRECT)
|
||||
AC_ARG_ENABLE(o_direct, [ --disable-o_direct Disable O_DIRECT],
|
||||
ODIRECT=$enableval)
|
||||
AC_MSG_RESULT($ODIRECT)
|
||||
|
||||
if test x$ODIRECT = xyes; then
|
||||
CFLAGS="$CFLAGS -DO_DIRECT_SUPPORT"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable cmdlib
|
||||
AC_MSG_CHECKING(whether to compile liblvm2cmd.so)
|
||||
AC_ARG_ENABLE(cmdlib, [ --enable-cmdlib Build shared command library],
|
||||
CMDLIB=$enableval, CMDLIB=no)
|
||||
AC_MSG_RESULT($CMDLIB)
|
||||
|
||||
if test x$CMDLIB = xyes; then
|
||||
CFLAGS="$CFLAGS -DCMDLIB"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable fsadm
|
||||
AC_MSG_CHECKING(whether to build fsadm)
|
||||
AC_ARG_ENABLE(fsadm, [ --enable-fsadm Enable fsadm],
|
||||
FSADM=$enableval)
|
||||
AC_MSG_RESULT($FSADM)
|
||||
|
||||
################################################################################
|
||||
dnl -- Mess with default exec_prefix
|
||||
if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
|
||||
then exec_prefix="";
|
||||
fi;
|
||||
|
||||
dnl Checks for library functions.
|
||||
################################################################################
|
||||
dnl -- Checks for library functions.
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
AC_TYPE_SIGNAL
|
||||
AC_FUNC_VPRINTF
|
||||
AC_CHECK_FUNCS(mkdir rmdir uname)
|
||||
AC_CHECK_FUNCS(mkdir rmdir uname,,AC_MSG_ERROR(bailing out))
|
||||
|
||||
dnl check for termcap (Shamelessly copied from parted 1.4.17)
|
||||
################################################################################
|
||||
dnl -- Check for termcap (Shamelessly copied from parted 1.4.17)
|
||||
if test x$READLINE = xyes; then
|
||||
AC_SEARCH_LIBS(tgetent, ncurses curses termcap termlib, ,
|
||||
AC_MSG_ERROR(
|
||||
@@ -95,11 +376,51 @@ Note: if you are using precompiled packages you will also need the development
|
||||
Note: (n)curses also seems to work as a substitute for termcap. This was
|
||||
not found either - but you could try installing that as well.
|
||||
)
|
||||
exit
|
||||
)
|
||||
fi
|
||||
|
||||
dnl Check for readline (Shamelessly copied from parted 1.4.17)
|
||||
################################################################################
|
||||
dnl -- Check for dlopen
|
||||
AC_CHECK_LIB(dl, dlopen, HAVE_LIBDL=yes, HAVE_LIBDL=no)
|
||||
|
||||
if [[ "x$HAVE_LIBDL" = xyes -a "x$STATIC_LINK" = xno ]]; then
|
||||
CFLAGS="$CFLAGS -DHAVE_LIBDL"
|
||||
LIBS="-ldl $LIBS"
|
||||
else
|
||||
HAVE_LIBDL=no
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for shared/static conflicts
|
||||
if [[ \( "x$LVM1" = xshared -o "x$POOL" = xshared -o "x$CLUSTER" = xshared \
|
||||
-o "x$SNAPSHOTS" = xshared -o "x$MIRRORS" = xshared \
|
||||
\) -a "x$STATIC_LINK" = xyes ]];
|
||||
then AC_MSG_ERROR(
|
||||
Features cannot be 'shared' when building statically
|
||||
)
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for is_selinux_enabled
|
||||
if test x$SELINUX = xyes; then
|
||||
AC_MSG_CHECKING(for is_selinux_enabled function)
|
||||
AC_CHECK_LIB(selinux, is_selinux_enabled, HAVE_SELINUX=yes, HAVE_SELINUX=no)
|
||||
AC_MSG_RESULT($HAVE_SELINUX)
|
||||
|
||||
if test x$HAVE_SELINUX = xyes; then
|
||||
CFLAGS="$CFLAGS -DHAVE_SELINUX"
|
||||
LIBS="-lselinux $LIBS"
|
||||
else
|
||||
AC_MSG_WARN(Disabling selinux)
|
||||
fi
|
||||
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)
|
||||
if test x$READLINE = xyes; then
|
||||
AC_CHECK_LIB(readline, readline, ,
|
||||
AC_MSG_ERROR(
|
||||
@@ -110,39 +431,158 @@ support with --disable-readline or download and install readline from:
|
||||
Note: if you are using precompiled packages you will also need the development
|
||||
package as well (which may be called readline-devel or something similar).
|
||||
)
|
||||
exit
|
||||
)
|
||||
AC_CHECK_FUNC(rl_completion_matches, HAVE_RL_COMPLETION_MATCHES=yes,
|
||||
HAVE_RL_COMPLETION_MATCHES=no)
|
||||
AC_CHECK_FUNC(rl_completion_matches, CFLAGS="$CFLAGS -DHAVE_RL_COMPLETION_MATCHES")
|
||||
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Internationalisation stuff
|
||||
AC_MSG_CHECKING(whether to enable internationalisation)
|
||||
AC_ARG_ENABLE(nls, [ --enable-nls Enable Native Language Support],
|
||||
INTL=$enableval, INTL=no)
|
||||
AC_MSG_RESULT($INTL)
|
||||
|
||||
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
|
||||
)
|
||||
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' ])
|
||||
|
||||
################################################################################
|
||||
dnl -- Ensure additional headers required
|
||||
if test x$READLINE = xyes; then
|
||||
AC_CHECK_HEADERS(readline/readline.h readline/history.h,,AC_MSG_ERROR(bailing out))
|
||||
fi
|
||||
|
||||
if test x$CLVMD = xyes; then
|
||||
AC_CHECK_HEADERS(mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h,,AC_MSG_ERROR(bailing out))
|
||||
AC_CHECK_FUNCS(dup2 getmntent memmove select socket,,AC_MSG_ERROR(bailing out))
|
||||
AC_FUNC_GETMNTENT
|
||||
# AC_FUNC_REALLOC
|
||||
AC_FUNC_SELECT_ARGTYPES
|
||||
fi
|
||||
|
||||
if test x$FSADM = xyes; then
|
||||
AC_CHECK_HEADERS(fstab.h sys/mount.h sys/vfs.h,,AC_MSG_ERROR(bailing out))
|
||||
AC_CHECK_FUNCS(memmove,,AC_MSG_ERROR(bailing out))
|
||||
fi
|
||||
|
||||
if test x$CLUSTER != xnone; then
|
||||
AC_CHECK_HEADERS(sys/socket.h sys/un.h,,AC_MSG_ERROR(bailing out))
|
||||
AC_CHECK_FUNCS(socket,,AC_MSG_ERROR(bailing out))
|
||||
fi
|
||||
|
||||
if test x$HAVE_LIBDL = xyes; then
|
||||
AC_CHECK_HEADERS(dlfcn.h,,AC_MSG_ERROR(bailing out))
|
||||
fi
|
||||
|
||||
if test x$INTL = xyes; then
|
||||
AC_CHECK_HEADERS(libintl.h,,AC_MSG_ERROR(bailing out))
|
||||
fi
|
||||
|
||||
if test x$DEVMAPPER = xyes; then
|
||||
AC_CHECK_HEADERS(libdevmapper.h,,AC_MSG_ERROR(bailing out))
|
||||
fi
|
||||
|
||||
if test x$HAVE_SELINUX = xyes; then
|
||||
AC_CHECK_HEADERS(selinux/selinux.h,,AC_MSG_ERROR(bailing out))
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
if test "-f VERSION"; then
|
||||
LVM_VERSION="\"`cat VERSION`\""
|
||||
else
|
||||
LVM_VERSION="Unknown"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
AC_SUBST(JOBS)
|
||||
AC_SUBST(STATIC_LINK)
|
||||
AC_SUBST(READLINE)
|
||||
AC_SUBST(HAVE_RL_COMPLETION_MATCHES)
|
||||
AC_SUBST(LVM1)
|
||||
AC_SUBST(POOL)
|
||||
AC_SUBST(SNAPSHOTS)
|
||||
AC_SUBST(MIRRORS)
|
||||
AC_SUBST(OWNER)
|
||||
AC_SUBST(GROUP)
|
||||
AC_SUBST(CFLAGS)
|
||||
AC_SUBST(COPTIMISE_FLAG)
|
||||
AC_SUBST(CLDFLAGS)
|
||||
AC_SUBST(CLDWHOLEARCHIVE)
|
||||
AC_SUBST(CLDNOWHOLEARCHIVE)
|
||||
AC_SUBST(LDDEPS)
|
||||
AC_SUBST(LDFLAGS)
|
||||
AC_SUBST(SOFLAG)
|
||||
AC_SUBST(LIBS)
|
||||
AC_SUBST(LVM_VERSION)
|
||||
dnl First and last lines should not contain files to generate in order to
|
||||
dnl keep utility scripts running properly
|
||||
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)
|
||||
AC_SUBST(CLVMD)
|
||||
AC_SUBST(CLUSTER)
|
||||
AC_SUBST(FSADM)
|
||||
|
||||
################################################################################
|
||||
dnl -- First and last lines should not contain files to generate in order to
|
||||
dnl -- keep utility scripts running properly
|
||||
AC_OUTPUT( \
|
||||
Makefile \
|
||||
make.tmpl \
|
||||
make.tmpl \
|
||||
daemons/Makefile \
|
||||
daemons/clvmd/Makefile \
|
||||
doc/Makefile \
|
||||
include/Makefile \
|
||||
lib/Makefile \
|
||||
lib/format1/Makefile \
|
||||
lib/format_pool/Makefile \
|
||||
lib/locking/Makefile \
|
||||
lib/mirror/Makefile \
|
||||
lib/snapshot/Makefile \
|
||||
man/Makefile \
|
||||
po/Makefile \
|
||||
tools/Makefile \
|
||||
tools/version.h \
|
||||
tools/fsadm/Makefile \
|
||||
test/mm/Makefile \
|
||||
test/device/Makefile \
|
||||
test/format1/Makefile \
|
||||
test/regex/Makefile \
|
||||
test/filters/Makefile \
|
||||
)
|
||||
|
||||
if test x$ODIRECT != xyes; then
|
||||
AC_MSG_WARN(Warning: O_DIRECT disabled: low-memory pvmove may lock up)
|
||||
fi
|
||||
|
||||
if test x$FSADM == xyes; then
|
||||
AC_MSG_WARN(fsadm support is untested)
|
||||
fi
|
||||
|
||||
23
daemons/Makefile.in
Normal file
23
daemons/Makefile.in
Normal file
@@ -0,0 +1,23 @@
|
||||
#
|
||||
# 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@
|
||||
|
||||
ifeq ("@CLVMD@", "yes")
|
||||
SUBDIRS = clvmd
|
||||
endif
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
49
daemons/clvmd/Makefile.in
Normal file
49
daemons/clvmd/Makefile.in
Normal file
@@ -0,0 +1,49 @@
|
||||
#
|
||||
# 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 = \
|
||||
clvmd-cman.c \
|
||||
clvmd-command.c \
|
||||
clvmd.c \
|
||||
libclvm.c \
|
||||
lvm-functions.c \
|
||||
system-lv.c
|
||||
|
||||
TARGETS = \
|
||||
clvmd
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
CFLAGS += -D_REENTRANT -fno-strict-aliasing
|
||||
LIBS += -ldevmapper -ldlm -llvm -lpthread
|
||||
|
||||
INSTALL_TARGETS = \
|
||||
install_clvmd
|
||||
|
||||
clvmd: $(OBJECTS) $(top_srcdir)/lib/liblvm.a
|
||||
$(CC) -o clvmd $(OBJECTS) $(LDFLAGS) $(LVMLIBS) $(LIBS)
|
||||
|
||||
.PHONY: install_clvmd
|
||||
|
||||
install_clvmd: $(TARGETS)
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) clvmd \
|
||||
$(sbindir)/clvmd
|
||||
|
||||
install: $(INSTALL_TARGETS)
|
||||
|
||||
install_cluster: $(INSTALL_TARGETS)
|
||||
|
||||
65
daemons/clvmd/clvm.h
Normal file
65
daemons/clvmd/clvm.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* Definitions for CLVMD server and clients */
|
||||
|
||||
/*
|
||||
* The protocol spoken over the cluster and across the local socket.
|
||||
*/
|
||||
|
||||
#ifndef _CLVM_H
|
||||
#define _CLVM_H
|
||||
|
||||
struct clvm_header {
|
||||
uint8_t cmd; /* See below */
|
||||
uint8_t flags; /* See below */
|
||||
uint16_t xid; /* Transaction ID */
|
||||
uint32_t clientid; /* Only used in Daemon->Daemon comms */
|
||||
int32_t status; /* For replies, whether request succeeded */
|
||||
uint32_t arglen; /* Length of argument below.
|
||||
If >1500 then it will be passed
|
||||
around the cluster in the system LV */
|
||||
char node[1]; /* Actually a NUL-terminated string, node name.
|
||||
If this is empty then the command is
|
||||
forwarded to all cluster nodes unless
|
||||
FLAG_LOCAL is also set. */
|
||||
char args[1]; /* Arguments for the command follow the
|
||||
node name, This member is only
|
||||
valid if the node name is empty */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Flags */
|
||||
#define CLVMD_FLAG_LOCAL 1 /* Only do this on the local node */
|
||||
#define CLVMD_FLAG_SYSTEMLV 2 /* Data in system LV under my node name */
|
||||
|
||||
/* Name of the local socket to communicate between libclvm and clvmd */
|
||||
//static const char CLVMD_SOCKNAME[]="/var/run/clvmd";
|
||||
static const char CLVMD_SOCKNAME[] = "\0clvmd";
|
||||
|
||||
/* Internal commands & replies */
|
||||
#define CLVMD_CMD_REPLY 1
|
||||
#define CLVMD_CMD_VERSION 2 /* Send version around cluster when we start */
|
||||
#define CLVMD_CMD_GOAWAY 3 /* Die if received this - we are running
|
||||
an incompatible version */
|
||||
#define CLVMD_CMD_TEST 4 /* Just for mucking about */
|
||||
|
||||
#define CLVMD_CMD_LOCK 30
|
||||
#define CLVMD_CMD_UNLOCK 31
|
||||
|
||||
/* Lock/Unlock commands */
|
||||
#define CLVMD_CMD_LOCK_LV 50
|
||||
#define CLVMD_CMD_LOCK_VG 51
|
||||
|
||||
#endif
|
||||
499
daemons/clvmd/clvmd-cman.c
Normal file
499
daemons/clvmd/clvmd-cman.c
Normal file
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* CMAN communication layer for clvmd.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <syslog.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvm.h"
|
||||
#include "libdlm.h"
|
||||
#include "log.h"
|
||||
#include "clvmd.h"
|
||||
#include "lvm-functions.h"
|
||||
|
||||
#define LOCKSPACE_NAME "clvmd"
|
||||
|
||||
static int cluster_sock;
|
||||
static int num_nodes;
|
||||
static struct cl_cluster_node *nodes = NULL;
|
||||
static int count_nodes; /* size of allocated nodes array */
|
||||
static int max_updown_nodes = 50; /* Current size of the allocated array */
|
||||
/* Node up/down status, indexed by nodeid */
|
||||
static int *node_updown = NULL;
|
||||
static dlm_lshandle_t *lockspace;
|
||||
|
||||
static void sigusr1_handler(int sig);
|
||||
static void count_clvmds_running(void);
|
||||
static void get_members(void);
|
||||
static int nodeid_from_csid(char *csid);
|
||||
static int name_from_nodeid(int nodeid, char *name);
|
||||
|
||||
struct lock_wait {
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
struct dlm_lksb lksb;
|
||||
};
|
||||
|
||||
int init_cluster()
|
||||
{
|
||||
struct sockaddr_cl saddr;
|
||||
int port = CLUSTER_PORT_CLVMD;
|
||||
|
||||
/* Open the cluster communication socket */
|
||||
cluster_sock = socket(AF_CLUSTER, SOCK_DGRAM, CLPROTO_CLIENT);
|
||||
if (cluster_sock == -1) {
|
||||
perror("Can't open cluster socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Bind to our port number on the cluster.
|
||||
Writes to this will block if the cluster loses quorum */
|
||||
saddr.scl_family = AF_CLUSTER;
|
||||
saddr.scl_port = port;
|
||||
|
||||
if (bind
|
||||
(cluster_sock, (struct sockaddr *) &saddr,
|
||||
sizeof(struct sockaddr_cl))) {
|
||||
log_error("Can't bind cluster socket: %m");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the cluster members list */
|
||||
get_members();
|
||||
count_clvmds_running();
|
||||
|
||||
/* Create a lockspace for LV & VG locks to live in */
|
||||
lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
|
||||
if (!lockspace) {
|
||||
log_error("Unable to create lockspace for CLVM\n");
|
||||
return -1;
|
||||
}
|
||||
dlm_ls_pthread_init(lockspace);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_main_cluster_fd()
|
||||
{
|
||||
return cluster_sock;
|
||||
}
|
||||
|
||||
int get_num_nodes()
|
||||
{
|
||||
return num_nodes;
|
||||
}
|
||||
|
||||
/* send_message with the fd check removed */
|
||||
int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
struct msghdr msg;
|
||||
struct sockaddr_cl saddr;
|
||||
int len = 0;
|
||||
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_flags = 0;
|
||||
iov[0].iov_len = msglen;
|
||||
iov[0].iov_base = buf;
|
||||
|
||||
saddr.scl_family = AF_CLUSTER;
|
||||
saddr.scl_port = CLUSTER_PORT_CLVMD;
|
||||
if (csid) {
|
||||
msg.msg_name = &saddr;
|
||||
msg.msg_namelen = sizeof(saddr);
|
||||
memcpy(&saddr.scl_nodeid, csid, MAX_CSID_LEN);
|
||||
} else { /* Cluster broadcast */
|
||||
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
}
|
||||
|
||||
do {
|
||||
len = sendmsg(cluster_sock, &msg, 0);
|
||||
if (len < 0 && errno != EAGAIN)
|
||||
log_error(errtext);
|
||||
|
||||
} while (len == -1 && errno == EAGAIN);
|
||||
return len;
|
||||
}
|
||||
|
||||
void get_our_csid(char *csid)
|
||||
{
|
||||
int i;
|
||||
memset(csid, 0, MAX_CSID_LEN);
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (nodes[i].us)
|
||||
memcpy(csid, &nodes[i].node_id, MAX_CSID_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
/* Call a callback routine for each node that known (down mean not running a clvmd) */
|
||||
int cluster_do_node_callback(struct local_client *client,
|
||||
void (*callback) (struct local_client *, char *,
|
||||
int))
|
||||
{
|
||||
int i;
|
||||
int somedown = 0;
|
||||
|
||||
for (i = 0; i < get_num_nodes(); i++) {
|
||||
callback(client, (char *)&nodes[i].node_id, node_updown[nodes[i].node_id]);
|
||||
if (!node_updown[nodes[i].node_id])
|
||||
somedown = -1;
|
||||
}
|
||||
return somedown;
|
||||
}
|
||||
|
||||
/* Process OOB message from the cluster socket,
|
||||
this currently just means that a node has stopped listening on our port */
|
||||
static void process_oob_msg(char *buf, int len, int nodeid)
|
||||
{
|
||||
char namebuf[256];
|
||||
switch (buf[0]) {
|
||||
case CLUSTER_OOB_MSG_PORTCLOSED:
|
||||
name_from_nodeid(nodeid, namebuf);
|
||||
log_notice("clvmd on node %s has died\n", namebuf);
|
||||
DEBUGLOG("Got OOB message, removing node %s\n", namebuf);
|
||||
|
||||
node_updown[nodeid] = 0;
|
||||
break;
|
||||
|
||||
case CLUSTER_OOB_MSG_STATECHANGE:
|
||||
DEBUGLOG("Got OOB message, Cluster state change\n");
|
||||
get_members();
|
||||
break;
|
||||
default:
|
||||
/* ERROR */
|
||||
DEBUGLOG("Got unknown OOB message: %d\n", buf[0]);
|
||||
}
|
||||
}
|
||||
|
||||
int cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
struct msghdr msg;
|
||||
struct sockaddr_cl saddr;
|
||||
|
||||
/* We never return a new client */
|
||||
*new_client = NULL;
|
||||
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_name = &saddr;
|
||||
msg.msg_flags = 0;
|
||||
msg.msg_namelen = sizeof(saddr);
|
||||
iov[0].iov_len = len;
|
||||
iov[0].iov_base = buf;
|
||||
|
||||
len = recvmsg(cluster_sock, &msg, MSG_OOB | O_NONBLOCK);
|
||||
if (len < 0 && errno == EAGAIN)
|
||||
return len;
|
||||
|
||||
DEBUGLOG("Read on cluster socket, len = %d\n", len);
|
||||
|
||||
/* A real error */
|
||||
if (len < 0) {
|
||||
log_error("read error on cluster socket: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* EOF - we have left the cluster */
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
/* Is it OOB? probably a node gone down */
|
||||
if (msg.msg_flags & MSG_OOB) {
|
||||
process_oob_msg(iov[0].iov_base, len, saddr.scl_nodeid);
|
||||
|
||||
/* Tell the upper layer to ignore this message */
|
||||
len = -1;
|
||||
errno = EAGAIN;
|
||||
}
|
||||
memcpy(csid, &saddr.scl_nodeid, sizeof(saddr.scl_nodeid));
|
||||
return len;
|
||||
}
|
||||
|
||||
void add_up_node(char *csid)
|
||||
{
|
||||
/* It's up ! */
|
||||
int nodeid = nodeid_from_csid(csid);
|
||||
|
||||
if (nodeid >= max_updown_nodes) {
|
||||
int *new_updown = realloc(node_updown, max_updown_nodes + 10);
|
||||
|
||||
if (new_updown) {
|
||||
node_updown = new_updown;
|
||||
max_updown_nodes += 10;
|
||||
DEBUGLOG("realloced more space for nodes. now %d\n",
|
||||
max_updown_nodes);
|
||||
} else {
|
||||
log_error
|
||||
("Realloc failed. Node status for clvmd will be wrong\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
node_updown[nodeid] = 1;
|
||||
DEBUGLOG("Added new node %d to updown list\n", nodeid);
|
||||
}
|
||||
|
||||
void cluster_closedown()
|
||||
{
|
||||
unlock_all();
|
||||
dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
|
||||
close(cluster_sock);
|
||||
}
|
||||
|
||||
static int is_listening(int nodeid)
|
||||
{
|
||||
struct cl_listen_request rq;
|
||||
int status;
|
||||
|
||||
rq.port = CLUSTER_PORT_CLVMD;
|
||||
rq.nodeid = nodeid;
|
||||
|
||||
do {
|
||||
status = ioctl(cluster_sock, SIOCCLUSTER_ISLISTENING, &rq);
|
||||
if (status < 0 && errno == EBUSY) { /* Don't busywait */
|
||||
sleep(1);
|
||||
errno = EBUSY; /* In case sleep trashes it */
|
||||
}
|
||||
}
|
||||
while (status < 0 && errno == EBUSY);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Populate the list of CLVMDs running.
|
||||
called only at startup time */
|
||||
void count_clvmds_running(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
node_updown[nodes[i].node_id] = is_listening(nodes[i].node_id);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get a list of active cluster members */
|
||||
static void get_members()
|
||||
{
|
||||
struct cl_cluster_nodelist nodelist;
|
||||
|
||||
num_nodes = ioctl(cluster_sock, SIOCCLUSTER_GETMEMBERS, 0);
|
||||
if (num_nodes == -1) {
|
||||
perror("get nodes");
|
||||
} else {
|
||||
/* Not enough room for new nodes list ? */
|
||||
if (num_nodes > count_nodes && nodes) {
|
||||
free(nodes);
|
||||
nodes = NULL;
|
||||
}
|
||||
|
||||
if (nodes == NULL) {
|
||||
count_nodes = num_nodes + 10; /* Overallocate a little */
|
||||
nodes = malloc(count_nodes * sizeof(struct cl_cluster_node));
|
||||
if (!nodes) {
|
||||
perror("Unable to allocate nodes array\n");
|
||||
exit(5);
|
||||
}
|
||||
}
|
||||
nodelist.max_members = count_nodes;
|
||||
nodelist.nodes = nodes;
|
||||
|
||||
num_nodes = ioctl(cluster_sock, SIOCCLUSTER_GETMEMBERS, &nodelist);
|
||||
if (num_nodes <= 0) {
|
||||
perror("get node details");
|
||||
exit(6);
|
||||
}
|
||||
|
||||
/* Sanity check struct */
|
||||
if (nodes[0].size != sizeof(struct cl_cluster_node)) {
|
||||
log_error
|
||||
("sizeof(cl_cluster_node) does not match size returned from the kernel: aborting\n");
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (node_updown == NULL) {
|
||||
node_updown =
|
||||
(int *) malloc(sizeof(int) *
|
||||
max(num_nodes, max_updown_nodes));
|
||||
memset(node_updown, 0,
|
||||
sizeof(int) * max(num_nodes, max_updown_nodes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert a node name to a CSID */
|
||||
int csid_from_name(char *csid, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (strcmp(name, nodes[i].name) == 0) {
|
||||
memcpy(csid, &nodes[i].node_id, MAX_CSID_LEN);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert a CSID to a node name */
|
||||
int name_from_csid(char *csid, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (memcmp(csid, &nodes[i].node_id, MAX_CSID_LEN) == 0) {
|
||||
strcpy(name, nodes[i].name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Who?? */
|
||||
strcpy(name, "Unknown");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert a node ID to a node name */
|
||||
int name_from_nodeid(int nodeid, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (nodeid == nodes[i].node_id) {
|
||||
strcpy(name, nodes[i].name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Who?? */
|
||||
strcpy(name, "Unknown");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert a CSID to a node ID */
|
||||
static int nodeid_from_csid(char *csid)
|
||||
{
|
||||
int nodeid;
|
||||
|
||||
memcpy(&nodeid, csid, MAX_CSID_LEN);
|
||||
|
||||
return nodeid;
|
||||
}
|
||||
|
||||
int is_quorate()
|
||||
{
|
||||
return ioctl(cluster_sock, SIOCCLUSTER_ISQUORATE, 0);
|
||||
}
|
||||
|
||||
static void sync_ast_routine(void *arg)
|
||||
{
|
||||
struct lock_wait *lwait = arg;
|
||||
|
||||
pthread_mutex_lock(&lwait->mutex);
|
||||
pthread_cond_signal(&lwait->cond);
|
||||
pthread_mutex_unlock(&lwait->mutex);
|
||||
}
|
||||
|
||||
int sync_lock(const char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
int status;
|
||||
struct lock_wait lwait;
|
||||
|
||||
if (!lockid) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Conversions need the lockid in the LKSB */
|
||||
if (flags & LKF_CONVERT)
|
||||
lwait.lksb.sb_lkid = *lockid;
|
||||
|
||||
pthread_cond_init(&lwait.cond, NULL);
|
||||
pthread_mutex_init(&lwait.mutex, NULL);
|
||||
pthread_mutex_lock(&lwait.mutex);
|
||||
|
||||
status = dlm_ls_lock(lockspace,
|
||||
mode,
|
||||
&lwait.lksb,
|
||||
flags,
|
||||
resource,
|
||||
strlen(resource),
|
||||
0, sync_ast_routine, &lwait, NULL, NULL);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Wait for it to complete */
|
||||
pthread_cond_wait(&lwait.cond, &lwait.mutex);
|
||||
pthread_mutex_unlock(&lwait.mutex);
|
||||
|
||||
*lockid = lwait.lksb.sb_lkid;
|
||||
|
||||
errno = lwait.lksb.sb_status;
|
||||
if (lwait.lksb.sb_status)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sync_unlock(const char *resource /* UNUSED */, int lockid)
|
||||
{
|
||||
int status;
|
||||
struct lock_wait lwait;
|
||||
|
||||
pthread_cond_init(&lwait.cond, NULL);
|
||||
pthread_mutex_init(&lwait.mutex, NULL);
|
||||
pthread_mutex_lock(&lwait.mutex);
|
||||
|
||||
status = dlm_ls_unlock(lockspace, lockid, 0, &lwait.lksb, &lwait);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Wait for it to complete */
|
||||
pthread_cond_wait(&lwait.cond, &lwait.mutex);
|
||||
pthread_mutex_unlock(&lwait.mutex);
|
||||
|
||||
errno = lwait.lksb.sb_status;
|
||||
if (lwait.lksb.sb_status != EUNLOCK)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
}
|
||||
219
daemons/clvmd/clvmd-command.c
Normal file
219
daemons/clvmd/clvmd-command.c
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
CLVMD Cluster LVM daemon command processor.
|
||||
|
||||
To add commands to the daemon simply add a processor in do_command and return
|
||||
and messages back in buf and the length in *retlen. The initial value of
|
||||
buflen is the maximum size of the buffer. if buf is not large enough then it
|
||||
may be reallocated by the functions in here to a suitable size bearing in
|
||||
mind that anything larger than the passed-in size will have to be returned
|
||||
using the system LV and so performance will suffer.
|
||||
|
||||
The status return will be negated and passed back to the originating node.
|
||||
|
||||
pre- and post- command routines are called only on the local node. The
|
||||
purpose is primarily to get and release locks, though the pre- routine should
|
||||
also do any other local setups required by the command (if any) and can
|
||||
return a failure code that prevents the command from being distributed around
|
||||
the cluster
|
||||
|
||||
The pre- and post- routines are run in their own thread so can block as long
|
||||
they like, do_command is run in the main clvmd thread so should not block for
|
||||
too long. If the pre-command returns an error code (!=0) then the command
|
||||
will not be propogated around the cluster but the post-command WILL be called
|
||||
|
||||
Also note that the pre and post routine are *always* called on the local
|
||||
node, even if the command to be executed was only requested to run on a
|
||||
remote node. It may peek inside the client structure to check the status of
|
||||
the command.
|
||||
|
||||
The clients of the daemon must, naturally, understand the return messages and
|
||||
codes.
|
||||
|
||||
Routines in here may only READ the values in the client structure passed in
|
||||
apart from client->private which they are free to do what they like with.
|
||||
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "locking.h"
|
||||
#include "log.h"
|
||||
#include "lvm-functions.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd.h"
|
||||
#include "libdlm.h"
|
||||
|
||||
/* This is where all the real work happens:
|
||||
NOTE: client will be NULL when this is executed on a remote node */
|
||||
int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
|
||||
char **buf, int buflen, int *retlen)
|
||||
{
|
||||
char *args = msg->node + strlen(msg->node) + 1;
|
||||
int arglen = msglen - sizeof(struct clvm_header) - strlen(msg->node);
|
||||
int status = 0;
|
||||
char *lockname;
|
||||
struct utsname nodeinfo;
|
||||
unsigned char lock_cmd;
|
||||
unsigned char lock_flags;
|
||||
|
||||
/* Do the command */
|
||||
switch (msg->cmd) {
|
||||
/* Just a test message */
|
||||
case CLVMD_CMD_TEST:
|
||||
if (arglen > buflen) {
|
||||
buflen = arglen + 200;
|
||||
*buf = realloc(*buf, buflen);
|
||||
}
|
||||
uname(&nodeinfo);
|
||||
*retlen = 1 + snprintf(*buf, buflen, "TEST from %s: %s v%s",
|
||||
nodeinfo.nodename, args,
|
||||
nodeinfo.release);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_VG:
|
||||
/* Check to see if the VG is in use by LVM1 */
|
||||
status = do_check_lvm1(&args[2]);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_LV:
|
||||
/* This is the biggie */
|
||||
lock_cmd = args[0];
|
||||
lock_flags = args[1];
|
||||
lockname = &args[2];
|
||||
status = do_lock_lv(lock_cmd, lock_flags, lockname);
|
||||
/* Replace EIO with something less scary */
|
||||
if (status == EIO) {
|
||||
*retlen =
|
||||
1 + snprintf(*buf, buflen,
|
||||
"Internal lvm error, check syslog");
|
||||
return EIO;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Won't get here because command is validated in pre_command */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check the status of the command and return the error text */
|
||||
if (status) {
|
||||
*retlen = 1 + snprintf(*buf, buflen, strerror(status));
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
/* Pre-command is a good place to get locks that are needed only for the duration
|
||||
of the commands around the cluster (don't forget to free them in post-command),
|
||||
and to sanity check the command arguments */
|
||||
int do_pre_command(struct local_client *client)
|
||||
{
|
||||
struct clvm_header *header =
|
||||
(struct clvm_header *) client->bits.localsock.cmd;
|
||||
unsigned char lock_cmd;
|
||||
unsigned char lock_flags;
|
||||
char *args = header->node + strlen(header->node) + 1;
|
||||
int lockid;
|
||||
int status = 0;
|
||||
char *lockname;
|
||||
|
||||
switch (header->cmd) {
|
||||
case CLVMD_CMD_TEST:
|
||||
status = sync_lock("CLVMD_TEST", LKM_EXMODE, 0, &lockid);
|
||||
client->bits.localsock.private = (void *) lockid;
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_VG:
|
||||
lock_cmd = args[0];
|
||||
lock_flags = args[1];
|
||||
lockname = &args[2];
|
||||
DEBUGLOG("doing PRE command LOCK_VG %s at %x\n", lockname,
|
||||
lock_cmd);
|
||||
if (lock_cmd == LCK_UNLOCK) {
|
||||
hold_unlock(lockname);
|
||||
} else {
|
||||
status =
|
||||
hold_lock(lockname, (int) lock_cmd,
|
||||
(int) lock_flags);
|
||||
if (status)
|
||||
status = errno;
|
||||
}
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_LV:
|
||||
lock_cmd = args[0];
|
||||
lock_flags = args[1];
|
||||
lockname = &args[2];
|
||||
status = pre_lock_lv(lock_cmd, lock_flags, lockname);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("Unknown command %d received\n", header->cmd);
|
||||
status = EINVAL;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Note that the post-command routine is called even if the pre-command or the real command
|
||||
failed */
|
||||
int do_post_command(struct local_client *client)
|
||||
{
|
||||
struct clvm_header *header =
|
||||
(struct clvm_header *) client->bits.localsock.cmd;
|
||||
int status = 0;
|
||||
unsigned char lock_cmd;
|
||||
unsigned char lock_flags;
|
||||
char *args = header->node + strlen(header->node) + 1;
|
||||
char *lockname;
|
||||
|
||||
switch (header->cmd) {
|
||||
case CLVMD_CMD_TEST:
|
||||
status =
|
||||
sync_unlock("CLVMD_TEST", (int) (long) client->bits.localsock.private);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_VG:
|
||||
/* Nothing to do here */
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_LV:
|
||||
lock_cmd = args[0];
|
||||
lock_flags = args[1];
|
||||
lockname = &args[2];
|
||||
status = post_lock_lv(lock_cmd, lock_flags, lockname);
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
55
daemons/clvmd/clvmd-comms.h
Normal file
55
daemons/clvmd/clvmd-comms.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Abstraction layer for clvmd cluster communications
|
||||
*/
|
||||
|
||||
#ifndef _CLVMD_COMMS_H
|
||||
#define _CLVMD_COMMS_H
|
||||
|
||||
struct local_client;
|
||||
|
||||
extern int cluster_send_message(void *buf, int msglen, char *csid,
|
||||
const char *errtext);
|
||||
extern int name_from_csid(char *csid, char *name);
|
||||
extern int csid_from_name(char *csid, char *name);
|
||||
extern int get_num_nodes(void);
|
||||
extern int cluster_fd_callback(struct local_client *fd, char *buf, int len,
|
||||
char *csid, struct local_client **new_client);
|
||||
extern int init_cluster(void);
|
||||
extern int get_main_cluster_fd(void); /* gets accept FD or cman cluster socket */
|
||||
extern int cluster_do_node_callback(struct local_client *client,
|
||||
void (*callback) (struct local_client *,
|
||||
char *csid, int node_up));
|
||||
extern int is_quorate(void);
|
||||
|
||||
extern void get_our_csid(char *csid);
|
||||
extern void add_up_node(char *csid);
|
||||
extern void cluster_closedown(void);
|
||||
|
||||
extern int sync_lock(const char *resource, int mode, int flags, int *lockid);
|
||||
extern int sync_unlock(const char *resource, int lockid);
|
||||
|
||||
#ifdef USE_GULM
|
||||
#include "tcp-comms.h"
|
||||
#else
|
||||
/* cman */
|
||||
#include "cnxman-socket.h"
|
||||
#define MAX_CSID_LEN 4
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
880
daemons/clvmd/clvmd-gulm.c
Normal file
880
daemons/clvmd/clvmd-gulm.c
Normal file
@@ -0,0 +1,880 @@
|
||||
/******************************************************************************
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 2002-2003 All rights reserved.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
/* This provides the interface between clvmd and gulm as the cluster
|
||||
* and lock manager.
|
||||
*
|
||||
* It also provides the "liblm" functions too as it's hard (and pointless)
|
||||
* to seperate them out when using gulm.
|
||||
*
|
||||
* What it does /not/ provide is the communications between clvmd daemons
|
||||
* on the cluster nodes. That is done in tcp-comms.c
|
||||
*/
|
||||
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <utmpx.h>
|
||||
#include <syslog.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "ccs.h"
|
||||
#include "list.h"
|
||||
#include "locking.h"
|
||||
#include "log.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
#include "hash.h"
|
||||
#include "clvmd-gulm.h"
|
||||
#include "libgulm.h"
|
||||
#include "hash.h"
|
||||
|
||||
/* Hash list of nodes in the cluster */
|
||||
static struct hash_table *node_hash;
|
||||
|
||||
/* hash list of outstanding lock requests */
|
||||
static struct hash_table *lock_hash;
|
||||
|
||||
/* Copy of the current core state */
|
||||
static uint8_t current_corestate;
|
||||
|
||||
/* Number of active nodes */
|
||||
static int num_nodes;
|
||||
|
||||
static char *cluster_name;
|
||||
|
||||
static pthread_mutex_t lock_start_mutex;
|
||||
static volatile int lock_start_flag;
|
||||
|
||||
struct node_info
|
||||
{
|
||||
enum {NODE_UNKNOWN, NODE_DOWN, NODE_UP, NODE_CLVMD} state;
|
||||
char name[MAX_CLUSTER_MEMBER_NAME_LEN];
|
||||
};
|
||||
|
||||
struct lock_wait
|
||||
{
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
int status;
|
||||
};
|
||||
|
||||
/* Forward */
|
||||
static int read_from_core_sock(struct local_client *client, char *buf, int len, char *csid,
|
||||
struct local_client **new_client);
|
||||
static int read_from_lock_sock(struct local_client *client, char *buf, int len, char *csid,
|
||||
struct local_client **new_client);
|
||||
static int get_all_cluster_nodes(void);
|
||||
|
||||
/* In tcp-comms.c */
|
||||
extern struct hash_table *sock_hash;
|
||||
|
||||
static int add_internal_client(int fd, fd_callback_t callback)
|
||||
{
|
||||
struct local_client *client;
|
||||
|
||||
DEBUGLOG("Add_internal_client, fd = %d\n", fd);
|
||||
|
||||
/* Add a GULM file descriptor it to the main loop */
|
||||
client = malloc(sizeof(struct local_client));
|
||||
if (!client)
|
||||
{
|
||||
DEBUGLOG("malloc failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(client, 0, sizeof(struct local_client));
|
||||
client->fd = fd;
|
||||
client->type = CLUSTER_INTERNAL;
|
||||
client->callback = callback;
|
||||
add_client(client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Gulm library handle */
|
||||
static gulm_interface_p gulm_if;
|
||||
static lg_core_callbacks_t core_callbacks;
|
||||
static lg_lockspace_callbacks_t lock_callbacks;
|
||||
|
||||
static void badsig_handler(int sig)
|
||||
{
|
||||
DEBUGLOG("got sig %d\n", sig);
|
||||
cluster_closedown();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void sighup_handler(int sig)
|
||||
{
|
||||
DEBUGLOG("got SIGHUP\n");
|
||||
|
||||
/* Re-read CCS node list */
|
||||
get_all_cluster_nodes();
|
||||
}
|
||||
|
||||
int init_cluster()
|
||||
{
|
||||
int status;
|
||||
int ccs_h;
|
||||
|
||||
/* Get cluster name from CCS */
|
||||
/* TODO: is this right? */
|
||||
ccs_h = ccs_connect();
|
||||
ccs_get(ccs_h, "//cluster/@name", &cluster_name);
|
||||
ccs_disconnect(ccs_h);
|
||||
|
||||
/* Block locking until we are logged in */
|
||||
pthread_mutex_init(&lock_start_mutex, NULL);
|
||||
pthread_mutex_lock(&lock_start_mutex);
|
||||
lock_start_flag = 1;
|
||||
|
||||
node_hash = hash_create(100);
|
||||
lock_hash = hash_create(10);
|
||||
|
||||
/* Get all nodes from CCS */
|
||||
get_all_cluster_nodes();
|
||||
|
||||
/* Initialise GULM library */
|
||||
status = lg_initialize(&gulm_if, cluster_name, "clvmd");
|
||||
if (status)
|
||||
{
|
||||
DEBUGLOG("lg_initialize failed: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Connect to core - we are not "important" :-) */
|
||||
status = lg_core_login(gulm_if, 0);
|
||||
if (status)
|
||||
{
|
||||
DEBUGLOG("lg_core_login failed: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Initialise the inter-node comms */
|
||||
status = init_comms();
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Add core FD to the list */
|
||||
status = add_internal_client(lg_core_selector(gulm_if), read_from_core_sock);
|
||||
if (status)
|
||||
{
|
||||
DEBUGLOG("can't allocate client space\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Connect to the lock server */
|
||||
if (lg_lock_login(gulm_if, "CLVM"))
|
||||
{
|
||||
syslog(LOG_ERR, "Cannot login in to LOCK server\n");
|
||||
DEBUGLOG("Cannot login in to LOCK server\n");
|
||||
exit(88);
|
||||
}
|
||||
|
||||
/* Add lockspace FD to the list */
|
||||
status = add_internal_client(lg_lock_selector(gulm_if), read_from_lock_sock);
|
||||
if (status)
|
||||
{
|
||||
DEBUGLOG("can't allocate client space\n");
|
||||
exit(status);
|
||||
}
|
||||
|
||||
/* Request a list of nodes, we can;t really do anything until
|
||||
this comes back */
|
||||
status = lg_core_nodelist(gulm_if);
|
||||
if (status)
|
||||
{
|
||||
DEBUGLOG("lg_core_nodelist failed: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* So I can kill it without taking GULM down too */
|
||||
signal(SIGINT, badsig_handler);
|
||||
signal(SIGTERM, badsig_handler);
|
||||
|
||||
/* Re-read the node list on SIGHUP */
|
||||
signal(SIGHUP, sighup_handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cluster_closedown()
|
||||
{
|
||||
DEBUGLOG("cluster_closedown\n");
|
||||
lg_lock_logout(gulm_if);
|
||||
lg_core_logout(gulm_if);
|
||||
lg_core_shutdown(gulm_if);
|
||||
lg_release(gulm_if);
|
||||
}
|
||||
|
||||
/* Expire locks for a named node, or us */
|
||||
#define GIO_KEY_SIZE 46
|
||||
static void drop_expired_locks(char *nodename)
|
||||
{
|
||||
struct utsname nodeinfo;
|
||||
uint8_t mask[GIO_KEY_SIZE];
|
||||
|
||||
memset(mask, 0xff, GIO_KEY_SIZE);
|
||||
|
||||
if (!nodename)
|
||||
{
|
||||
uname(&nodeinfo);
|
||||
nodename = nodeinfo.nodename;
|
||||
}
|
||||
|
||||
if (lg_lock_drop_exp(gulm_if, nodename, mask, GIO_KEY_SIZE))
|
||||
{
|
||||
DEBUGLOG("Error calling lg_lock_drop_exp()\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int read_from_core_sock(struct local_client *client, char *buf, int len, char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
int status;
|
||||
|
||||
*new_client = NULL;
|
||||
status = lg_core_handle_messages(gulm_if, &core_callbacks, NULL);
|
||||
return status<0 ? status : 1;
|
||||
}
|
||||
|
||||
static int read_from_lock_sock(struct local_client *client, char *buf, int len, char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
int status;
|
||||
|
||||
*new_client = NULL;
|
||||
status = lg_lock_handle_messages(gulm_if, &lock_callbacks, NULL);
|
||||
return status<0 ? status : 1;
|
||||
}
|
||||
|
||||
|
||||
/* CORE callback routines */
|
||||
static int core_login_reply(void *misc, uint64_t gen, uint32_t error, uint32_t rank, uint8_t corestate)
|
||||
{
|
||||
DEBUGLOG("CORE Got a Login reply. gen:%lld err:%d rank:%d corestate:%d\n",
|
||||
gen, error, rank, corestate);
|
||||
|
||||
if (error)
|
||||
exit(error);
|
||||
|
||||
current_corestate = corestate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_node_state(struct node_info *ninfo, char *csid, uint8_t nodestate)
|
||||
{
|
||||
if (nodestate == lg_core_Logged_in)
|
||||
{
|
||||
/* Don't clobber NODE_CLVMD state */
|
||||
if (ninfo->state != NODE_CLVMD)
|
||||
{
|
||||
if (ninfo->state == NODE_UNKNOWN ||
|
||||
ninfo->state == NODE_DOWN)
|
||||
num_nodes++;
|
||||
|
||||
ninfo->state = NODE_UP;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nodestate == lg_core_Expired ||
|
||||
nodestate == lg_core_Fenced ||
|
||||
nodestate == lg_core_Logged_out)
|
||||
{
|
||||
if (ninfo->state != NODE_DOWN)
|
||||
num_nodes--;
|
||||
ninfo->state = NODE_DOWN;
|
||||
tcp_remove_client(csid);
|
||||
}
|
||||
}
|
||||
DEBUGLOG("set_node_state, '%s' state = %d, num_nodes=%d\n",
|
||||
ninfo->name, ninfo->state, num_nodes);
|
||||
}
|
||||
|
||||
static struct node_info *add_or_set_node(char *name, uint32_t ip, uint8_t state)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = hash_lookup_binary(node_hash, (char *)&ip, MAX_CSID_LEN);
|
||||
if (!ninfo)
|
||||
{
|
||||
/* If we can't find that node then re-read the config file in case it
|
||||
was added after we were started */
|
||||
DEBUGLOG("Node %s not found, re-reading config file\n", name);
|
||||
get_all_cluster_nodes();
|
||||
|
||||
/* Now try again */
|
||||
ninfo = hash_lookup_binary(node_hash, (char *)&ip, MAX_CSID_LEN);
|
||||
if (!ninfo)
|
||||
{
|
||||
DEBUGLOG("Ignoring node %s, not part of the SAN cluster\n", name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
set_node_state(ninfo, (char *)&ip, state);
|
||||
|
||||
return ninfo;
|
||||
}
|
||||
|
||||
static int core_nodelist(void *misc, lglcb_t type, char *name, uint32_t ip, uint8_t state)
|
||||
{
|
||||
DEBUGLOG("CORE nodelist\n");
|
||||
|
||||
if (type == lglcb_start)
|
||||
{
|
||||
DEBUGLOG("Got Nodelist, start\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type == lglcb_item)
|
||||
{
|
||||
DEBUGLOG("Got nodelist, item: %s, %#x, %#x\n", name, ip, state);
|
||||
|
||||
add_or_set_node(name, ip, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type == lglcb_stop)
|
||||
{
|
||||
char ourcsid[MAX_CSID_LEN];
|
||||
|
||||
DEBUGLOG("Got Nodelist, stop\n");
|
||||
clvmd_cluster_init_completed();
|
||||
|
||||
/* Mark ourself as up */
|
||||
get_our_csid(ourcsid);
|
||||
add_up_node(ourcsid);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGLOG("Unknown lglcb_t %#x\n", type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int core_statechange(void *misc, uint8_t corestate, uint32_t masterip, char *mastername)
|
||||
{
|
||||
DEBUGLOG("CORE Got statechange corestate:%#x masterip:%#x mastername:%s\n",
|
||||
corestate, masterip, mastername);
|
||||
|
||||
current_corestate = corestate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int core_nodechange(void *misc, char *nodename, uint32_t nodeip, uint8_t nodestate)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
DEBUGLOG("CORE node change, name=%s, ip=%x, state = %d\n", nodename, nodeip, nodestate);
|
||||
|
||||
/* If we don't get nodeip here, try a lookup by name */
|
||||
if (!nodeip)
|
||||
csid_from_name((char *)&nodeip, nodename);
|
||||
if (!nodeip)
|
||||
return 0;
|
||||
|
||||
ninfo = add_or_set_node(nodename, nodeip, nodestate);
|
||||
if (!ninfo)
|
||||
return 0;
|
||||
|
||||
/* Check if we need to drop any expired locks */
|
||||
if (ninfo->state == NODE_DOWN)
|
||||
{
|
||||
drop_expired_locks(nodename);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int core_error(void *misc, uint32_t err)
|
||||
{
|
||||
DEBUGLOG("CORE error: %d\n", err);
|
||||
// Not sure what happens here
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* LOCK callback routines */
|
||||
static int lock_login_reply(void *misc, uint32_t error, uint8_t which)
|
||||
{
|
||||
DEBUGLOG("LOCK Got a Login reply. err:%d which:%d\n",
|
||||
error, which);
|
||||
|
||||
if (error)
|
||||
exit(error);
|
||||
|
||||
/* Drop any expired locks for us that might be hanging around */
|
||||
drop_expired_locks(NULL);
|
||||
|
||||
/* Enable locking operations in other threads */
|
||||
if (lock_start_flag)
|
||||
{
|
||||
lock_start_flag = 0;
|
||||
pthread_mutex_unlock(&lock_start_mutex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lock_lock_state(void *misc, uint8_t *key, uint16_t keylen, uint8_t state, uint32_t flags, uint32_t error,
|
||||
uint8_t *LVB, uint16_t LVBlen)
|
||||
{
|
||||
struct lock_wait *lwait;
|
||||
|
||||
DEBUGLOG("LOCK lock state: %s, error = %d\n", key, error);
|
||||
|
||||
lwait = hash_lookup(lock_hash, key);
|
||||
if (!lwait)
|
||||
{
|
||||
DEBUGLOG("Can't find hash entry for resource %s\n", key);
|
||||
return 0;
|
||||
}
|
||||
lwait->status = error;
|
||||
pthread_mutex_lock(&lwait->mutex);
|
||||
pthread_cond_signal(&lwait->cond);
|
||||
pthread_mutex_unlock(&lwait->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int lock_error(void *misc, uint32_t err)
|
||||
{
|
||||
DEBUGLOG("LOCK error: %d\n", err);
|
||||
// Not sure what happens here
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* CORE callbacks */
|
||||
static lg_core_callbacks_t core_callbacks = {
|
||||
.login_reply = core_login_reply,
|
||||
.nodelist = core_nodelist,
|
||||
.statechange = core_statechange,
|
||||
.nodechange = core_nodechange,
|
||||
.error = core_error,
|
||||
};
|
||||
|
||||
/* LOCK callbacks */
|
||||
static lg_lockspace_callbacks_t lock_callbacks = {
|
||||
.login_reply = lock_login_reply,
|
||||
.lock_state = lock_lock_state,
|
||||
.error = lock_error,
|
||||
};
|
||||
|
||||
/* Allow tcp-comms to loop round the list of active nodes */
|
||||
int get_next_node_csid(void **context, char *csid)
|
||||
{
|
||||
struct node_info *ninfo = NULL;
|
||||
|
||||
/* First node */
|
||||
if (!*context)
|
||||
{
|
||||
*context = hash_get_first(node_hash);
|
||||
}
|
||||
else
|
||||
{
|
||||
*context = hash_get_next(node_hash, *context);
|
||||
}
|
||||
if (*context)
|
||||
ninfo = hash_get_data(node_hash, *context);
|
||||
|
||||
/* Find a node that is UP */
|
||||
while (*context && ninfo->state == NODE_DOWN)
|
||||
{
|
||||
*context = hash_get_next(node_hash, *context);
|
||||
if (*context)
|
||||
{
|
||||
ninfo = hash_get_data(node_hash, *context);
|
||||
}
|
||||
}
|
||||
|
||||
if (!*context || ninfo->state == NODE_DOWN)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(csid, hash_get_key(node_hash, *context), MAX_CSID_LEN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int name_from_csid(char *csid, char *name)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = hash_lookup_binary(node_hash, csid, MAX_CSID_LEN);
|
||||
if (!ninfo)
|
||||
{
|
||||
sprintf(name, "UNKNOWN [%d.%d.%d.%d]",
|
||||
csid[0], csid[1], csid[2], csid[3]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(name, ninfo->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int csid_from_name(char *csid, char *name)
|
||||
{
|
||||
struct hash_node *hn;
|
||||
struct node_info *ninfo;
|
||||
|
||||
hash_iterate(hn, node_hash)
|
||||
{
|
||||
ninfo = hash_get_data(node_hash, hn);
|
||||
if (strcmp(ninfo->name, name) == 0)
|
||||
{
|
||||
memcpy(csid, hash_get_key(node_hash, hn), MAX_CSID_LEN);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int get_num_nodes()
|
||||
{
|
||||
DEBUGLOG("num_nodes = %d\n", num_nodes);
|
||||
return num_nodes;
|
||||
}
|
||||
|
||||
/* Node is now known to be running a clvmd */
|
||||
void add_up_node(char *csid)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = hash_lookup_binary(node_hash, csid, MAX_CSID_LEN);
|
||||
if (!ninfo)
|
||||
return;
|
||||
|
||||
ninfo->state = NODE_CLVMD;
|
||||
return;
|
||||
|
||||
}
|
||||
/* Node is now known to be NOT running a clvmd */
|
||||
void add_down_node(char *csid)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = hash_lookup_binary(node_hash, csid, MAX_CSID_LEN);
|
||||
if (!ninfo)
|
||||
return;
|
||||
|
||||
/* Only set it to UP if it was previously known to be
|
||||
running clvmd - gulm may set it DOWN quite soon */
|
||||
if (ninfo->state == NODE_CLVMD)
|
||||
ninfo->state = NODE_UP;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* Call a callback for each node, so the caller knows whether it's up or down */
|
||||
int cluster_do_node_callback(struct local_client *master_client,
|
||||
void (*callback)(struct local_client *, char *csid, int node_up))
|
||||
{
|
||||
struct hash_node *hn;
|
||||
struct node_info *ninfo;
|
||||
|
||||
hash_iterate(hn, node_hash)
|
||||
{
|
||||
char csid[MAX_CSID_LEN];
|
||||
struct local_client *client;
|
||||
|
||||
ninfo = hash_get_data(node_hash, hn);
|
||||
memcpy(csid, hash_get_key(node_hash, hn), MAX_CSID_LEN);
|
||||
|
||||
DEBUGLOG("down_callback. node %s, state = %d\n", ninfo->name, ninfo->state);
|
||||
|
||||
client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
|
||||
if (client)
|
||||
callback(master_client, csid, ninfo->state == NODE_CLVMD);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert gulm error codes to unix errno numbers */
|
||||
static int gulm_to_errno(int gulm_ret)
|
||||
{
|
||||
switch (gulm_ret)
|
||||
{
|
||||
case lg_err_TryFailed:
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
|
||||
case lg_err_AlreadyPend:
|
||||
errno = EBUSY;
|
||||
|
||||
/* More?? */
|
||||
default:
|
||||
errno = EINVAL;
|
||||
}
|
||||
|
||||
return gulm_ret ? -1 : 0;
|
||||
}
|
||||
|
||||
/* Real locking */
|
||||
static int _lock_resource(char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
int status;
|
||||
struct lock_wait lwait;
|
||||
|
||||
/* Wait until the lock module is ready */
|
||||
if (lock_start_flag)
|
||||
{
|
||||
pthread_mutex_lock(&lock_start_mutex);
|
||||
pthread_mutex_unlock(&lock_start_mutex);
|
||||
}
|
||||
|
||||
pthread_cond_init(&lwait.cond, NULL);
|
||||
pthread_mutex_init(&lwait.mutex, NULL);
|
||||
pthread_mutex_lock(&lwait.mutex);
|
||||
|
||||
/* This needs to be converted from DLM/LVM2 value for GULM */
|
||||
if (flags == LCK_NONBLOCK) flags = lg_lock_flag_Try;
|
||||
|
||||
hash_insert(lock_hash, resource, &lwait);
|
||||
DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
|
||||
|
||||
status = lg_lock_state_req(gulm_if, resource, strlen(resource)+1,
|
||||
mode, flags, NULL, 0);
|
||||
if (status)
|
||||
{
|
||||
DEBUGLOG("lg_lock_state returned %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Wait for it to complete */
|
||||
pthread_cond_wait(&lwait.cond, &lwait.mutex);
|
||||
pthread_mutex_unlock(&lwait.mutex);
|
||||
|
||||
hash_remove(lock_hash, resource);
|
||||
DEBUGLOG("lock-resource returning %d\n", lwait.status);
|
||||
|
||||
return gulm_to_errno(lwait.status);
|
||||
}
|
||||
|
||||
|
||||
static int _unlock_resource(char *resource, int lockid)
|
||||
{
|
||||
int status;
|
||||
struct lock_wait lwait;
|
||||
|
||||
pthread_cond_init(&lwait.cond, NULL);
|
||||
pthread_mutex_init(&lwait.mutex, NULL);
|
||||
pthread_mutex_lock(&lwait.mutex);
|
||||
|
||||
hash_insert(lock_hash, resource, &lwait);
|
||||
|
||||
DEBUGLOG("unlock_resource %s\n", resource);
|
||||
status = lg_lock_state_req(gulm_if, resource, strlen(resource)+1,
|
||||
lg_lock_state_Unlock, 0, NULL, 0);
|
||||
|
||||
if (status)
|
||||
{
|
||||
DEBUGLOG("lg_lock_state(unlock) returned %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Wait for it to complete */
|
||||
|
||||
pthread_cond_wait(&lwait.cond, &lwait.mutex);
|
||||
pthread_mutex_unlock(&lwait.mutex);
|
||||
|
||||
hash_remove(lock_hash, resource);
|
||||
|
||||
return gulm_to_errno(lwait.status);
|
||||
}
|
||||
|
||||
|
||||
/* These two locking functions MUST be called in a seperate thread from
|
||||
the clvmd main loop because they expect to be woken up by it.
|
||||
|
||||
These are abstractions around the real locking functions (above)
|
||||
as we need to emulate the DLM's EX/PW/CW interaction with GULM using
|
||||
two locks.
|
||||
To aid unlocking, we store the lock mode in the lockid (as GULM
|
||||
doesn't use this).
|
||||
*/
|
||||
int sync_lock(const char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
int status;
|
||||
char lock1[strlen(resource)+3];
|
||||
char lock2[strlen(resource)+3];
|
||||
|
||||
snprintf(lock1, sizeof(lock1), "%s-1", resource);
|
||||
snprintf(lock2, sizeof(lock2), "%s-2", resource);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case LCK_EXCL:
|
||||
status = _lock_resource(lock1, lg_lock_state_Exclusive, flags, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
/* If we can't get this lock then bail out */
|
||||
status = _lock_resource(lock2, lg_lock_state_Exclusive, LCK_NONBLOCK, lockid);
|
||||
if (status == lg_err_TryFailed)
|
||||
{
|
||||
_unlock_resource(lock1, *lockid);
|
||||
status = -1;
|
||||
errno = EAGAIN;
|
||||
}
|
||||
break;
|
||||
|
||||
case LCK_READ:
|
||||
status = _lock_resource(lock1, lg_lock_state_Shared, flags, lockid);
|
||||
break;
|
||||
|
||||
case LCK_WRITE:
|
||||
status = _lock_resource(lock2, lg_lock_state_Exclusive, flags, lockid);
|
||||
break;
|
||||
|
||||
default:
|
||||
status = -1;
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
out:
|
||||
*lockid = mode;
|
||||
return status;
|
||||
}
|
||||
|
||||
int sync_unlock(const char *resource, int lockid)
|
||||
{
|
||||
int status = 0;
|
||||
char lock1[strlen(resource)+3];
|
||||
char lock2[strlen(resource)+3];
|
||||
|
||||
snprintf(lock1, sizeof(lock1), "%s-1", resource);
|
||||
snprintf(lock2, sizeof(lock2), "%s-2", resource);
|
||||
|
||||
/* The held lock mode is in the lock id */
|
||||
assert(lockid == LCK_EXCL ||
|
||||
lockid == LCK_READ ||
|
||||
lockid == LCK_WRITE);
|
||||
|
||||
switch (lockid)
|
||||
{
|
||||
case LCK_EXCL:
|
||||
status = _unlock_resource(lock1, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
status = _unlock_resource(lock2, lockid);
|
||||
break;
|
||||
|
||||
case LCK_READ:
|
||||
status = _unlock_resource(lock1, lockid);
|
||||
break;
|
||||
|
||||
case LCK_WRITE:
|
||||
status = _unlock_resource(lock2, lockid);
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
int is_quorate()
|
||||
{
|
||||
if (current_corestate == lg_core_Slave ||
|
||||
current_corestate == lg_core_Master ||
|
||||
current_corestate == lg_core_Client)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get all the cluster node names & IPs from CCS and
|
||||
add them to our node list so we know who to talk to.
|
||||
Called when we start up and if we get sent SIGHUP.
|
||||
*/
|
||||
static int get_all_cluster_nodes()
|
||||
{
|
||||
int ctree;
|
||||
char *nodename;
|
||||
int error;
|
||||
|
||||
/* Open the config file */
|
||||
ctree = ccs_connect();
|
||||
if (ctree <= 0)
|
||||
{
|
||||
log_error("Error connecting to CCS");
|
||||
return -1;
|
||||
}
|
||||
|
||||
error = ccs_get(ctree, "//nodes/node/@name", &nodename);
|
||||
while (nodename)
|
||||
{
|
||||
char nodeip[MAX_CSID_LEN];
|
||||
char *clvmflag;
|
||||
char key[256];
|
||||
|
||||
sprintf(key, "//nodes/node[@name=\"%s\"]/clvm", nodename);
|
||||
ccs_get(ctree, key, &clvmflag);
|
||||
|
||||
if ((get_ip_address(nodename, nodeip) == 0) && atoi(clvmflag))
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
/* If it's not in the list, then add it */
|
||||
ninfo = hash_lookup_binary(node_hash, nodeip, MAX_CSID_LEN);
|
||||
if (!ninfo)
|
||||
{
|
||||
ninfo = malloc(sizeof(struct node_info));
|
||||
if (!ninfo)
|
||||
{
|
||||
syslog(LOG_ERR, "Cannot alloc memory for node info\n");
|
||||
ccs_disconnect(ctree);
|
||||
return -1;
|
||||
}
|
||||
strcpy(ninfo->name, nodename);
|
||||
|
||||
ninfo->state = NODE_DOWN;
|
||||
hash_insert_binary(node_hash, nodeip, MAX_CSID_LEN, ninfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGLOG("node %s has clvm disabled\n", nodename);
|
||||
}
|
||||
if (clvmflag) free(clvmflag);
|
||||
free(nodename);
|
||||
error = ccs_get(ctree, "//nodes/node/@name", &nodename);
|
||||
}
|
||||
|
||||
/* Finished with config file */
|
||||
ccs_disconnect(ctree);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gulm_fd(void)
|
||||
{
|
||||
return lg_core_selector(gulm_if);
|
||||
}
|
||||
9
daemons/clvmd/clvmd-gulm.h
Normal file
9
daemons/clvmd/clvmd-gulm.h
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
|
||||
|
||||
extern int get_next_node_csid(void **context, char *csid);
|
||||
extern void add_down_node(char *csid);
|
||||
extern int gulm_fd(void);
|
||||
extern int get_ip_address(char *node, char *addr);
|
||||
extern void tcp_remove_client(char *csid);
|
||||
extern int alloc_client(int fd, char *csid, struct local_client **new_client);
|
||||
1693
daemons/clvmd/clvmd.c
Normal file
1693
daemons/clvmd/clvmd.c
Normal file
File diff suppressed because it is too large
Load Diff
119
daemons/clvmd/clvmd.h
Normal file
119
daemons/clvmd/clvmd.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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 _CLVMD_H
|
||||
#define _CLVMD_H
|
||||
|
||||
#define CLVMD_MAJOR_VERSION 0
|
||||
#define CLVMD_MINOR_VERSION 2
|
||||
#define CLVMD_PATCH_VERSION 1
|
||||
|
||||
/* Name of the cluster LVM admin lock */
|
||||
#define ADMIN_LOCK_NAME "CLVMD_ADMIN"
|
||||
|
||||
/* Default time (in seconds) we will wait for all remote commands to execute
|
||||
before declaring them dead */
|
||||
#define DEFAULT_CMD_TIMEOUT 60
|
||||
|
||||
/* One of these for each reply we get from command execution on a node */
|
||||
struct node_reply {
|
||||
char node[MAX_CLUSTER_MEMBER_NAME_LEN];
|
||||
char *replymsg;
|
||||
int status;
|
||||
struct node_reply *next;
|
||||
};
|
||||
|
||||
/*
|
||||
* These exist for the use of local sockets only when we are
|
||||
* collecting responses from all cluster nodes
|
||||
*/
|
||||
struct localsock_bits {
|
||||
struct node_reply *replies;
|
||||
int num_replies;
|
||||
int expected_replies;
|
||||
time_t sent_time; /* So we can check for timeouts */
|
||||
int in_progress; /* Only execute one cmd at a time per client */
|
||||
int sent_out; /* Flag to indicate that a command was sent
|
||||
to remote nodes */
|
||||
void *private; /* Private area for command processor use */
|
||||
void *cmd; /* Whole command as passed down local socket */
|
||||
int cmd_len; /* Length of above */
|
||||
int pipe; /* Pipe to send PRE completion status down */
|
||||
int finished; /* Flag to tell subthread to exit */
|
||||
int all_success; /* Set to 0 if any node (or the pre_command)
|
||||
failed */
|
||||
struct local_client *pipe_client;
|
||||
pthread_t threadid;
|
||||
enum { PRE_COMMAND, POST_COMMAND, QUIT } state;
|
||||
pthread_mutex_t mutex; /* Main thread and worker synchronisation */
|
||||
pthread_cond_t cond;
|
||||
|
||||
pthread_mutex_t reply_mutex; /* Protect reply structure */
|
||||
};
|
||||
|
||||
/* Entries for PIPE clients */
|
||||
struct pipe_bits {
|
||||
struct local_client *client; /* Actual (localsock) client */
|
||||
pthread_t threadid; /* Our own copy of the thread id */
|
||||
};
|
||||
|
||||
/* Entries for Network socket clients */
|
||||
struct netsock_bits {
|
||||
void *private;
|
||||
int flags;
|
||||
};
|
||||
|
||||
typedef int (*fd_callback_t) (struct local_client * fd, char *buf, int len,
|
||||
char *csid, struct local_client ** new_client);
|
||||
|
||||
/* One of these for each fd we are listening on */
|
||||
struct local_client {
|
||||
int fd;
|
||||
enum { CLUSTER_MAIN_SOCK, CLUSTER_DATA_SOCK, LOCAL_RENDEZVOUS,
|
||||
LOCAL_SOCK, THREAD_PIPE, CLUSTER_INTERNAL } type;
|
||||
struct local_client *next;
|
||||
unsigned short xid;
|
||||
fd_callback_t callback;
|
||||
|
||||
union {
|
||||
struct localsock_bits localsock;
|
||||
struct pipe_bits pipe;
|
||||
struct netsock_bits net;
|
||||
} bits;
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUGLOG(fmt, args...) fprintf(stderr, "CLVMD[%d]: %ld ", getpid(), time(NULL) ); fprintf(stderr, fmt, ## args)
|
||||
#else
|
||||
#define DEBUGLOG(fmt, args...)
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
/* The real command processor is in clvmd-command.c */
|
||||
extern int do_command(struct local_client *client, struct clvm_header *msg,
|
||||
int msglen, char **buf, int buflen, int *retlen);
|
||||
|
||||
/* Pre and post command routines are called only on the local node */
|
||||
extern int do_pre_command(struct local_client *client);
|
||||
extern int do_post_command(struct local_client *client);
|
||||
|
||||
extern int add_client(struct local_client *new_client);
|
||||
|
||||
extern void clvmd_cluster_init_completed(void);
|
||||
|
||||
#endif
|
||||
225
daemons/clvmd/cnxman-socket.h
Normal file
225
daemons/clvmd/cnxman-socket.h
Normal file
@@ -0,0 +1,225 @@
|
||||
/******************************************************************************
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
||||
** Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
/* CMAN socket interface header,
|
||||
may be include by user or kernel code */
|
||||
|
||||
#ifndef __CNXMAN_SOCKET_H
|
||||
#define __CNXMAN_SOCKET_H
|
||||
|
||||
/* A currently unused number. TIPC also uses this number and you're unlikely
|
||||
to be using both.
|
||||
*/
|
||||
#define AF_CLUSTER 30
|
||||
#define PF_CLUSTER AF_CLUSTER
|
||||
|
||||
/* Protocol(socket) types */
|
||||
#define CLPROTO_MASTER 2
|
||||
#define CLPROTO_CLIENT 3
|
||||
|
||||
/* ioctls -- should register these properly */
|
||||
#define SIOCCLUSTER_NOTIFY _IOW('x', 0x01, int)
|
||||
#define SIOCCLUSTER_REMOVENOTIFY _IO( 'x', 0x02)
|
||||
#define SIOCCLUSTER_GETMEMBERS _IOR('x', 0x03, struct cl_cluster_nodelist)
|
||||
#define SIOCCLUSTER_SETEXPECTED_VOTES _IOW('x', 0x04, int)
|
||||
#define SIOCCLUSTER_ISQUORATE _IO( 'x', 0x05)
|
||||
#define SIOCCLUSTER_ISLISTENING _IOW('x', 0x06, struct cl_listen_request)
|
||||
#define SIOCCLUSTER_GETALLMEMBERS _IOR('x', 0x07, struct cl_cluster_nodelist)
|
||||
#define SIOCCLUSTER_SET_VOTES _IOW('x', 0x08, int)
|
||||
#define SIOCCLUSTER_GET_VERSION _IOR('x', 0x09, struct cl_version)
|
||||
#define SIOCCLUSTER_SET_VERSION _IOW('x', 0x0a, struct cl_version)
|
||||
#define SIOCCLUSTER_ISACTIVE _IO( 'x', 0x0b)
|
||||
#define SIOCCLUSTER_KILLNODE _IOW('x', 0x0c, int)
|
||||
#define SIOCCLUSTER_GET_JOINCOUNT _IO( 'x', 0x0d)
|
||||
#define SIOCCLUSTER_SERVICE_REGISTER _IOW('x', 0x0e, char)
|
||||
#define SIOCCLUSTER_SERVICE_UNREGISTER _IO('x', 0x0f)
|
||||
#define SIOCCLUSTER_SERVICE_JOIN _IO( 'x', 0x10)
|
||||
#define SIOCCLUSTER_SERVICE_LEAVE _IO( 'x', 0x20)
|
||||
#define SIOCCLUSTER_SERVICE_SETSIGNAL _IOW('x', 0x30, int)
|
||||
#define SIOCCLUSTER_SERVICE_STARTDONE _IOW('x', 0x40, unsigned int)
|
||||
#define SIOCCLUSTER_SERVICE_GETEVENT _IOR('x', 0x50, struct cl_service_event)
|
||||
#define SIOCCLUSTER_SERVICE_GETMEMBERS _IOR('x', 0x60, struct cl_cluster_nodelist)
|
||||
#define SIOCCLUSTER_SERVICE_GLOBALID _IOR('x', 0x70, uint32_t)
|
||||
#define SIOCCLUSTER_SERVICE_SETLEVEL _IOR('x', 0x80, int)
|
||||
#define SIOCCLUSTER_GETNODE _IOWR('x', 0x90, struct cl_cluster_node)
|
||||
#define SIOCCLUSTER_BARRIER _IOW('x', 0x0a0, struct cl_barrier_info)
|
||||
|
||||
/* These were setsockopts */
|
||||
#define SIOCCLUSTER_PASS_SOCKET _IOW('x', 0x0b0, struct cl_passed_sock)
|
||||
#define SIOCCLUSTER_SET_NODENAME _IOW('x', 0x0b1, char *)
|
||||
#define SIOCCLUSTER_SET_NODEID _IOW('x', 0x0b2, int)
|
||||
#define SIOCCLUSTER_JOIN_CLUSTER _IOW('x', 0x0b3, struct cl_join_cluster_info)
|
||||
#define SIOCCLUSTER_LEAVE_CLUSTER _IOW('x', 0x0b4, int)
|
||||
|
||||
|
||||
/* Maximum size of a cluster message */
|
||||
#define MAX_CLUSTER_MESSAGE 1500
|
||||
#define MAX_CLUSTER_MEMBER_NAME_LEN 255
|
||||
#define MAX_BARRIER_NAME_LEN 33
|
||||
#define MAX_SA_ADDR_LEN 12
|
||||
#define MAX_CLUSTER_NAME_LEN 16
|
||||
|
||||
/* Well-known cluster port numbers */
|
||||
#define CLUSTER_PORT_MEMBERSHIP 1 /* Mustn't block during cluster
|
||||
* transitions! */
|
||||
#define CLUSTER_PORT_SERVICES 2
|
||||
#define CLUSTER_PORT_SYSMAN 10 /* Remote execution daemon */
|
||||
#define CLUSTER_PORT_CLVMD 11 /* Cluster LVM daemon */
|
||||
#define CLUSTER_PORT_SLM 12 /* LVM SLM (simple lock manager) */
|
||||
|
||||
/* Port numbers above this will be blocked when the cluster is inquorate or in
|
||||
* transition */
|
||||
#define HIGH_PROTECTED_PORT 9
|
||||
|
||||
/* Reasons for leaving the cluster */
|
||||
#define CLUSTER_LEAVEFLAG_DOWN 0 /* Normal shutdown */
|
||||
#define CLUSTER_LEAVEFLAG_KILLED 1
|
||||
#define CLUSTER_LEAVEFLAG_PANIC 2
|
||||
#define CLUSTER_LEAVEFLAG_REMOVED 3 /* This one can reduce quorum */
|
||||
#define CLUSTER_LEAVEFLAG_REJECTED 4 /* Not allowed into the cluster in the
|
||||
* first place */
|
||||
#define CLUSTER_LEAVEFLAG_INCONSISTENT 5 /* Our view of the cluster is
|
||||
* in a minority */
|
||||
#define CLUSTER_LEAVEFLAG_DEAD 6 /* Discovered to be dead */
|
||||
#define CLUSTER_LEAVEFLAG_FORCE 0x10 /* Forced by command-line */
|
||||
|
||||
/* OOB messages sent to a local socket */
|
||||
#define CLUSTER_OOB_MSG_PORTCLOSED 1
|
||||
#define CLUSTER_OOB_MSG_STATECHANGE 2
|
||||
#define CLUSTER_OOB_MSG_SERVICEEVENT 3
|
||||
|
||||
/* Sendmsg flags, these are above the normal sendmsg flags so they don't
|
||||
* interfere */
|
||||
#define MSG_NOACK 0x010000 /* Don't need an ACK for this message */
|
||||
#define MSG_QUEUE 0x020000 /* Queue the message for sending later */
|
||||
#define MSG_MULTICAST 0x080000 /* Message was sent to all nodes in the cluster
|
||||
*/
|
||||
#define MSG_ALLINT 0x100000 /* Send out of all interfaces */
|
||||
|
||||
typedef enum { NODESTATE_REMOTEMEMBER, NODESTATE_JOINING, NODESTATE_MEMBER,
|
||||
NODESTATE_DEAD } nodestate_t;
|
||||
|
||||
|
||||
struct sockaddr_cl {
|
||||
unsigned short scl_family;
|
||||
unsigned char scl_flags;
|
||||
unsigned char scl_port;
|
||||
int scl_nodeid;
|
||||
};
|
||||
|
||||
/*
|
||||
* This is how we pass the multicast & receive sockets into kernel space.
|
||||
*/
|
||||
struct cl_passed_sock {
|
||||
int fd; /* FD of master socket to do multicast on */
|
||||
int number; /* Socket number, to match up recvonly & bcast
|
||||
* sockets */
|
||||
int multicast; /* Is it multicast or receive ? */
|
||||
};
|
||||
|
||||
/* Cluster configuration info passed when we join the cluster */
|
||||
struct cl_join_cluster_info {
|
||||
unsigned char votes;
|
||||
unsigned int expected_votes;
|
||||
unsigned int two_node;
|
||||
unsigned int config_version;
|
||||
|
||||
char cluster_name[17];
|
||||
};
|
||||
|
||||
|
||||
/* This is the structure, per node, returned from the membership ioctl */
|
||||
struct cl_cluster_node {
|
||||
unsigned int size;
|
||||
unsigned int node_id;
|
||||
unsigned int us;
|
||||
unsigned int leave_reason;
|
||||
unsigned int incarnation;
|
||||
nodestate_t state;
|
||||
char name[MAX_CLUSTER_MEMBER_NAME_LEN];
|
||||
unsigned char votes;
|
||||
};
|
||||
|
||||
/* The struct passed to the membership ioctls */
|
||||
struct cl_cluster_nodelist {
|
||||
uint32_t max_members;
|
||||
struct cl_cluster_node *nodes;
|
||||
};
|
||||
|
||||
/* Structure passed to SIOCCLUSTER_ISLISTENING */
|
||||
struct cl_listen_request {
|
||||
unsigned char port;
|
||||
int nodeid;
|
||||
};
|
||||
|
||||
/* A Cluster PORTCLOSED message - received by a local user as an OOB message */
|
||||
struct cl_portclosed_oob {
|
||||
unsigned char cmd; /* CLUSTER_OOB_MSG_PORTCLOSED */
|
||||
unsigned char port;
|
||||
};
|
||||
|
||||
/* Get all version numbers or set the config version */
|
||||
struct cl_version {
|
||||
unsigned int major;
|
||||
unsigned int minor;
|
||||
unsigned int patch;
|
||||
unsigned int config;
|
||||
};
|
||||
|
||||
/* structure passed to barrier ioctls */
|
||||
struct cl_barrier_info {
|
||||
char cmd;
|
||||
char name[MAX_BARRIER_NAME_LEN];
|
||||
unsigned int flags;
|
||||
unsigned long arg;
|
||||
};
|
||||
|
||||
typedef enum { SERVICE_EVENT_STOP, SERVICE_EVENT_START, SERVICE_EVENT_FINISH,
|
||||
SERVICE_EVENT_LEAVEDONE } service_event_t;
|
||||
|
||||
typedef enum { SERVICE_START_FAILED, SERVICE_START_JOIN, SERVICE_START_LEAVE }
|
||||
service_start_t;
|
||||
|
||||
struct cl_service_event {
|
||||
service_event_t type;
|
||||
service_start_t start_type;
|
||||
unsigned int event_id;
|
||||
unsigned int last_stop;
|
||||
unsigned int last_start;
|
||||
unsigned int last_finish;
|
||||
unsigned int node_count;
|
||||
};
|
||||
|
||||
|
||||
/* Commands to the barrier ioctl */
|
||||
#define BARRIER_IOCTL_REGISTER 1
|
||||
#define BARRIER_IOCTL_CHANGE 2
|
||||
#define BARRIER_IOCTL_DELETE 3
|
||||
#define BARRIER_IOCTL_WAIT 4
|
||||
|
||||
/* Attributes of a barrier - bitmask */
|
||||
#define BARRIER_ATTR_AUTODELETE 1
|
||||
#define BARRIER_ATTR_MULTISTEP 2
|
||||
#define BARRIER_ATTR_MANUAL 4
|
||||
#define BARRIER_ATTR_ENABLED 8
|
||||
#define BARRIER_ATTR_CALLBACK 16
|
||||
|
||||
/* Attribute setting commands */
|
||||
#define BARRIER_SETATTR_AUTODELETE 1
|
||||
#define BARRIER_SETATTR_MULTISTEP 2
|
||||
#define BARRIER_SETATTR_ENABLED 3
|
||||
#define BARRIER_SETATTR_NODES 4
|
||||
#define BARRIER_SETATTR_CALLBACK 5
|
||||
#define BARRIER_SETATTR_TIMEOUT 6
|
||||
|
||||
#endif
|
||||
446
daemons/clvmd/libclvm.c
Normal file
446
daemons/clvmd/libclvm.c
Normal file
@@ -0,0 +1,446 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* library functions for Cluster LVM Daemon */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <syslog.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <search.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "clvm.h"
|
||||
#include "libclvm.h"
|
||||
|
||||
/* CLVM in hex! */
|
||||
#define LVM_SIGNATURE 0x434C564D
|
||||
|
||||
#define MAX_CLUSTER_MEMBER_NAME_LEN 255
|
||||
|
||||
/* NOTE: the LVMD uses the socket FD as the client ID, this means
|
||||
that any client that calls fork() will inherit the context of
|
||||
it's parent. */
|
||||
static int clvmd_sock = -1;
|
||||
|
||||
static int open_local_sock(void)
|
||||
{
|
||||
int local_socket;
|
||||
struct sockaddr_un sockaddr;
|
||||
|
||||
/* Open local socket */
|
||||
local_socket = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (local_socket < 0) {
|
||||
perror("Can't create local socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fcntl(local_socket, F_SETFD, !FD_CLOEXEC);
|
||||
|
||||
strcpy(sockaddr.sun_path, CLVMD_SOCKNAME);
|
||||
sockaddr.sun_family = AF_UNIX;
|
||||
if (connect
|
||||
(local_socket, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) {
|
||||
int saved_errno = errno;
|
||||
|
||||
close(local_socket);
|
||||
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
return local_socket;
|
||||
}
|
||||
|
||||
/* Send a request and return the status */
|
||||
static int send_request(char *inbuf, int inlen, char **retbuf)
|
||||
{
|
||||
char outbuf[PIPE_BUF];
|
||||
struct clvm_header *outheader = (struct clvm_header *) outbuf;
|
||||
int len;
|
||||
int off;
|
||||
fd_set fds;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(clvmd_sock, &fds);
|
||||
|
||||
/* Send it to CLVMD */
|
||||
if (write(clvmd_sock, inbuf, inlen) != inlen) {
|
||||
perror("Error writing to CLVMD");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the response */
|
||||
if ((len = read(clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) {
|
||||
perror("Error reading CLVMD");
|
||||
return -1;
|
||||
}
|
||||
if (len == 0) {
|
||||
fprintf(stderr, "EOF reading CLVMD");
|
||||
errno = ENOTCONN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allocate buffer */
|
||||
*retbuf = malloc(len + outheader->arglen);
|
||||
if (!*retbuf) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Copy the header */
|
||||
memcpy(*retbuf, outbuf, len);
|
||||
outheader = (struct clvm_header *) *retbuf;
|
||||
|
||||
/* Read the returned values */
|
||||
off = 1; /* we've already read the first byte */
|
||||
|
||||
while (off < outheader->arglen && len > 0) {
|
||||
len = read(clvmd_sock, outheader->args + off, PIPE_BUF);
|
||||
if (len > 0)
|
||||
off += len;
|
||||
}
|
||||
|
||||
/* Was it an error ? */
|
||||
if (outheader->status < 0) {
|
||||
errno = -outheader->status;
|
||||
return -2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Build the structure header and parse-out wildcard node names */
|
||||
static void build_header(struct clvm_header *head, int cmd, const char *node,
|
||||
void *data, int len)
|
||||
{
|
||||
head->cmd = cmd;
|
||||
head->status = 0;
|
||||
head->flags = 0;
|
||||
head->clientid = 0;
|
||||
head->arglen = len;
|
||||
if (node) {
|
||||
/* Allow a couple of special node names:
|
||||
"*" for all nodes,
|
||||
"." for the local node only
|
||||
*/
|
||||
if (strcmp(node, "*") == 0) {
|
||||
head->node[0] = '\0';
|
||||
} else if (strcmp(node, ".") == 0) {
|
||||
head->node[0] = '\0';
|
||||
head->flags = CLVMD_FLAG_LOCAL;
|
||||
} else {
|
||||
strcpy(head->node, node);
|
||||
}
|
||||
} else {
|
||||
head->node[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Send a message to a(or all) node(s) in the cluster */
|
||||
int lvm_cluster_write(char cmd, char *node, void *data, int len)
|
||||
{
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
|
||||
char *retbuf = NULL;
|
||||
int status;
|
||||
struct clvm_header *head = (struct clvm_header *) outbuf;
|
||||
|
||||
if (clvmd_sock == -1)
|
||||
clvmd_sock = open_local_sock();
|
||||
if (clvmd_sock == -1)
|
||||
return -1;
|
||||
|
||||
build_header(head, cmd, node, data, len);
|
||||
memcpy(head->node + strlen(head->node) + 1, data, len);
|
||||
|
||||
status =
|
||||
send_request(outbuf,
|
||||
sizeof(struct clvm_header) + strlen(head->node) + len,
|
||||
&retbuf);
|
||||
if (retbuf)
|
||||
free(retbuf);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* API: Send a message to a(or all) node(s) in the cluster
|
||||
and wait for replies */
|
||||
int lvm_cluster_request(char cmd, const char *node, void *data, int len,
|
||||
lvm_response_t ** response, int *num)
|
||||
{
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
|
||||
int *outptr;
|
||||
char *inptr;
|
||||
char *retbuf = NULL;
|
||||
int status;
|
||||
int i;
|
||||
int num_responses = 0;
|
||||
struct clvm_header *head = (struct clvm_header *) outbuf;
|
||||
lvm_response_t *rarray;
|
||||
|
||||
*num = 0;
|
||||
|
||||
if (clvmd_sock == -1)
|
||||
clvmd_sock = open_local_sock();
|
||||
if (clvmd_sock == -1)
|
||||
return -1;
|
||||
|
||||
build_header(head, cmd, node, data, len);
|
||||
memcpy(head->node + strlen(head->node) + 1, data, len);
|
||||
|
||||
status =
|
||||
send_request(outbuf,
|
||||
sizeof(struct clvm_header) + strlen(head->node) + len,
|
||||
&retbuf);
|
||||
if (status == 0 || status == -2) {
|
||||
/* Count the number of responses we got */
|
||||
head = (struct clvm_header *) retbuf;
|
||||
inptr = head->args;
|
||||
while (inptr[0]) {
|
||||
num_responses++;
|
||||
inptr += strlen(inptr) + 1;
|
||||
inptr += sizeof(int);
|
||||
inptr += strlen(inptr) + 1;
|
||||
}
|
||||
|
||||
/* Allocate response array. With an extra pair of INTs on the front to sanity
|
||||
check the pointer when we are given it back to free */
|
||||
outptr =
|
||||
malloc(sizeof(lvm_response_t) * num_responses +
|
||||
sizeof(int) * 2);
|
||||
if (!outptr) {
|
||||
if (retbuf)
|
||||
free(retbuf);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*response = (lvm_response_t *) (outptr + 2);
|
||||
outptr[0] = LVM_SIGNATURE;
|
||||
outptr[1] = num_responses;
|
||||
rarray = *response;
|
||||
|
||||
/* Unpack the response into an lvm_response_t array */
|
||||
inptr = head->args;
|
||||
i = 0;
|
||||
while (inptr[0]) {
|
||||
strcpy(rarray[i].node, inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
|
||||
rarray[i].status = *(int *) inptr;
|
||||
inptr += sizeof(int);
|
||||
|
||||
rarray[i].response = malloc(strlen(inptr) + 1);
|
||||
if (rarray[i].response == NULL) {
|
||||
/* Free up everything else and return error */
|
||||
int j;
|
||||
for (j = 0; j < i; j++)
|
||||
free(rarray[i].response);
|
||||
free(outptr);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(rarray[i].response, inptr);
|
||||
rarray[i].len = strlen(inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
i++;
|
||||
}
|
||||
*num = num_responses;
|
||||
*response = rarray;
|
||||
}
|
||||
|
||||
if (retbuf)
|
||||
free(retbuf);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* API: Free reply array */
|
||||
int lvm_cluster_free_request(lvm_response_t * response)
|
||||
{
|
||||
int *ptr = (int *) response - 2;
|
||||
int i;
|
||||
int num;
|
||||
|
||||
/* Check it's ours to free */
|
||||
if (response == NULL || *ptr != LVM_SIGNATURE) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
num = ptr[1];
|
||||
for (i = 0; i < num; i++) {
|
||||
free(response[i].response);
|
||||
}
|
||||
free(ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* These are a "higher-level" API providing black-box lock/unlock
|
||||
functions for cluster LVM...maybe */
|
||||
|
||||
/* Set by lock(), used by unlock() */
|
||||
static int num_responses;
|
||||
static lvm_response_t *response;
|
||||
|
||||
int lvm_lock_for_cluster(char scope, char *name, int verbosity)
|
||||
{
|
||||
int status;
|
||||
int i;
|
||||
char *args;
|
||||
int len;
|
||||
|
||||
if (name) {
|
||||
len = strlen(name) + 2;
|
||||
args = alloca(len);
|
||||
strcpy(args + 1, name);
|
||||
} else {
|
||||
len = 2;
|
||||
args = alloca(len);
|
||||
args[1] = '\0';
|
||||
}
|
||||
args[0] = scope;
|
||||
|
||||
status = lvm_cluster_request(CLVMD_CMD_LOCK,
|
||||
"", args, len, &response, &num_responses);
|
||||
|
||||
/* If any nodes were down then display them and return an error */
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
if (response[i].status == -EHOSTDOWN) {
|
||||
if (verbosity)
|
||||
fprintf(stderr,
|
||||
"clvmd not running on node %s\n",
|
||||
response[i].node);
|
||||
status = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there was an error then free the memory now as the caller won't
|
||||
want to do the unlock */
|
||||
if (status) {
|
||||
int saved_errno = errno;
|
||||
lvm_cluster_free_request(response);
|
||||
num_responses = 0;
|
||||
errno = saved_errno;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int lvm_unlock_for_cluster(char scope, char *name, int verbosity)
|
||||
{
|
||||
int status;
|
||||
int i;
|
||||
int len;
|
||||
int failed;
|
||||
int num_unlock_responses;
|
||||
char *args;
|
||||
lvm_response_t *unlock_response;
|
||||
|
||||
/* We failed - this should not have been called */
|
||||
if (num_responses == 0)
|
||||
return 0;
|
||||
|
||||
if (name) {
|
||||
len = strlen(name) + 2;
|
||||
args = alloca(len);
|
||||
strcpy(args + 1, name);
|
||||
} else {
|
||||
len = 2;
|
||||
args = alloca(len);
|
||||
args[1] = '\0';
|
||||
}
|
||||
args[0] = scope;
|
||||
|
||||
/* See if it failed anywhere */
|
||||
failed = 0;
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
if (response[i].status != 0)
|
||||
failed++;
|
||||
}
|
||||
|
||||
/* If it failed on any nodes then we only unlock on
|
||||
the nodes that succeeded */
|
||||
if (failed) {
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
/* Unlock the ones that succeeded */
|
||||
if (response[i].status == 0) {
|
||||
status = lvm_cluster_request(CLVMD_CMD_UNLOCK,
|
||||
response[i].node,
|
||||
args, len,
|
||||
&unlock_response,
|
||||
&num_unlock_responses);
|
||||
if (status) {
|
||||
if (verbosity)
|
||||
fprintf(stderr,
|
||||
"cluster command to node %s failed: %s\n",
|
||||
response[i].node,
|
||||
strerror(errno));
|
||||
} else if (unlock_response[0].status != 0) {
|
||||
if (verbosity > 1)
|
||||
fprintf(stderr,
|
||||
"unlock on node %s failed: %s\n",
|
||||
response[i].node,
|
||||
strerror(unlock_response
|
||||
[0].status));
|
||||
}
|
||||
lvm_cluster_free_request(unlock_response);
|
||||
} else {
|
||||
if (verbosity)
|
||||
fprintf(stderr,
|
||||
"command on node %s failed: '%s' - will be left locked\n",
|
||||
response[i].node,
|
||||
strerror(response[i].status));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* All OK, we can do a full cluster unlock */
|
||||
status = lvm_cluster_request(CLVMD_CMD_UNLOCK,
|
||||
"",
|
||||
args, len,
|
||||
&unlock_response,
|
||||
&num_unlock_responses);
|
||||
if (status) {
|
||||
if (verbosity > 1)
|
||||
fprintf(stderr, "cluster command failed: %s\n",
|
||||
strerror(errno));
|
||||
} else {
|
||||
for (i = 0; i < num_unlock_responses; i++) {
|
||||
if (unlock_response[i].status != 0) {
|
||||
if (verbosity > 1)
|
||||
fprintf(stderr,
|
||||
"unlock on node %s failed: %s\n",
|
||||
response[i].node,
|
||||
strerror(unlock_response
|
||||
[0].status));
|
||||
}
|
||||
}
|
||||
}
|
||||
lvm_cluster_free_request(unlock_response);
|
||||
}
|
||||
lvm_cluster_free_request(response);
|
||||
|
||||
return 0;
|
||||
}
|
||||
36
daemons/clvmd/libclvm.h
Normal file
36
daemons/clvmd/libclvm.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LIBCLVM_H
|
||||
#define _LIBCLVM_H
|
||||
|
||||
typedef struct lvm_response {
|
||||
char node[255];
|
||||
char *response;
|
||||
int status;
|
||||
int len;
|
||||
|
||||
} lvm_response_t;
|
||||
|
||||
extern int lvm_cluster_request(char cmd, const char *node, void *data, int len,
|
||||
lvm_response_t ** response, int *num);
|
||||
extern int lvm_cluster_write(char cmd, char *node, void *data, int len);
|
||||
extern int lvm_cluster_free_request(lvm_response_t * response);
|
||||
|
||||
/* The "high-level" API */
|
||||
extern int lvm_lock_for_cluster(char scope, char *name, int verbosity);
|
||||
extern int lvm_unlock_for_cluster(char scope, char *name, int verbosity);
|
||||
|
||||
#endif
|
||||
447
daemons/clvmd/lvm-functions.c
Normal file
447
daemons/clvmd/lvm-functions.c
Normal file
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* 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 <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "libdlm.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
#include "lvm-functions.h"
|
||||
|
||||
/* LVM2 headers */
|
||||
#include "toolcontext.h"
|
||||
#include "log.h"
|
||||
#include "activate.h"
|
||||
#include "hash.h"
|
||||
#include "locking.h"
|
||||
|
||||
static struct cmd_context *cmd = NULL;
|
||||
static struct hash_table *lv_hash = NULL;
|
||||
|
||||
struct lv_info {
|
||||
int lock_id;
|
||||
int lock_mode;
|
||||
};
|
||||
|
||||
/* Return the mode a lock is currently held at (or -1 if not held) */
|
||||
static int get_current_lock(char *resource)
|
||||
{
|
||||
struct lv_info *lvi;
|
||||
|
||||
lvi = hash_lookup(lv_hash, resource);
|
||||
if (lvi) {
|
||||
return lvi->lock_mode;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Called at shutdown to tidy the lockspace */
|
||||
void unlock_all()
|
||||
{
|
||||
struct hash_node *v;
|
||||
hash_iterate(v, lv_hash) {
|
||||
struct lv_info *lvi = hash_get_data(lv_hash, v);
|
||||
|
||||
sync_unlock(hash_get_key(lv_hash, v), lvi->lock_id);
|
||||
}
|
||||
}
|
||||
|
||||
/* Gets a real lock and keeps the info in the hash table */
|
||||
int hold_lock(char *resource, int mode, int flags)
|
||||
{
|
||||
int status;
|
||||
int saved_errno;
|
||||
struct lv_info *lvi;
|
||||
|
||||
flags &= LKF_NOQUEUE; /* Only LKF_NOQUEUE is valid here */
|
||||
|
||||
lvi = hash_lookup(lv_hash, resource);
|
||||
if (lvi) {
|
||||
/* Already exists - convert it */
|
||||
status =
|
||||
sync_lock(resource, mode, LKF_CONVERT | flags,
|
||||
&lvi->lock_id);
|
||||
saved_errno = errno;
|
||||
if (!status)
|
||||
lvi->lock_mode = mode;
|
||||
|
||||
if (status) {
|
||||
DEBUGLOG("hold_lock. convert to %d failed: %s\n", mode,
|
||||
strerror(errno));
|
||||
}
|
||||
errno = saved_errno;
|
||||
} else {
|
||||
lvi = malloc(sizeof(struct lv_info));
|
||||
if (!lvi)
|
||||
return -1;
|
||||
|
||||
lvi->lock_mode = mode;
|
||||
status = sync_lock(resource, mode, flags, &lvi->lock_id);
|
||||
saved_errno = errno;
|
||||
if (status) {
|
||||
free(lvi);
|
||||
DEBUGLOG("hold_lock. lock at %d failed: %s\n", mode,
|
||||
strerror(errno));
|
||||
} else {
|
||||
hash_insert(lv_hash, resource, lvi);
|
||||
}
|
||||
errno = saved_errno;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Unlock and remove it from the hash table */
|
||||
int hold_unlock(char *resource)
|
||||
{
|
||||
struct lv_info *lvi;
|
||||
int status;
|
||||
int saved_errno;
|
||||
|
||||
lvi = hash_lookup(lv_hash, resource);
|
||||
|
||||
if (!lvi) {
|
||||
DEBUGLOG("hold_unlock, lock not already held\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = sync_unlock(resource, lvi->lock_id);
|
||||
saved_errno = errno;
|
||||
if (!status) {
|
||||
hash_remove(lv_hash, resource);
|
||||
free(lvi);
|
||||
} else {
|
||||
DEBUGLOG("hold_unlock. unlock failed(%d): %s\n", status,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
errno = saved_errno;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Watch the return codes here.
|
||||
liblvm API functions return 1(true) for success, 0(false) for failure and don't set errno.
|
||||
libdlm API functions return 0 for success, -1 for failure and do set errno.
|
||||
These functions here return 0 for success or >0 for failure (where the retcode is errno)
|
||||
*/
|
||||
|
||||
/* Activate LV exclusive or non-exclusive */
|
||||
static int do_activate_lv(char *resource, int mode)
|
||||
{
|
||||
int oldmode;
|
||||
int status;
|
||||
int activate_lv;
|
||||
struct lvinfo lvi;
|
||||
|
||||
/* Is it already open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == mode) {
|
||||
return 0; /* Nothing to do */
|
||||
}
|
||||
|
||||
/* Does the config file want us to activate this LV ? */
|
||||
if (!lv_activation_filter(cmd, resource, &activate_lv))
|
||||
return EIO;
|
||||
|
||||
if (!activate_lv)
|
||||
return 0; /* Success, we did nothing! */
|
||||
|
||||
/* Do we need to activate exclusively? */
|
||||
if (activate_lv == 2)
|
||||
mode = LKM_EXMODE;
|
||||
|
||||
/* OK, try to get the lock */
|
||||
status = hold_lock(resource, mode, LKF_NOQUEUE);
|
||||
if (status)
|
||||
return errno;
|
||||
|
||||
/* If it's suspended then resume it */
|
||||
if (!lv_info_by_lvid(cmd, resource, &lvi))
|
||||
return EIO;
|
||||
|
||||
if (lvi.suspended)
|
||||
if (!lv_resume(cmd, resource))
|
||||
return EIO;
|
||||
|
||||
/* Now activate it */
|
||||
if (!lv_activate(cmd, resource))
|
||||
return EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Resume the LV if it was active */
|
||||
static int do_resume_lv(char *resource)
|
||||
{
|
||||
int oldmode;
|
||||
|
||||
/* Is it open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == -1) {
|
||||
DEBUGLOG("do_deactivate_lock, lock not already held\n");
|
||||
return 0; /* We don't need to do anything */
|
||||
}
|
||||
|
||||
if (!lv_resume_if_active(cmd, resource))
|
||||
return EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Suspend the device if active */
|
||||
static int do_suspend_lv(char *resource)
|
||||
{
|
||||
int oldmode;
|
||||
struct lvinfo lvi;
|
||||
|
||||
/* Is it open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == -1) {
|
||||
DEBUGLOG("do_suspend_lv, lock held at %d\n", oldmode);
|
||||
return 0; /* Not active, so it's OK */
|
||||
}
|
||||
|
||||
/* Only suspend it if it exists */
|
||||
if (!lv_info_by_lvid(cmd, resource, &lvi))
|
||||
return EIO;
|
||||
|
||||
if (lvi.exists) {
|
||||
if (!lv_suspend_if_active(cmd, resource)) {
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_deactivate_lv(char *resource)
|
||||
{
|
||||
int oldmode;
|
||||
int status;
|
||||
|
||||
/* Is it open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == -1) {
|
||||
DEBUGLOG("do_deactivate_lock, lock not already held\n");
|
||||
return 0; /* We don't need to do anything */
|
||||
}
|
||||
|
||||
if (!lv_deactivate(cmd, resource))
|
||||
return EIO;
|
||||
|
||||
status = hold_unlock(resource);
|
||||
if (status)
|
||||
return errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is the LOCK_LV part that happens on all nodes in the cluster -
|
||||
it is responsible for the interaction with device-mapper and LVM */
|
||||
int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
DEBUGLOG("do_lock_lv: resource '%s', cmd = 0x%x, flags = %d\n",
|
||||
resource, command, lock_flags);
|
||||
|
||||
if (!cmd->config_valid || config_files_changed(cmd)) {
|
||||
/* Reinitialise various settings inc. logging, filters */
|
||||
if (!refresh_toolcontext(cmd)) {
|
||||
log_error("Updated config file invalid. Aborting.");
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
switch (command) {
|
||||
case LCK_LV_EXCLUSIVE:
|
||||
status = do_activate_lv(resource, LKM_EXMODE);
|
||||
break;
|
||||
|
||||
case LCK_LV_SUSPEND:
|
||||
status = do_suspend_lv(resource);
|
||||
break;
|
||||
|
||||
case LCK_UNLOCK:
|
||||
case LCK_LV_RESUME: /* if active */
|
||||
status = do_resume_lv(resource);
|
||||
break;
|
||||
|
||||
case LCK_LV_ACTIVATE:
|
||||
status = do_activate_lv(resource, LKM_CRMODE);
|
||||
break;
|
||||
|
||||
case LCK_LV_DEACTIVATE:
|
||||
status = do_deactivate_lv(resource);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUGLOG("Invalid LV command 0x%x\n", command);
|
||||
status = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* clean the pool for another command */
|
||||
pool_empty(cmd->mem);
|
||||
|
||||
DEBUGLOG("Command return is %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Functions to do on the local node only BEFORE the cluster-wide stuff above happens */
|
||||
int pre_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
{
|
||||
/* Nearly all the stuff happens cluster-wide. Apart from SUSPEND. Here we get the
|
||||
lock out on this node (because we are the node modifying the metadata)
|
||||
before suspending cluster-wide.
|
||||
*/
|
||||
if (command == LCK_LV_SUSPEND) {
|
||||
DEBUGLOG("pre_lock_lv: resource '%s', cmd = 0x%x, flags = %d\n",
|
||||
resource, command, lock_flags);
|
||||
|
||||
if (hold_lock(resource, LKM_PWMODE, LKF_NOQUEUE))
|
||||
return errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Functions to do on the local node only AFTER the cluster-wide stuff above happens */
|
||||
int post_lock_lv(unsigned char command, unsigned char lock_flags,
|
||||
char *resource)
|
||||
{
|
||||
/* Opposite of above, done on resume after a metadata update */
|
||||
if (command == LCK_LV_RESUME) {
|
||||
int oldmode;
|
||||
|
||||
DEBUGLOG
|
||||
("post_lock_lv: resource '%s', cmd = 0x%x, flags = %d\n",
|
||||
resource, command, lock_flags);
|
||||
|
||||
/* If the lock state is PW then restore it to what it was */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == LKM_PWMODE) {
|
||||
struct lvinfo lvi;
|
||||
|
||||
if (!lv_info_by_lvid(cmd, resource, &lvi))
|
||||
return EIO;
|
||||
|
||||
if (lvi.exists) {
|
||||
if (hold_lock(resource, LKM_CRMODE, 0))
|
||||
return errno;
|
||||
} else {
|
||||
if (hold_unlock(resource))
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if a VG is un use by LVM1 so we don't stomp on it */
|
||||
int do_check_lvm1(char *vgname)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = check_lvm1_vg_inactive(cmd, vgname);
|
||||
|
||||
return status == 1 ? 0 : EBUSY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ideally, clvmd should be started before any LVs are active
|
||||
* but this may not be the case...
|
||||
* I suppose this also comes in handy if clvmd crashes, not that it would!
|
||||
*/
|
||||
static void *get_initial_state()
|
||||
{
|
||||
char lv[64], vg[64], flags[25];
|
||||
char uuid[65];
|
||||
char line[255];
|
||||
FILE *lvs =
|
||||
popen
|
||||
("/sbin/lvm lvs --nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr",
|
||||
"r");
|
||||
|
||||
if (!lvs)
|
||||
return NULL;
|
||||
|
||||
while (fgets(line, sizeof(line), lvs)) {
|
||||
if (sscanf(line, "%s %s %s\n", vg, lv, flags) == 3) {
|
||||
/* States: s:suspended a:active S:dropped snapshot I:invalid snapshot */
|
||||
if (flags[4] == 'a' || flags[4] == 's') { /* is it active or suspended? */
|
||||
/* Convert hyphen-separated UUIDs into one */
|
||||
memcpy(&uuid[0], &vg[0], 6);
|
||||
memcpy(&uuid[6], &vg[7], 4);
|
||||
memcpy(&uuid[10], &vg[12], 4);
|
||||
memcpy(&uuid[14], &vg[17], 4);
|
||||
memcpy(&uuid[18], &vg[22], 4);
|
||||
memcpy(&uuid[22], &vg[27], 4);
|
||||
memcpy(&uuid[26], &vg[32], 6);
|
||||
memcpy(&uuid[32], &lv[0], 6);
|
||||
memcpy(&uuid[38], &lv[7], 4);
|
||||
memcpy(&uuid[42], &lv[12], 4);
|
||||
memcpy(&uuid[46], &lv[17], 4);
|
||||
memcpy(&uuid[50], &lv[22], 4);
|
||||
memcpy(&uuid[54], &lv[27], 4);
|
||||
memcpy(&uuid[58], &lv[32], 6);
|
||||
uuid[64] = '\0';
|
||||
|
||||
DEBUGLOG("getting initial lock for %s\n", uuid);
|
||||
hold_lock(uuid, LKM_CRMODE, LKF_NOQUEUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(lvs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void init_lvhash()
|
||||
{
|
||||
/* Create hash table for keeping LV locks & status */
|
||||
lv_hash = hash_create(100);
|
||||
}
|
||||
|
||||
/* Called to initialise the LVM context of the daemon */
|
||||
int init_lvm(void)
|
||||
{
|
||||
if (!(cmd = create_toolcontext(NULL))) {
|
||||
log_error("Failed to allocate command context");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Use LOG_DAEMON for syslog messages instead of LOG_USER */
|
||||
init_syslog(LOG_DAEMON);
|
||||
init_debug(_LOG_ERR);
|
||||
|
||||
get_initial_state();
|
||||
|
||||
return 1;
|
||||
}
|
||||
35
daemons/clvmd/lvm-functions.h
Normal file
35
daemons/clvmd/lvm-functions.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* Functions in lvm-functions.c */
|
||||
|
||||
#ifndef _LVM_FUNCTIONS_H
|
||||
#define _LVM_FUNCTIONS_H
|
||||
|
||||
extern int pre_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern int do_check_lvm1(char *vgname);
|
||||
extern int init_lvm(void);
|
||||
extern void init_lvhash(void);
|
||||
|
||||
extern int hold_unlock(char *resource);
|
||||
extern int hold_lock(char *resource, int mode, int flags);
|
||||
extern void unlock_all(void);
|
||||
|
||||
#endif
|
||||
369
daemons/clvmd/system-lv.c
Normal file
369
daemons/clvmd/system-lv.c
Normal file
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* Routines dealing with the System LV */
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <syslog.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <mntent.h>
|
||||
|
||||
#include "libdlm.h"
|
||||
#include "log.h"
|
||||
#include "list.h"
|
||||
#include "locking.h"
|
||||
#include "system-lv.h"
|
||||
#include "clvmd-comms.h"
|
||||
#ifdef HAVE_CCS
|
||||
#include "ccs.h"
|
||||
#endif
|
||||
|
||||
#define SYSTEM_LV_FILESYSTEM "ext2"
|
||||
#define SYSTEM_LV_MOUNTPOINT "/tmp/.clvmd-XXXXXX"
|
||||
|
||||
extern char *config_filename(void);
|
||||
|
||||
static char system_lv_name[PATH_MAX] = { '\0' };
|
||||
static char mount_point[PATH_MAX] = { '\0' };
|
||||
static int mounted = 0;
|
||||
static int mounted_rw = 0;
|
||||
static int lockid;
|
||||
static const char *lock_name = "CLVM_SYSTEM_LV";
|
||||
|
||||
/* Look in /proc/mounts or (as a last resort) /etc/mtab to
|
||||
see if the system-lv is mounted. If it is mounted and we
|
||||
think it's not then abort because we don't have the right
|
||||
lock status and we don't know what other processes are doing with it.
|
||||
|
||||
Returns 1 for mounted, 0 for not mounted so it matches the condition
|
||||
of the "mounted" static variable above.
|
||||
*/
|
||||
static int is_really_mounted(void)
|
||||
{
|
||||
FILE *mountfile;
|
||||
struct mntent *ment;
|
||||
|
||||
mountfile = setmntent("/proc/mounts", "r");
|
||||
if (!mountfile) {
|
||||
mountfile = setmntent("/etc/mtab", "r");
|
||||
if (!mountfile) {
|
||||
log_error("Unable to open /proc/mounts or /etc/mtab");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for system LV name in the file */
|
||||
do {
|
||||
ment = getmntent(mountfile);
|
||||
if (ment) {
|
||||
if (strcmp(ment->mnt_fsname, system_lv_name) == 0) {
|
||||
endmntent(mountfile);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (ment);
|
||||
|
||||
endmntent(mountfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the system LV name from the config file */
|
||||
static int find_system_lv(void)
|
||||
{
|
||||
if (system_lv_name[0] == '\0') {
|
||||
#ifdef HAVE_CCS
|
||||
int error;
|
||||
ccs_node_t *ctree;
|
||||
|
||||
/* Read the cluster config file */
|
||||
/* Open the config file */
|
||||
error = open_ccs_file(&ctree, "clvm.ccs");
|
||||
if (error) {
|
||||
perror("reading config file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(system_lv_name, find_ccs_str(ctree,
|
||||
"cluster/systemlv", '/',
|
||||
"/dev/vg/system_lv"));
|
||||
|
||||
/* Finished with config file */
|
||||
close_ccs_file(ctree);
|
||||
#else
|
||||
if (getenv("CLVMD_SYSTEM_LV"))
|
||||
strcpy(system_lv_name, getenv("CLVMD_SYSTEM_LV"));
|
||||
else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* See if it has been mounted outside our control */
|
||||
if (is_really_mounted() != mounted) {
|
||||
log_error
|
||||
("The system LV state has been mounted/umounted outside the control of clvmd\n"
|
||||
"it cannot not be used for cluster communications until this is fixed.\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No prizes */
|
||||
int system_lv_umount(void)
|
||||
{
|
||||
if (!mounted)
|
||||
return 0;
|
||||
|
||||
if (umount(mount_point) < 0) {
|
||||
log_error("umount of system LV (%s) failed: %m\n",
|
||||
system_lv_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sync_unlock(lock_name, lockid);
|
||||
mounted = 0;
|
||||
|
||||
/* Remove the mount point */
|
||||
rmdir(mount_point);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int system_lv_mount(int readwrite)
|
||||
{
|
||||
int status;
|
||||
int saved_errno;
|
||||
int fd;
|
||||
|
||||
if (find_system_lv()) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Is it already mounted suitably? */
|
||||
if (mounted) {
|
||||
if (!readwrite || (readwrite && mounted_rw)) {
|
||||
return 0;
|
||||
} else {
|
||||
/* Mounted RO and we need RW */
|
||||
if (system_lv_umount() < 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Randomize the mount point */
|
||||
strcpy(mount_point, SYSTEM_LV_MOUNTPOINT);
|
||||
fd = mkstemp(mount_point);
|
||||
if (fd < 0) {
|
||||
log_error("mkstemp for system LV mount point failed: %m\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Race condition here but there's no mkstemp for directories */
|
||||
close(fd);
|
||||
unlink(mount_point);
|
||||
mkdir(mount_point, 0600);
|
||||
|
||||
/* Make sure we have a system-lv lock */
|
||||
status =
|
||||
sync_lock(lock_name, (readwrite) ? LKM_EXMODE : LKM_CRMODE, 0,
|
||||
&lockid);
|
||||
if (status < 0)
|
||||
return -1;
|
||||
|
||||
/* Mount it */
|
||||
if (mount(system_lv_name, mount_point, SYSTEM_LV_FILESYSTEM,
|
||||
MS_MGC_VAL | MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_SYNCHRONOUS
|
||||
| (readwrite ? 0 : MS_RDONLY), NULL) < 0) {
|
||||
/* mount(2) returns EINVAL if the volume has no FS on it. So, if we want to
|
||||
write to it we try to make a filesystem in it and retry the mount */
|
||||
if (errno == EINVAL && readwrite) {
|
||||
char cmd[256];
|
||||
|
||||
log_error("Attempting mkfs on system LV device %s\n",
|
||||
system_lv_name);
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/mkfs -t %s %s",
|
||||
SYSTEM_LV_FILESYSTEM, system_lv_name);
|
||||
system(cmd);
|
||||
|
||||
if (mount
|
||||
(system_lv_name, mount_point, SYSTEM_LV_FILESYSTEM,
|
||||
MS_MGC_VAL | MS_NOSUID | MS_NODEV | MS_NOEXEC |
|
||||
MS_SYNCHRONOUS | (readwrite ? 0 : MS_RDONLY),
|
||||
NULL) == 0)
|
||||
goto mounted;
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
log_error("mount of system LV (%s, %s, %s) failed: %m\n",
|
||||
system_lv_name, mount_point, SYSTEM_LV_FILESYSTEM);
|
||||
sync_unlock(lock_name, lockid);
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
mounted:
|
||||
/* Set the internal flags */
|
||||
mounted = 1;
|
||||
mounted_rw = readwrite;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Erase *all* files in the root directory of the system LV.
|
||||
This *MUST* be called with an appropriate lock held!
|
||||
The LV is left mounted RW because it is assumed that the
|
||||
caller wants to write something here after clearing some space */
|
||||
int system_lv_eraseall(void)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
char fname[PATH_MAX];
|
||||
|
||||
/* Must be mounted R/W */
|
||||
system_lv_mount(1);
|
||||
|
||||
dir = opendir(mount_point);
|
||||
if (!dir)
|
||||
return -1;
|
||||
|
||||
while ((ent = readdir(dir))) {
|
||||
struct stat st;
|
||||
snprintf(fname, sizeof(fname), "%s/%s", mount_point,
|
||||
ent->d_name);
|
||||
|
||||
if (stat(fname, &st)) {
|
||||
if (S_ISREG(st.st_mode))
|
||||
unlink(fname);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is a "high-level" routine - it mounts the system LV, writes
|
||||
the data into a file named after this node and then umounts the LV
|
||||
again */
|
||||
int system_lv_write_data(char *data, ssize_t len)
|
||||
{
|
||||
struct utsname nodeinfo;
|
||||
char fname[PATH_MAX];
|
||||
int outfile;
|
||||
ssize_t thiswrite;
|
||||
ssize_t written;
|
||||
|
||||
if (system_lv_mount(1))
|
||||
return -1;
|
||||
|
||||
/* Build the file name we are goingto use. */
|
||||
uname(&nodeinfo);
|
||||
snprintf(fname, sizeof(fname), "%s/%s", mount_point, nodeinfo.nodename);
|
||||
|
||||
/* Open the file for output */
|
||||
outfile = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0600);
|
||||
if (outfile < 0) {
|
||||
int saved_errno = errno;
|
||||
system_lv_umount();
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
written = 0;
|
||||
do {
|
||||
thiswrite = write(outfile, data + written, len - written);
|
||||
if (thiswrite > 0)
|
||||
written += thiswrite;
|
||||
|
||||
} while (written < len && thiswrite > 0);
|
||||
|
||||
close(outfile);
|
||||
|
||||
system_lv_umount();
|
||||
return (thiswrite < 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
/* This is a "high-level" routine - it mounts the system LV, reads
|
||||
the data from a named file and then umounts the LV
|
||||
again */
|
||||
int system_lv_read_data(char *fname_base, char *data, ssize_t *len)
|
||||
{
|
||||
char fname[PATH_MAX];
|
||||
int outfile;
|
||||
struct stat st;
|
||||
ssize_t filesize;
|
||||
ssize_t thisread;
|
||||
ssize_t readbytes;
|
||||
|
||||
if (system_lv_mount(0))
|
||||
return -1;
|
||||
|
||||
/* Build the file name we are going to use. */
|
||||
snprintf(fname, sizeof(fname), "%s/%s", mount_point, fname_base);
|
||||
|
||||
/* Get the file size and stuff. Actually we only need the file size but
|
||||
this will also check that the file exists */
|
||||
if (stat(fname, &st) < 0) {
|
||||
int saved_errno = errno;
|
||||
|
||||
log_error("stat of file %s on system LV failed: %m\n", fname);
|
||||
system_lv_umount();
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
filesize = st.st_size;
|
||||
|
||||
outfile = open(fname, O_RDONLY);
|
||||
if (outfile < 0) {
|
||||
int saved_errno = errno;
|
||||
|
||||
log_error("open of file %s on system LV failed: %m\n", fname);
|
||||
system_lv_umount();
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
readbytes = 0;
|
||||
do {
|
||||
thisread =
|
||||
read(outfile, data + readbytes, filesize - readbytes);
|
||||
if (thisread > 0)
|
||||
readbytes += thisread;
|
||||
|
||||
} while (readbytes < filesize && thisread > 0);
|
||||
|
||||
close(outfile);
|
||||
|
||||
system_lv_umount();
|
||||
|
||||
*len = readbytes;
|
||||
return (thisread < 0) ? -1 : 0;
|
||||
}
|
||||
30
daemons/clvmd/system-lv.h
Normal file
30
daemons/clvmd/system-lv.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 _CLVM_SYSTEM_LV_H
|
||||
#define _CLVM_SYSTEM_LV_H
|
||||
|
||||
/* Prototypes for System-LV functions */
|
||||
|
||||
/* "low-level" functions */
|
||||
extern int system_lv_umount(void);
|
||||
extern int system_lv_mount(int readwrite);
|
||||
extern int system_lv_eraseall(void);
|
||||
|
||||
/* "high-level" functions */
|
||||
extern int system_lv_write_data(char *data, ssize_t len);
|
||||
extern int system_lv_read_data(char *fname_base, char *data, ssize_t *len);
|
||||
|
||||
#endif
|
||||
480
daemons/clvmd/tcp-comms.c
Normal file
480
daemons/clvmd/tcp-comms.c
Normal file
@@ -0,0 +1,480 @@
|
||||
/******************************************************************************
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 2002-2003 All rights reserved.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
/* This provides the inter-clvmd communications for a system without CMAN.
|
||||
There is a listening TCP socket which accepts new connections in the
|
||||
normal way.
|
||||
It can also make outgoing connnections to the other clvmd nodes.
|
||||
*/
|
||||
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <netdb.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "ccs.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
#include "clvmd-gulm.h"
|
||||
#include "hash.h"
|
||||
|
||||
#define DEFAULT_TCP_PORT 21064
|
||||
|
||||
static int listen_fd = -1;
|
||||
static int tcp_port;
|
||||
struct hash_table *sock_hash;
|
||||
|
||||
static int get_tcp_port(int default_port);
|
||||
static int get_our_ip_address(char *addr, int *family);
|
||||
static int read_from_tcpsock(struct local_client *fd, char *buf, int len, char *csid,
|
||||
struct local_client **new_client);
|
||||
|
||||
/* Called by init_cluster() to open up the listening socket */
|
||||
// TODO: IPv6 compat.
|
||||
int init_comms()
|
||||
{
|
||||
struct sockaddr *addr = NULL;
|
||||
struct sockaddr_in addr4;
|
||||
struct sockaddr_in6 addr6;
|
||||
int addr_len;
|
||||
int family;
|
||||
char address[MAX_CSID_LEN];
|
||||
|
||||
sock_hash = hash_create(100);
|
||||
tcp_port = get_tcp_port(DEFAULT_TCP_PORT);
|
||||
|
||||
/* Get IP address and IP type */
|
||||
get_our_ip_address(address, &family);
|
||||
if (family == AF_INET)
|
||||
{
|
||||
memcpy(&addr4.sin_addr, addr, sizeof(struct in_addr));
|
||||
addr = (struct sockaddr *)&addr4;
|
||||
addr4.sin_port = htons(tcp_port);
|
||||
addr_len = sizeof(addr4);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&addr6.sin6_addr, addr, sizeof(struct in6_addr));
|
||||
addr = (struct sockaddr *)&addr6;
|
||||
addr6.sin6_port = htons(tcp_port);
|
||||
addr_len = sizeof(addr6);
|
||||
}
|
||||
|
||||
listen_fd = socket(family, SOCK_STREAM, 0);
|
||||
|
||||
if (listen_fd < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int one = 1;
|
||||
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
|
||||
}
|
||||
|
||||
addr->sa_family = family;
|
||||
|
||||
if (bind(listen_fd, addr, addr_len) < 0)
|
||||
{
|
||||
DEBUGLOG("Can't bind to port\n");
|
||||
syslog(LOG_ERR, "Can't bind to port %d, is clvmd already running ?", tcp_port);
|
||||
close(listen_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
listen(listen_fd, 5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tcp_remove_client(char *csid)
|
||||
{
|
||||
struct local_client *client;
|
||||
DEBUGLOG("tcp_remove_client\n");
|
||||
|
||||
/* Don't actually close the socket here - that's the
|
||||
job of clvmd.c whch will do the job when it notices the
|
||||
other end has gone. We just need to remove the client(s) from
|
||||
the hash table so we don't try to use it for sending any more */
|
||||
client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
|
||||
if (client)
|
||||
{
|
||||
hash_remove_binary(sock_hash, csid, MAX_CSID_LEN);
|
||||
}
|
||||
|
||||
/* Look for a mangled one too */
|
||||
csid[0] ^= 0x80;
|
||||
|
||||
client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
|
||||
if (client)
|
||||
{
|
||||
hash_remove_binary(sock_hash, csid, MAX_CSID_LEN);
|
||||
}
|
||||
|
||||
/* Put it back as we found it */
|
||||
csid[0] ^= 0x80;
|
||||
}
|
||||
|
||||
int alloc_client(int fd, char *csid, struct local_client **new_client)
|
||||
{
|
||||
struct local_client *client;
|
||||
|
||||
DEBUGLOG("alloc_client %d csid = [%d.%d.%d.%d]\n", fd,csid[0],csid[1],csid[2],csid[3]);
|
||||
|
||||
/* Create a local_client and return it */
|
||||
client = malloc(sizeof(struct local_client));
|
||||
if (!client)
|
||||
{
|
||||
DEBUGLOG("malloc failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(client, 0, sizeof(struct local_client));
|
||||
client->fd = fd;
|
||||
client->type = CLUSTER_DATA_SOCK;
|
||||
client->callback = read_from_tcpsock;
|
||||
if (new_client)
|
||||
*new_client = client;
|
||||
|
||||
/* Add to our list of node sockets */
|
||||
if (hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN))
|
||||
{
|
||||
DEBUGLOG("alloc_client mangling CSID for second connection\n");
|
||||
/* This is a duplicate connection but we can't close it because
|
||||
the other end may already have started sending.
|
||||
So, we mangle the IP address and keep it, all sending will
|
||||
go out of the main FD
|
||||
*/
|
||||
csid[0] ^= 0x80;
|
||||
client->bits.net.flags = 1; /* indicate mangled CSID */
|
||||
|
||||
/* If it still exists then kill the connection as we should only
|
||||
ever have one incoming connection from each node */
|
||||
if (hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN))
|
||||
{
|
||||
DEBUGLOG("Multiple incoming connections from node\n");
|
||||
syslog(LOG_ERR, " Bogus incoming connection from %d.%d.%d.%d\n", csid[0],csid[1],csid[2],csid[3]);
|
||||
|
||||
free(client);
|
||||
errno = ECONNREFUSED;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
hash_insert_binary(sock_hash, csid, MAX_CSID_LEN, client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_main_cluster_fd()
|
||||
{
|
||||
return listen_fd;
|
||||
}
|
||||
|
||||
|
||||
/* Read on main comms (listen) socket, accept it */
|
||||
int cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
int newfd;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
int status;
|
||||
char name[MAX_CLUSTER_MEMBER_NAME_LEN];
|
||||
|
||||
DEBUGLOG("cluster_fd_callback\n");
|
||||
*new_client = NULL;
|
||||
newfd = accept(listen_fd, (struct sockaddr *)&addr, &addrlen);
|
||||
|
||||
DEBUGLOG("cluster_fd_callback, newfd=%d (errno=%d)\n", newfd, errno);
|
||||
if (!newfd)
|
||||
{
|
||||
syslog(LOG_ERR, "error in accept: %m");
|
||||
errno = EAGAIN;
|
||||
return -1; /* Don't return an error or clvmd will close the listening FD */
|
||||
}
|
||||
|
||||
/* Check that the client is a member of the cluster
|
||||
and reject if not.
|
||||
// FIXME: IPv4 specific
|
||||
*/
|
||||
if (name_from_csid((char *)&addr.sin_addr.s_addr, name) < 0)
|
||||
{
|
||||
char *ip = (char *)&addr.sin_addr.s_addr;
|
||||
syslog(LOG_ERR, "Got connect from non-cluster node %d.%d.%d.%d\n",
|
||||
ip[0], ip[1], ip[2], ip[3]);
|
||||
DEBUGLOG("Got connect from non-cluster node %d.%d.%d.%d\n",
|
||||
ip[0], ip[1], ip[2], ip[3]);
|
||||
close(newfd);
|
||||
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = alloc_client(newfd, (char *)&addr.sin_addr.s_addr, new_client);
|
||||
if (status)
|
||||
{
|
||||
DEBUGLOG("cluster_fd_callback, alloc_client failed, status = %d\n", status);
|
||||
close(newfd);
|
||||
/* See above... */
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
DEBUGLOG("cluster_fd_callback, returning %d, %p\n", newfd, *new_client);
|
||||
return newfd;
|
||||
}
|
||||
|
||||
|
||||
static int read_from_tcpsock(struct local_client *client, char *buf, int len, char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
socklen_t slen = sizeof(addr);
|
||||
int status;
|
||||
|
||||
DEBUGLOG("read_from_tcpsock fd %d\n", client->fd);
|
||||
*new_client = NULL;
|
||||
|
||||
/* Get "csid" */
|
||||
getpeername(client->fd, (struct sockaddr *)&addr, &slen);
|
||||
memcpy(csid, &addr.sin_addr.s_addr, MAX_CSID_LEN);
|
||||
|
||||
status = read(client->fd, buf, len);
|
||||
|
||||
DEBUGLOG("read_from_tcpsock, status = %d(errno = %d)\n", status, errno);
|
||||
|
||||
/* Remove it from the hash table if there's an error, clvmd will
|
||||
remove the socket from its lists and free the client struct */
|
||||
if (status == 0 ||
|
||||
(status < 0 && errno != EAGAIN && errno != EINTR))
|
||||
{
|
||||
char remcsid[MAX_CSID_LEN];
|
||||
|
||||
memcpy(remcsid, csid, MAX_CSID_LEN);
|
||||
close(client->fd);
|
||||
|
||||
/* If the csid was mangled, then make sure we remove the right entry */
|
||||
if (client->bits.net.flags)
|
||||
remcsid[0] ^= 0x80;
|
||||
hash_remove_binary(sock_hash, remcsid, MAX_CSID_LEN);
|
||||
|
||||
/* Tell cluster manager layer */
|
||||
add_down_node(remcsid);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int connect_csid(char *csid, struct local_client **newclient)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in addr;
|
||||
int status;
|
||||
|
||||
DEBUGLOG("Connecting socket\n");
|
||||
fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "Unable to create new socket: %m");
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
memcpy(&addr.sin_addr.s_addr, csid, MAX_CSID_LEN);
|
||||
addr.sin_port = htons(tcp_port);
|
||||
|
||||
DEBUGLOG("Connecting socket %d\n", fd);
|
||||
if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "Unable to connect to remote node: %m");
|
||||
DEBUGLOG("Unable to connect to remote node: %s\n", strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = alloc_client(fd, csid, newclient);
|
||||
if (status)
|
||||
close(fd);
|
||||
else
|
||||
add_client(*newclient);
|
||||
|
||||
/* If we can connect to it, it must be running a clvmd */
|
||||
add_up_node(csid);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Send a message to a known CSID */
|
||||
static int tcp_send_message(void *buf, int msglen, unsigned char *csid, const char *errtext)
|
||||
{
|
||||
int status;
|
||||
struct local_client *client;
|
||||
char ourcsid[MAX_CSID_LEN];
|
||||
|
||||
assert(csid);
|
||||
|
||||
DEBUGLOG("tcp_send_message, csid = [%d.%d.%d.%d], msglen = %d\n", csid[0],csid[1],csid[2],csid[3], msglen);
|
||||
|
||||
/* Don't connect to ourself */
|
||||
get_our_csid(ourcsid);
|
||||
if (memcmp(csid, ourcsid, MAX_CSID_LEN) == 0)
|
||||
return msglen;
|
||||
|
||||
client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
|
||||
if (!client)
|
||||
{
|
||||
status = connect_csid(csid, &client);
|
||||
if (status)
|
||||
return -1;
|
||||
}
|
||||
DEBUGLOG("tcp_send_message, fd = %d\n", client->fd);
|
||||
|
||||
return write(client->fd, buf, msglen);
|
||||
}
|
||||
|
||||
|
||||
int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
|
||||
{
|
||||
int status=0;
|
||||
|
||||
DEBUGLOG("cluster send message, csid = %p, msglen = %d\n", csid, msglen);
|
||||
|
||||
/* If csid is NULL then send to all known (not just connected) nodes */
|
||||
if (!csid)
|
||||
{
|
||||
void *context = NULL;
|
||||
char loop_csid[MAX_CSID_LEN];
|
||||
|
||||
/* Loop round all gulm-known nodes */
|
||||
while (get_next_node_csid(&context, loop_csid))
|
||||
{
|
||||
status = tcp_send_message(buf, msglen, loop_csid, errtext);
|
||||
if (status == 0 ||
|
||||
(status < 0 && (errno == EAGAIN || errno == EINTR)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
status = tcp_send_message(buf, msglen, csid, errtext);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int get_tcp_port(int default_port)
|
||||
{
|
||||
int ccs_handle;
|
||||
int port = default_port;
|
||||
char *portstr;
|
||||
|
||||
ccs_handle = ccs_connect();
|
||||
if (ccs_handle)
|
||||
{
|
||||
return port;
|
||||
}
|
||||
|
||||
if (!ccs_get(ccs_handle, "//clvm/@port", &portstr))
|
||||
{
|
||||
port = atoi(portstr);
|
||||
free(portstr);
|
||||
|
||||
if (port <= 0 && port >= 65536)
|
||||
port = default_port;
|
||||
}
|
||||
ccs_disconnect(ccs_handle);
|
||||
|
||||
DEBUGLOG("Using port %d for communications\n", port);
|
||||
return port;
|
||||
}
|
||||
|
||||
/* To get our own IP address we get the locally bound address of the
|
||||
socket that's talking to GULM in the assumption(eek) that it will
|
||||
be on the "right" network in a multi-homed system */
|
||||
static int get_our_ip_address(char *addr, int *family)
|
||||
{
|
||||
/* Use a sockaddr_in6 to make sure it's big enough */
|
||||
struct sockaddr_in6 saddr;
|
||||
int socklen = sizeof(saddr);
|
||||
|
||||
if (!getsockname(gulm_fd(), (struct sockaddr *)&saddr, &socklen))
|
||||
{
|
||||
if (saddr.sin6_family == AF_INET6)
|
||||
{
|
||||
memcpy(addr, &saddr.sin6_addr, sizeof(saddr.sin6_addr));
|
||||
}
|
||||
else
|
||||
{
|
||||
struct sockaddr_in *sin4 = (struct sockaddr_in *)&saddr;
|
||||
memcpy(addr, &sin4->sin_addr, sizeof(sin4->sin_addr));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Public version of above for those that don't care what protocol
|
||||
we're using */
|
||||
void get_our_csid(char *csid)
|
||||
{
|
||||
static char our_csid[MAX_CSID_LEN];
|
||||
static int got_csid = 0;
|
||||
|
||||
if (!got_csid)
|
||||
{
|
||||
int family;
|
||||
|
||||
memset(our_csid, 0, sizeof(our_csid));
|
||||
if (get_our_ip_address(our_csid, &family))
|
||||
{
|
||||
got_csid = 1;
|
||||
}
|
||||
}
|
||||
memcpy(csid, our_csid, MAX_CSID_LEN);
|
||||
}
|
||||
|
||||
/* Get someone else's IP address from DNS */
|
||||
int get_ip_address(char *node, char *addr)
|
||||
{
|
||||
struct hostent *he;
|
||||
|
||||
memset(addr, 0, MAX_CSID_LEN);
|
||||
|
||||
// TODO: what do we do about multi-homed hosts ???
|
||||
// CCSs ip_interfaces solved this but some bugger removed it.
|
||||
|
||||
/* Try IPv6 first. The man page for gethostbyname implies that
|
||||
it will lookup ip6 & ip4 names, but it seems not to */
|
||||
he = gethostbyname2(node, AF_INET6);
|
||||
if (!he)
|
||||
he = gethostbyname2(node, AF_INET);
|
||||
if (!he)
|
||||
return -1;
|
||||
|
||||
/* For IPv4 address just use the lower 4 bytes */
|
||||
memcpy(&addr, he->h_addr_list[0],
|
||||
he->h_length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
7
daemons/clvmd/tcp-comms.h
Normal file
7
daemons/clvmd/tcp-comms.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define MAX_CLUSTER_MESSAGE 1600
|
||||
#define MAX_CSID_LEN sizeof(struct in6_addr)
|
||||
#define MAX_CLUSTER_MEMBER_NAME_LEN 128
|
||||
|
||||
extern int init_comms(void);
|
||||
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.
|
||||
59
debian/changelog
vendored
59
debian/changelog
vendored
@@ -1,3 +1,62 @@
|
||||
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
|
||||
|
||||
* Get rid of awk dependency in init script. (Closes: #146257)
|
||||
|
||||
-- Andres Salomon <dilinger@mp3revolution.net> Sun, 12 May 2002 04:39:06 -0500
|
||||
|
||||
lvm2 (0.95.05-2) unstable; urgency=low
|
||||
|
||||
* Use ${shlibs:Depends} in Depends.
|
||||
* Get rid of postinst/postrm scripts, use debhelper's init script instead.
|
||||
* Add Conflicts against lvm10, lvm-common.
|
||||
* Fix endian issues on big-endian machines.
|
||||
|
||||
-- Andres Salomon <dilinger@mp3revolution.net> Thu, 2 May 2002 23:53:53 -0500
|
||||
|
||||
lvm2 (0.95.05-1) unstable; urgency=low
|
||||
|
||||
* New release (Beta2).
|
||||
|
||||
-- Andres Salomon <dilinger@mp3revolution.net> Thu, 25 Apr 2002 00:37:41 -0500
|
||||
|
||||
lvm2 (0.95.04cvs20020306-1) unstable; urgency=low
|
||||
|
||||
* CVS updated.
|
||||
|
||||
2
debian/conffiles
vendored
2
debian/conffiles
vendored
@@ -1,2 +0,0 @@
|
||||
/etc/lvm/lvm.conf
|
||||
/etc/init.d/lvm2
|
||||
13
debian/control
vendored
13
debian/control
vendored
@@ -2,18 +2,23 @@ Source: lvm2
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Maintainer: Andres Salomon <dilinger@mp3revolution.net>
|
||||
Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev, libreadline4-dev
|
||||
Standards-Version: 3.5.2
|
||||
Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev (>= 0.96.04), libreadline4-dev
|
||||
Standards-Version: 3.5.8.0
|
||||
|
||||
Package: lvm2
|
||||
Architecture: any
|
||||
Depends: libdevmapper0
|
||||
Depends: ${shlibs:Depends}
|
||||
Conflicts: lvm10, lvm-common
|
||||
Replaces: lvm10, lvm-common
|
||||
Provides: lvm-binaries
|
||||
Suggests: dmsetup
|
||||
Suggests: dmsetup, kernel-patch-device-mapper
|
||||
Description: The Linux Logical Volume Manager
|
||||
This is LVM2, the rewrite of The Linux Logical Volume Manager. LVM
|
||||
supports enterprise level volume management of disk and disk subsystems
|
||||
by grouping arbitrary disks into volume groups. The total capacity of
|
||||
volume groups can be allocated to logical volumes, which are accessed as
|
||||
regular block devices.
|
||||
.
|
||||
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
|
||||
|
||||
Upstream Author(s): LVM Development Team
|
||||
Upstream Author: LVM Development Team
|
||||
|
||||
Copyright (c) 2001-2002 LVM Development Team
|
||||
|
||||
|
||||
7
debian/docs
vendored
7
debian/docs
vendored
@@ -1,8 +1,5 @@
|
||||
BUGS
|
||||
INTRO
|
||||
README
|
||||
TODO
|
||||
VERSION
|
||||
doc/example.conf
|
||||
doc/pvmove_outline.txt
|
||||
doc/testing.txt
|
||||
WHATS_NEW
|
||||
doc/*
|
||||
|
||||
9
debian/init.d
vendored
9
debian/init.d
vendored
@@ -14,10 +14,10 @@ modprobe dm-mod >/dev/null 2>&1
|
||||
|
||||
# Create necessary files in /dev for device-mapper
|
||||
create_devfiles() {
|
||||
DIR="/dev/device-mapper"
|
||||
DIR="/dev/mapper"
|
||||
FILE="$DIR/control"
|
||||
major=$(awk '$2 ~ /^misc$/ {print $1}' /proc/devices)
|
||||
minor=$(awk "\$2 ~ /^$DM_NAME\$/ {print \$1}" /proc/misc)
|
||||
major=$(grep "[0-9] misc$" /proc/devices | sed 's/[ ]\+misc//')
|
||||
minor=$(grep "[0-9] device-mapper$" /proc/misc | sed 's/[ ]\+device-mapper//')
|
||||
|
||||
if test ! -d $DIR; then
|
||||
mkdir --mode=755 $DIR >/dev/null 2>&1
|
||||
@@ -56,8 +56,7 @@ case "$1" in
|
||||
echo "$NAME."
|
||||
;;
|
||||
*)
|
||||
N=/etc/init.d/$NAME
|
||||
echo "Usage: $N {start|stop|restart|force-reload}" >&2
|
||||
echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
49
debian/postinst
vendored
49
debian/postinst
vendored
@@ -1,49 +0,0 @@
|
||||
#! /bin/sh
|
||||
# postinst script for lvm2
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
# summary of how this script can be called:
|
||||
# * <postinst> `configure' <most-recently-configured-version>
|
||||
# * <old-postinst> `abort-upgrade' <new version>
|
||||
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
|
||||
# <new-version>
|
||||
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
|
||||
# <failed-install-package> <version> `removing'
|
||||
# <conflicting-package> <version>
|
||||
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# the debian-policy package
|
||||
#
|
||||
# quoting from the policy:
|
||||
# Any necessary prompting should almost always be confined to the
|
||||
# post-installation script, and should be protected with a conditional
|
||||
# so that unnecessary prompting doesn't happen if a package's
|
||||
# installation fails and the `postinst' is called with `abort-upgrade',
|
||||
# `abort-remove' or `abort-deconfigure'.
|
||||
|
||||
case "$1" in
|
||||
configure)
|
||||
update-rc.d lvm2 start 25 S . start 50 0 6 . >/dev/null
|
||||
/etc/init.d/lvm2 start
|
||||
;;
|
||||
|
||||
abort-upgrade|abort-remove|abort-deconfigure)
|
||||
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postinst called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
|
||||
|
||||
39
debian/postrm
vendored
39
debian/postrm
vendored
@@ -1,39 +0,0 @@
|
||||
#! /bin/sh
|
||||
# postrm script for lvm2
|
||||
#
|
||||
# see: dh_installdeb(1)
|
||||
|
||||
set -e
|
||||
|
||||
# summary of how this script can be called:
|
||||
# * <postrm> `remove'
|
||||
# * <postrm> `purge'
|
||||
# * <old-postrm> `upgrade' <new-version>
|
||||
# * <new-postrm> `failed-upgrade' <old-version>
|
||||
# * <new-postrm> `abort-install'
|
||||
# * <new-postrm> `abort-install' <old-version>
|
||||
# * <new-postrm> `abort-upgrade' <old-version>
|
||||
# * <disappearer's-postrm> `disappear' <r>overwrit>r> <new-version>
|
||||
# for details, see http://www.debian.org/doc/debian-policy/ or
|
||||
# the debian-policy package
|
||||
|
||||
|
||||
case "$1" in
|
||||
purge)
|
||||
rm -f /etc/init.d/lvm2
|
||||
update-rc.d lvm2 remove >/dev/null
|
||||
;;
|
||||
remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postrm called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
esac
|
||||
|
||||
# dh_installdeb will replace this with shell code automatically
|
||||
# generated by other debhelper scripts.
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
||||
3
debian/rules
vendored
3
debian/rules
vendored
@@ -98,11 +98,10 @@ binary-arch: build install
|
||||
# dh_installemacsen -a
|
||||
# dh_installpam -a
|
||||
# dh_installmime -a
|
||||
dh_installinit -n
|
||||
dh_installinit --update-rcd-params="start 26 S . start 50 0 6 ."
|
||||
dh_installcron
|
||||
dh_installman
|
||||
dh_installinfo
|
||||
dh_undocumented
|
||||
dh_installchangelogs
|
||||
dh_strip
|
||||
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 $(top_srcdir)/make.tmpl
|
||||
|
||||
install:
|
||||
@if [ ! -e $(confdir)/$(CONFDEST) ]; then \
|
||||
echo "Installing $(CONFSRC) as $(confdir)/$(CONFDEST)"; \
|
||||
@INSTALL@ -D $(OWNER) $(GROUP) -m 644 $(CONFSRC) \
|
||||
$(confdir)/$(CONFDEST); \
|
||||
fi
|
||||
|
||||
222
doc/example.conf
222
doc/example.conf
@@ -1,74 +1,102 @@
|
||||
# This is an example configuration file for the LVM2 system. It
|
||||
# contains the default settings that would be used if there was no
|
||||
# This is an example configuration file for the LVM2 system.
|
||||
# It contains the default settings that would be used if there was no
|
||||
# /etc/lvm/lvm.conf file.
|
||||
# Refer to 'man lvm.conf' for further information.
|
||||
#
|
||||
# Refer to 'man lvm.conf' for further information including the file layout.
|
||||
#
|
||||
# To put this file in a different directory and override /etc/lvm set
|
||||
# the environment variable LVM_SYSTEM_DIR before running the tools.
|
||||
|
||||
|
||||
# This section allows the user to configure which block devices should
|
||||
# This section allows you to configure which block devices should
|
||||
# be used by the LVM system.
|
||||
devices {
|
||||
|
||||
# where do you want your volume groups to appear ?
|
||||
# Where do you want your volume groups to appear ?
|
||||
dir = "/dev"
|
||||
|
||||
# An array of directories that contain the device nodes you wish
|
||||
# to use with LVM2.
|
||||
scan = "/dev"
|
||||
|
||||
# A very important option, that allows you to tune the LVM2 system
|
||||
# to just look at a restricted set of devices that you're
|
||||
# interested in.
|
||||
scan = [ "/dev" ]
|
||||
|
||||
# A filter that tells LVM2 to only use a restricted set of devices.
|
||||
# The filter consists of an array of regular expressions. These
|
||||
# expressions can be delimited by a character of your choice, and
|
||||
# prefixed with either an 'a' (for accept) or 'r' (for reject).
|
||||
# ATM you cannot use anchors (^ or $) in your regular expression.
|
||||
# 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.
|
||||
# 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:
|
||||
filter = "a/.*/"
|
||||
filter = [ "a/.*/" ]
|
||||
|
||||
# Exclude the cdrom drive
|
||||
# filter = [ "r|/dev/cdrom|" ]
|
||||
|
||||
# When testing I like to work with just loopback devices:
|
||||
# filter = ["a/loop/", "r/.*/"]
|
||||
# filter = [ "a/loop/", "r/.*/" ]
|
||||
|
||||
# Or maybe all loops and ide drives except hdc:
|
||||
# filter =["a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|"]
|
||||
# filter =[ "a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|" ]
|
||||
|
||||
# The results of all the filtering are cached on disk to avoid
|
||||
# Use anchors if you want to be really specific
|
||||
# filter = [ "a|^/dev/hda8$|", "r/.*/" ]
|
||||
|
||||
# The results of the filtering are cached on disk to avoid
|
||||
# rescanning dud devices (which can take a very long time). By
|
||||
# default this cache file is hidden in the /etc/lvm directory, it
|
||||
# is human readable to aid filter debugging.
|
||||
# default this cache file is hidden in the /etc/lvm directory.
|
||||
# It is safe to delete this file: the tools regenerate it.
|
||||
cache = "/etc/lvm/.cache"
|
||||
|
||||
# You can turn off writing this cache file by setting this to 0.
|
||||
write_cache_state = 1
|
||||
|
||||
# Advanced settings.
|
||||
|
||||
# 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.
|
||||
# 1 enables; 0 disables.
|
||||
sysfs_scan = 1
|
||||
|
||||
# By default, LVM2 will ignore devices used as components of
|
||||
# software RAID (md) devices by looking for md superblocks.
|
||||
# 1 enables; 0 disables.
|
||||
md_component_detection = 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.
|
||||
log {
|
||||
|
||||
# Where should the log of error and debug messages go ? By
|
||||
# default there is no log.
|
||||
#file = "/var/log/lvm2.log"
|
||||
|
||||
# Should we overwrite the last log. By default we append.
|
||||
overwrite = 0
|
||||
|
||||
# There are 9 log levels, with 9 being the most verbose.
|
||||
level = 3
|
||||
|
||||
# Controls the messages sent to stdout or stderr while running
|
||||
# LVM2. There are three levels of verbosity, 3 being the most
|
||||
# verbose.
|
||||
# Controls the messages sent to stdout or stderr.
|
||||
# There are three levels of verbosity, 3 being the most verbose.
|
||||
verbose = 0
|
||||
|
||||
# Should we send log messages through syslog?
|
||||
# 1 is yes; 0 is no.
|
||||
syslog = 1
|
||||
|
||||
# Choose format of output messages
|
||||
# Should we log error and debug messages to a file?
|
||||
# By default there is no log file.
|
||||
#file = "/var/log/lvm2.log"
|
||||
|
||||
# Should we overwrite the log file each time the program is run?
|
||||
# By default we append.
|
||||
overwrite = 0
|
||||
|
||||
# What level of log messages should we send to the log file and/or syslog?
|
||||
# There are 6 syslog-like log levels currently in use - 2 to 7 inclusive.
|
||||
# 7 is the most verbose (LOG_DEBUG).
|
||||
level = 0
|
||||
|
||||
# Format of output messages
|
||||
# Whether or not (1 or 0) to indent messages according to their severity
|
||||
indent = 1
|
||||
|
||||
@@ -76,13 +104,18 @@ log {
|
||||
command_names = 0
|
||||
|
||||
# A prefix to use before the message text (but after the command name,
|
||||
# if selected)
|
||||
# if selected). Default is two spaces, so you can see/grep the severity
|
||||
# of each message.
|
||||
prefix = " "
|
||||
|
||||
# To make the messages look similar to the original LVM use:
|
||||
# To make the messages look similar to the original LVM tools use:
|
||||
# indent = 0
|
||||
# command_names = 1
|
||||
# prefix = " -- "
|
||||
|
||||
# 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
|
||||
@@ -93,19 +126,20 @@ backup {
|
||||
|
||||
# Should we maintain a backup of the current metadata configuration ?
|
||||
# Use 1 for Yes; 0 for No.
|
||||
# Think very hard before turning this off.
|
||||
# Think very hard before turning this off!
|
||||
backup = 1
|
||||
|
||||
# Where shall we keep it ?
|
||||
# Remember to back up this directory regularly!
|
||||
backup_dir = "/etc/lvm/backup"
|
||||
|
||||
|
||||
# Should we maintain an archive of old metadata configurations.
|
||||
# Use 1 for Yes; 0 for No.
|
||||
# On by default. Think very hard before turning this off.
|
||||
archive = 1
|
||||
|
||||
# Where should archived files go ?
|
||||
# Remember to back up this directory regularly!
|
||||
archive_dir = "/etc/lvm/archive"
|
||||
|
||||
# What is the minimum number of archive files you wish to keep ?
|
||||
@@ -115,14 +149,15 @@ backup {
|
||||
retain_days = 30
|
||||
}
|
||||
|
||||
# Settings for the running LVM2 in shell mode.
|
||||
# Settings for the running LVM2 in shell (readline) mode.
|
||||
shell {
|
||||
|
||||
# Number of lines of history to store in ~/.lvm_history
|
||||
history_size = 100
|
||||
}
|
||||
|
||||
# Miscellaneous global settings
|
||||
|
||||
# Miscellaneous global LVM2 settings
|
||||
global {
|
||||
|
||||
# The file creation mask for any files and directories created.
|
||||
@@ -136,4 +171,113 @@ global {
|
||||
# will be made. Equivalent to having the -t option on every
|
||||
# command. Defaults to off.
|
||||
test = 0
|
||||
|
||||
# Whether or not to communicate with the kernel device-mapper.
|
||||
# Set to 0 if you want to use the tools to manipulate LVM metadata
|
||||
# without activating any logical volumes.
|
||||
# If the device-mapper kernel driver is not present in your kernel
|
||||
# setting this to 0 should suppress the error messages.
|
||||
activation = 1
|
||||
|
||||
# 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
|
||||
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,7 @@
|
||||
../daemons/clvmd/clvm.h
|
||||
../lib/activate/activate.h
|
||||
../lib/activate/targets.h
|
||||
../lib/cache/lvmcache.h
|
||||
../lib/commands/errors.h
|
||||
../lib/commands/toolcontext.h
|
||||
../lib/config/config.h
|
||||
@@ -8,26 +11,39 @@
|
||||
../lib/datastruct/hash.h
|
||||
../lib/datastruct/list.h
|
||||
../lib/datastruct/lvm-types.h
|
||||
../lib/datastruct/str_list.h
|
||||
../lib/device/dev-cache.h
|
||||
../lib/device/device.h
|
||||
../lib/display/display.h
|
||||
../lib/filters/filter-composite.h
|
||||
../lib/filters/filter-md.h
|
||||
../lib/filters/filter-persistent.h
|
||||
../lib/filters/filter-regex.h
|
||||
../lib/filters/filter-sysfs.h
|
||||
../lib/filters/filter.h
|
||||
../lib/format1/format1.h
|
||||
../lib/format1/lvm1_label.h
|
||||
../lib/format_pool/format_pool.h
|
||||
../lib/format_text/format-text.h
|
||||
../lib/format_text/text_export.h
|
||||
../lib/format_text/text_import.h
|
||||
../lib/label/label.h
|
||||
../lib/label/uuid-map.h
|
||||
../lib/locking/locking.h
|
||||
../lib/log/log.h
|
||||
../lib/metadata/lv_alloc.h
|
||||
../lib/metadata/metadata.h
|
||||
../lib/metadata/segtypes.h
|
||||
../lib/mm/dbg_malloc.h
|
||||
../lib/mm/memlock.h
|
||||
../lib/mm/pool.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-string.h
|
||||
../lib/misc/selinux.h
|
||||
../lib/misc/sharedlib.h
|
||||
../lib/regex/matcher.h
|
||||
../lib/report/report.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
|
||||
# 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 file is part of the LVM2.
|
||||
#
|
||||
# This LVM library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Library General Public License for more details.
|
||||
# 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 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
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
@@ -24,6 +20,8 @@ VPATH = @srcdir@
|
||||
|
||||
LN_S = @LN_S@
|
||||
|
||||
.PHONY: clean distclean all install pofile install_cluster
|
||||
|
||||
all: .symlinks_created
|
||||
|
||||
.symlinks_created: .symlinks
|
||||
@@ -35,9 +33,11 @@ distclean:
|
||||
find . -maxdepth 1 -type l -exec $(RM) \{\} \;
|
||||
$(RM) Makefile .include_symlinks .symlinks_created
|
||||
|
||||
pofile: all
|
||||
|
||||
clean:
|
||||
|
||||
install:
|
||||
|
||||
.PHONY: clean distclean all install
|
||||
install_cluster:
|
||||
|
||||
|
||||
124
lib/Makefile.in
124
lib/Makefile.in
@@ -1,44 +1,66 @@
|
||||
#
|
||||
# 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@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
SOURCES=\
|
||||
ifeq ("@LVM1@", "shared")
|
||||
SUBDIRS = format1
|
||||
endif
|
||||
|
||||
ifeq ("@POOL@", "shared")
|
||||
SUBDIRS += format_pool
|
||||
endif
|
||||
|
||||
ifeq ("@SNAPSHOTS@", "shared")
|
||||
SUBDIRS += snapshot
|
||||
endif
|
||||
|
||||
ifeq ("@MIRRORS@", "shared")
|
||||
SUBDIRS += mirror
|
||||
endif
|
||||
|
||||
SOURCES =\
|
||||
activate/activate.c \
|
||||
activate/dev_manager.c \
|
||||
activate/fs.c \
|
||||
cache/lvmcache.c \
|
||||
commands/toolcontext.c \
|
||||
config/config.c \
|
||||
datastruct/bitset.c \
|
||||
datastruct/btree.c \
|
||||
datastruct/hash.c \
|
||||
datastruct/str_list.c \
|
||||
device/dev-cache.c \
|
||||
device/dev-io.c \
|
||||
device/device.c \
|
||||
display/display.c \
|
||||
error/errseg.c \
|
||||
filters/filter-composite.c \
|
||||
filters/filter-persistent.c \
|
||||
filters/filter-regex.c \
|
||||
filters/filter-sysfs.c \
|
||||
filters/filter-md.c \
|
||||
filters/filter.c \
|
||||
format1/disk-rep.c \
|
||||
format1/format1.c \
|
||||
format1/import-export.c \
|
||||
format1/import-extents.c \
|
||||
format1/layout.c \
|
||||
format1/lvm1_label.c \
|
||||
format1/vg_number.c \
|
||||
format_text/archive.c \
|
||||
format_text/export.c \
|
||||
format_text/flags.c \
|
||||
format_text/format-text.c \
|
||||
format_text/import.c \
|
||||
format_text/import_vsn1.c \
|
||||
format_text/tags.c \
|
||||
format_text/text_label.c \
|
||||
label/label.c \
|
||||
label/uuid-map.c \
|
||||
locking/external_locking.c \
|
||||
locking/file_locking.c \
|
||||
locking/locking.c \
|
||||
locking/no_locking.c \
|
||||
@@ -46,23 +68,81 @@ SOURCES=\
|
||||
metadata/lv_manip.c \
|
||||
metadata/merge.c \
|
||||
metadata/metadata.c \
|
||||
metadata/mirror.c \
|
||||
metadata/pv_map.c \
|
||||
metadata/segtypes.c \
|
||||
metadata/snapshot_manip.c \
|
||||
misc/crc.c \
|
||||
misc/lvm-file.c \
|
||||
mm/dbg_malloc.c \
|
||||
misc/lvm-string.c \
|
||||
mm/memlock.c \
|
||||
mm/pool.c \
|
||||
regex/matcher.c \
|
||||
regex/parse_rx.c \
|
||||
regex/ttree.c \
|
||||
report/report.c \
|
||||
striped/striped.c \
|
||||
uuid/uuid.c \
|
||||
vgcache/vgcache.c
|
||||
zero/zero.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
|
||||
|
||||
include ../make.tmpl
|
||||
ifeq ("@POOL@", "internal")
|
||||
SOURCES +=\
|
||||
format_pool/disk_rep.c \
|
||||
format_pool/format_pool.c \
|
||||
format_pool/import_export.c \
|
||||
format_pool/pool_label.c
|
||||
endif
|
||||
|
||||
liblvm.a: $(OBJECTS)
|
||||
$(RM) $@
|
||||
$(AR) r $@ $(OBJECTS)
|
||||
$(RANLIB) $@
|
||||
ifeq ("@CLUSTER@", "internal")
|
||||
SOURCES += locking/cluster_locking.c
|
||||
endif
|
||||
|
||||
ifeq ("@CLUSTER@", "shared")
|
||||
SUBDIRS += locking
|
||||
endif
|
||||
|
||||
ifeq ("@SNAPSHOTS@", "internal")
|
||||
SOURCES += snapshot/snapshot.c
|
||||
endif
|
||||
|
||||
ifeq ("@MIRRORS@", "internal")
|
||||
SOURCES += mirror/mirrored.c
|
||||
endif
|
||||
|
||||
ifeq ("@DEBUG@", "yes")
|
||||
SOURCES += mm/dbg_malloc.c
|
||||
endif
|
||||
|
||||
ifeq ("@DEVMAPPER@", "yes")
|
||||
SOURCES +=\
|
||||
activate/dev_manager.c \
|
||||
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 $(top_srcdir)/make.tmpl
|
||||
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "ll-activate.h"
|
||||
#include "lvm-string.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <libdevmapper.h>
|
||||
|
||||
/*
|
||||
* Emit a target for a given segment.
|
||||
* FIXME: tidy this function.
|
||||
*/
|
||||
static int _emit_target(struct dm_task *dmt, struct stripe_segment *seg)
|
||||
{
|
||||
char params[1024];
|
||||
uint64_t esize = seg->lv->vg->extent_size;
|
||||
uint32_t s, stripes = seg->stripes;
|
||||
int w = 0, tw = 0, error = 0;
|
||||
const char *no_space =
|
||||
"Insufficient space to write target parameters.";
|
||||
char *filler = "/dev/ioerror";
|
||||
char *target;
|
||||
|
||||
if (stripes == 1) {
|
||||
if (!seg->area[0].pv) {
|
||||
target = "error";
|
||||
error = 1;
|
||||
}
|
||||
else
|
||||
target = "linear";
|
||||
}
|
||||
|
||||
if (stripes > 1) {
|
||||
target = "striped";
|
||||
tw = lvm_snprintf(params, sizeof(params), "%u %u ",
|
||||
stripes, seg->stripe_size);
|
||||
|
||||
if (tw < 0) {
|
||||
log_err(no_space);
|
||||
return 0;
|
||||
}
|
||||
|
||||
w = tw;
|
||||
}
|
||||
|
||||
if (!error) {
|
||||
for (s = 0; s < stripes; s++, w += tw) {
|
||||
if (!seg->area[s].pv)
|
||||
tw = lvm_snprintf(
|
||||
params + w, sizeof(params) - w,
|
||||
"%s 0%s", filler,
|
||||
s == (stripes - 1) ? "" : " ");
|
||||
else
|
||||
tw = lvm_snprintf(
|
||||
params + w, sizeof(params) - w,
|
||||
"%s %" PRIu64 "%s",
|
||||
dev_name(seg->area[s].pv->dev),
|
||||
(seg->area[s].pv->pe_start +
|
||||
(esize * seg->area[s].pe)),
|
||||
s == (stripes - 1) ? "" : " ");
|
||||
|
||||
if (tw < 0) {
|
||||
log_err(no_space);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log_very_verbose("Adding target: %" PRIu64 " %" PRIu64 " %s %s",
|
||||
esize * seg->le, esize * seg->len,
|
||||
target, params);
|
||||
|
||||
if (!dm_task_add_target(dmt, esize * seg->le, esize * seg->len,
|
||||
target, params)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int device_populate_lv(struct dm_task *dmt, struct logical_volume *lv)
|
||||
{
|
||||
struct list *segh;
|
||||
struct stripe_segment *seg;
|
||||
|
||||
log_very_verbose("Generating devmapper table for %s", lv->name);
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct stripe_segment);
|
||||
if (!_emit_target(dmt, seg)) {
|
||||
log_error("Unable to build table for '%s'", lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1,30 +1,261 @@
|
||||
/*
|
||||
* 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 "activate.h"
|
||||
#include "memlock.h"
|
||||
#include "display.h"
|
||||
#include "log.h"
|
||||
#include "fs.h"
|
||||
#include "lvm-file.h"
|
||||
#include "lvm-string.h"
|
||||
#include "pool.h"
|
||||
#include "toolcontext.h"
|
||||
#include "dev_manager.h"
|
||||
|
||||
/* FIXME Temporary */
|
||||
#include "vgcache.h"
|
||||
#include "str_list.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
const 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 host 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))
|
||||
return 0;
|
||||
return 1;
|
||||
@@ -35,6 +266,9 @@ int driver_version(char *version, size_t size)
|
||||
int r = 0;
|
||||
struct dm_task *dmt;
|
||||
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
log_very_verbose("Getting driver version");
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_VERSION))) {
|
||||
stack;
|
||||
@@ -55,29 +289,153 @@ int driver_version(char *version, size_t size)
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if info structure populated, else 0 on failure.
|
||||
*/
|
||||
int lv_info(struct logical_volume *lv, struct dm_info *info)
|
||||
int target_present(const char *target_name)
|
||||
{
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
int r = 0;
|
||||
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;
|
||||
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->cmd, lv->vg->name))) {
|
||||
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);
|
||||
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.
|
||||
*/
|
||||
int lv_snapshot_percent(struct logical_volume *lv, float *percent)
|
||||
{
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(r = dev_manager_snapshot_percent(dm, lv, percent)))
|
||||
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->cmd, lv->vg->name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(r = dev_manager_mirror_percent(dm, lv, wait, percent, event_nr)))
|
||||
stack;
|
||||
|
||||
dev_manager_destroy(dm);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _lv_active(struct logical_volume *lv)
|
||||
{
|
||||
struct dm_info info;
|
||||
struct lvinfo info;
|
||||
|
||||
if (!lv_info(lv, &info)) {
|
||||
stack;
|
||||
@@ -89,7 +447,7 @@ static int _lv_active(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)) {
|
||||
stack;
|
||||
@@ -100,12 +458,12 @@ static int _lv_open_count(struct logical_volume *lv)
|
||||
}
|
||||
|
||||
/* 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;
|
||||
struct dev_manager *dm;
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->name))) {
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -122,7 +480,7 @@ static int _lv_deactivate(struct logical_volume *lv)
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->name))) {
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -134,12 +492,12 @@ static int _lv_deactivate(struct logical_volume *lv)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _lv_suspend(struct logical_volume *lv)
|
||||
static int _lv_suspend_lv(struct logical_volume *lv)
|
||||
{
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->name))) {
|
||||
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -152,7 +510,7 @@ static int _lv_suspend(struct logical_volume *lv)
|
||||
}
|
||||
|
||||
/*
|
||||
* These two functions return the number of LVs in the state,
|
||||
* These two functions return the number of visible LVs in the state,
|
||||
* or -1 on error.
|
||||
*/
|
||||
int lvs_in_vg_activated(struct volume_group *vg)
|
||||
@@ -161,9 +519,13 @@ int lvs_in_vg_activated(struct volume_group *vg)
|
||||
struct logical_volume *lv;
|
||||
int count = 0;
|
||||
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
count += (_lv_active(lv) == 1);
|
||||
if (lv->status & VISIBLE_LV)
|
||||
count += (_lv_active(lv) == 1);
|
||||
}
|
||||
|
||||
return count;
|
||||
@@ -175,133 +537,33 @@ int lvs_in_vg_opened(struct volume_group *vg)
|
||||
struct logical_volume *lv;
|
||||
int count = 0;
|
||||
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
count += (_lv_open_count(lv) == 1);
|
||||
if (lv->status & VISIBLE_LV)
|
||||
count += (_lv_open_count(lv) > 0);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct logical_volume *_lv_from_lvid(struct cmd_context *cmd,
|
||||
const char *lvid_s)
|
||||
{
|
||||
struct lv_list *lvl;
|
||||
struct volume_group *vg;
|
||||
union lvid *lvid;
|
||||
char *vgname;
|
||||
|
||||
lvid = (union lvid *) lvid_s;
|
||||
|
||||
/* FIXME Change vgread to accept vgid directly - can't rely on cache */
|
||||
if (!(vgname = vgname_from_vgid(cmd, &lvid->id[0]))) {
|
||||
log_error("Volume group for uuid not found: %s", lvid_s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log_verbose("Finding volume group \"%s\"", vgname);
|
||||
if (!(vg = cmd->fid->ops->vg_read(cmd->fid, vgname))) {
|
||||
log_error("Volume group \"%s\" doesn't exist", vgname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group \"%s\" is exported", vgname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(lvl = find_lv_in_vg_by_lvid(vg, lvid))) {
|
||||
log_very_verbose("Can't find logical volume id %s", lvid_s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return lvl->lv;
|
||||
}
|
||||
|
||||
/* These return success if the device is not active */
|
||||
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s)
|
||||
static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
int error_if_not_suspended)
|
||||
{
|
||||
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;
|
||||
|
||||
if (test_mode()) {
|
||||
_skip("Suspending '%s'.", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_info(lv, &info)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info.exists && !info.suspended)
|
||||
return _lv_suspend(lv);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s)
|
||||
{
|
||||
struct logical_volume *lv;
|
||||
struct dm_info info;
|
||||
|
||||
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
|
||||
return 0;
|
||||
|
||||
if (test_mode()) {
|
||||
_skip("Resuming '%s'.", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_info(lv, &info)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info.exists && info.suspended)
|
||||
return _lv_activate(lv);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
|
||||
{
|
||||
struct logical_volume *lv;
|
||||
struct dm_info info;
|
||||
|
||||
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
|
||||
return 0;
|
||||
|
||||
if (test_mode()) {
|
||||
_skip("Deactivating '%s'.", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_info(lv, &info)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info.exists)
|
||||
return _lv_deactivate(lv);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lv_activate(struct cmd_context *cmd, const char *lvid_s)
|
||||
{
|
||||
struct logical_volume *lv;
|
||||
struct dm_info info;
|
||||
|
||||
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
|
||||
return 0;
|
||||
|
||||
if (test_mode()) {
|
||||
_skip("Activating '%s'.", lv->name);
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!lv_info(lv, &info)) {
|
||||
@@ -310,7 +572,216 @@ int lv_activate(struct cmd_context *cmd, const char *lvid_s)
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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,35 +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
|
||||
#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 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.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*
|
||||
* These should eventually use config file
|
||||
* to determine whether or not to activate
|
||||
* Returns 1 if activate_lv has been set: 1 = activate; 0 = don't.
|
||||
*/
|
||||
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);
|
||||
int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
|
||||
int *activate_lv);
|
||||
|
||||
/*
|
||||
* FIXME:
|
||||
* I don't like the *lvs_in_vg* function names.
|
||||
* Returns 1 if percent has been set, else 0.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*
|
||||
* Return number of LVs in the VG that are active.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,33 @@
|
||||
/*
|
||||
* 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
|
||||
#define _LVM_DEV_MANAGER_H
|
||||
|
||||
#include "metadata.h"
|
||||
|
||||
#include <libdevmapper.h>
|
||||
|
||||
struct logical_volume;
|
||||
struct cmd_context;
|
||||
struct dev_manager;
|
||||
struct dm_info;
|
||||
|
||||
/*
|
||||
* Constructor and destructor.
|
||||
*/
|
||||
struct dev_manager *dev_manager_create(const char *vg_name);
|
||||
struct dev_manager *dev_manager_create(struct cmd_context *cmd,
|
||||
const char *vg_name);
|
||||
void dev_manager_destroy(struct dev_manager *dm);
|
||||
void dev_manager_exit(void);
|
||||
|
||||
/*
|
||||
* The device handler is responsible for creating all the layered
|
||||
@@ -25,12 +35,20 @@ void dev_manager_destroy(struct dev_manager *dm);
|
||||
* (eg, an origin is created before its snapshot, but is not
|
||||
* unsuspended until the snapshot is also created.)
|
||||
*/
|
||||
int dev_manager_info(struct dev_manager *dm, struct logical_volume *lv,
|
||||
struct dm_info *info);
|
||||
int dev_manager_info(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
int mknodes, struct dm_info *info);
|
||||
int dev_manager_snapshot_percent(struct dev_manager *dm,
|
||||
struct logical_volume *lv, float *percent);
|
||||
int dev_manager_mirror_percent(struct dev_manager *dm,
|
||||
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_activate(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.
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
|
||||
#ifndef DMFS_INTERFACE_H
|
||||
#define DMFS_INTERFACE_H
|
||||
|
||||
struct dmfs;
|
||||
|
||||
struct dmfs *dmfs_create(void);
|
||||
void dmfs_destroy(struct dmfs *dm);
|
||||
|
||||
int dmfs_dev_is_present(struct dmfs *dm, const char *dev);
|
||||
int dmfs_dev_is_active(struct dmfs *dm, const char *dev);
|
||||
|
||||
int dmfs_table_is_present(struct dmfs *dm, const char *dev, const char *table);
|
||||
int dmfs_table_is_active(struct dmfs *dm, const char *dev, const char *table);
|
||||
|
||||
int dmfs_dev_create(struct dmfs *dm, const char *name);
|
||||
int dmfs_dev_load_table(struct dmfs *dm, const char *dev,
|
||||
const char *table, const char *file);
|
||||
int dmfs_dev_drop_table(struct dmfs *dm, const char *dev, const char *table);
|
||||
|
||||
int dmfs_dev_activate_table(struct dmfs *dm, const char *dev,
|
||||
const char *table);
|
||||
|
||||
int dmfs_dev_deactivate(struct dmfs *dm, const char *dev);
|
||||
|
||||
#endif
|
||||
@@ -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 "log.h"
|
||||
#include "toolcontext.h"
|
||||
#include "lvm-string.h"
|
||||
#include "lvm-file.h"
|
||||
#include "memlock.h"
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
# include "selinux.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <dirent.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];
|
||||
|
||||
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 "
|
||||
"group directory.");
|
||||
return 0;
|
||||
@@ -35,7 +46,7 @@ static int _mk_dir(struct volume_group *vg)
|
||||
return 1;
|
||||
|
||||
log_very_verbose("Creating directory %s", vg_path);
|
||||
if (mkdir(vg_path, 0555)) {
|
||||
if (mkdir(vg_path, 0777)) {
|
||||
log_sys_error("mkdir", vg_path);
|
||||
return 0;
|
||||
}
|
||||
@@ -43,12 +54,12 @@ static int _mk_dir(struct volume_group *vg)
|
||||
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];
|
||||
|
||||
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 "
|
||||
"group directory.");
|
||||
return 0;
|
||||
@@ -62,32 +73,100 @@ static int _rm_dir(struct volume_group *vg)
|
||||
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;
|
||||
|
||||
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
|
||||
lv->vg->cmd->dev_dir, lv->vg->name, lv->name) == -1) {
|
||||
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
|
||||
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 "
|
||||
"logical volume link %s", lv->name);
|
||||
"logical volume link %s", lv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(link_path, sizeof(link_path), "%s/%s",
|
||||
dm_dir(), dev) == -1) {
|
||||
log_error("Couldn't create destination pathname for "
|
||||
"logical volume link for %s", lv->name);
|
||||
"logical volume link for %s", lv_name);
|
||||
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 (!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",
|
||||
link_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_very_verbose("Removing %s", lv_path);
|
||||
if (unlink(lv_path) < 0) {
|
||||
log_sys_error("unlink", lv_path);
|
||||
return 0;
|
||||
@@ -100,26 +179,36 @@ static int _mk_link(struct logical_volume *lv, const char *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
if (!set_selinux_context(lv_path)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
char lv_path[PATH_MAX];
|
||||
|
||||
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.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_very_verbose("Removing link %s", lv_path);
|
||||
if (lstat(lv_path, &buf) || !S_ISLNK(buf.st_mode)) {
|
||||
log_error("%s not symbolic link - not removing", lv_path);
|
||||
if (errno != ENOENT)
|
||||
log_error("%s not symbolic link - not removing",
|
||||
lv_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_very_verbose("Removing link %s", lv_path);
|
||||
if (unlink(lv_path) < 0) {
|
||||
log_sys_error("unlink", lv_path);
|
||||
return 0;
|
||||
@@ -128,35 +217,143 @@ static int _rm_link(struct logical_volume *lv, const char *lv_name)
|
||||
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)) {
|
||||
stack;
|
||||
return 0;
|
||||
switch (type) {
|
||||
case FS_ADD:
|
||||
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;
|
||||
}
|
||||
|
||||
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)) {
|
||||
stack;
|
||||
strcpy(*pos, str);
|
||||
*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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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,
|
||||
const char *dev, const char *old_name)
|
||||
{
|
||||
if (old_name && !_rm_link(lv, old_name))
|
||||
stack;
|
||||
|
||||
if (!_mk_link(lv, dev))
|
||||
stack;
|
||||
|
||||
return 1;
|
||||
return _fs_op(FS_RENAME, lv->vg->cmd->dev_dir, lv->vg->name, lv->name,
|
||||
dev, old_name);
|
||||
}
|
||||
|
||||
void fs_unlock(void)
|
||||
{
|
||||
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
|
||||
@@ -14,10 +23,10 @@
|
||||
* up the volume group directory in /dev and the
|
||||
* symbolic links to the dm device.
|
||||
*/
|
||||
int fs_add_lv(struct logical_volume *lv, const char *dev);
|
||||
int fs_del_lv(struct logical_volume *lv);
|
||||
int fs_add_lv(const struct logical_volume *lv, const char *dev);
|
||||
int fs_del_lv(const struct logical_volume *lv);
|
||||
int fs_rename_lv(struct logical_volume *lv,
|
||||
const char *dev, const char *old_name);
|
||||
|
||||
void fs_unlock(void);
|
||||
|
||||
#endif
|
||||
|
||||
25
lib/activate/targets.h
Normal file
25
lib/activate/targets.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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_TARGETS_H
|
||||
#define _LVM_TARGETS_H
|
||||
|
||||
struct dev_manager;
|
||||
struct lv_segment;
|
||||
|
||||
int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg, char *params, size_t paramsize, int *pos,
|
||||
int start_area, int areas);
|
||||
|
||||
#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);
|
||||
}
|
||||
87
lib/cache/lvmcache.h
vendored
Normal file
87
lib/cache/lvmcache.h
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
#define ORPHAN ""
|
||||
|
||||
#define CACHE_INVALID 0x00000001
|
||||
#define CACHE_LOCKED 0x00000002
|
||||
|
||||
/* LVM specific per-volume info */
|
||||
/* Eventual replacement for struct physical_volume perhaps? */
|
||||
|
||||
struct cmd_context;
|
||||
struct format_type;
|
||||
struct volume_group;
|
||||
|
||||
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
|
||||
#define _LVM_ERRORS_H
|
||||
|
||||
#define EINVALID_CMD_LINE 1
|
||||
#define ENO_SUCH_CMD 3
|
||||
#define ECMD_PROCESSED 4
|
||||
#define ECMD_PROCESSED 1
|
||||
#define ENO_SUCH_CMD 2
|
||||
#define EINVALID_CMD_LINE 3
|
||||
#define ECMD_FAILED 5
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
1005
lib/commands/toolcontext.c
Normal file
1005
lib/commands/toolcontext.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,33 +1,92 @@
|
||||
/*
|
||||
* 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
|
||||
#define _LVM_TOOLCONTEXT_H
|
||||
|
||||
#include "dev-cache.h"
|
||||
#include "config.h"
|
||||
#include "pool.h"
|
||||
#include "metadata.h"
|
||||
|
||||
/* command-instance-related variables needed by library */
|
||||
struct cmd_context {
|
||||
/* format handler allocates all objects from here */
|
||||
struct pool *mem;
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
struct format_instance *fid;
|
||||
/*
|
||||
* 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? */
|
||||
|
||||
char *cmd_line;
|
||||
char *dev_dir;
|
||||
struct dev_filter *filter;
|
||||
struct config_file *cf;
|
||||
int archive; /* should we archive ? */
|
||||
int backup; /* should we backup ? */
|
||||
|
||||
struct command *command;
|
||||
struct uuid_map *um;
|
||||
struct arg *args;
|
||||
struct format_type *fmt;
|
||||
|
||||
mode_t umask;
|
||||
};
|
||||
|
||||
struct config_tree;
|
||||
|
||||
/* 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 */
|
||||
struct list segtypes; /* Available segment types */
|
||||
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 list config_files;
|
||||
int config_valid;
|
||||
struct config_tree *cft;
|
||||
struct config_info default_settings;
|
||||
struct config_info current_settings;
|
||||
|
||||
/* List of defined tags */
|
||||
struct list tags;
|
||||
int hosttags;
|
||||
|
||||
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);
|
||||
int config_files_changed(struct cmd_context *cmd);
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,72 +1,96 @@
|
||||
/*
|
||||
* 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
|
||||
#define _LVM_CONFIG_H
|
||||
|
||||
#include <inttypes.h>
|
||||
struct device;
|
||||
struct cmd_context;
|
||||
|
||||
enum {
|
||||
CFG_STRING,
|
||||
CFG_FLOAT,
|
||||
CFG_INT,
|
||||
CFG_STRING,
|
||||
CFG_FLOAT,
|
||||
CFG_INT,
|
||||
CFG_EMPTY_ARRAY
|
||||
};
|
||||
|
||||
struct config_value {
|
||||
int type;
|
||||
union {
|
||||
int i;
|
||||
float r;
|
||||
char *str;
|
||||
} v;
|
||||
struct config_value *next; /* for arrays */
|
||||
int type;
|
||||
union {
|
||||
int i;
|
||||
float r;
|
||||
char *str;
|
||||
} v;
|
||||
struct config_value *next; /* for arrays */
|
||||
};
|
||||
|
||||
struct config_node {
|
||||
char *key;
|
||||
struct config_node *sib, *child;
|
||||
struct config_value *v;
|
||||
char *key;
|
||||
struct config_node *sib, *child;
|
||||
struct config_value *v;
|
||||
};
|
||||
|
||||
struct config_file {
|
||||
struct config_node *root;
|
||||
struct config_tree {
|
||||
struct config_node *root;
|
||||
};
|
||||
|
||||
struct config_file *create_config_file(void);
|
||||
void destroy_config_file(struct config_file *cf);
|
||||
struct config_tree_list {
|
||||
struct list list;
|
||||
struct config_tree *cft;
|
||||
};
|
||||
|
||||
int read_config(struct config_file *cf, const char *file);
|
||||
int write_config(struct config_file *cf, const char *file);
|
||||
struct config_tree *create_config_tree(const char *filename);
|
||||
void destroy_config_tree(struct config_tree *cft);
|
||||
|
||||
struct config_node *find_config_node(struct config_node *cn,
|
||||
const char *path, char seperator);
|
||||
typedef uint32_t (*checksum_fn_t) (uint32_t initial, void *buf, uint32_t size);
|
||||
|
||||
const char *find_config_str(struct config_node *cn,
|
||||
const char *path, char sep, const char *fail);
|
||||
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);
|
||||
|
||||
int find_config_int(struct config_node *cn, const char *path,
|
||||
char sep, int fail);
|
||||
int read_config_file(struct config_tree *cft);
|
||||
int write_config_file(struct config_tree *cft, const char *file);
|
||||
time_t config_file_timestamp(struct config_tree *cft);
|
||||
int config_file_changed(struct config_tree *cft);
|
||||
int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
|
||||
struct config_tree *newdata);
|
||||
|
||||
float find_config_float(struct config_node *cn, const char *path,
|
||||
char sep, float fail);
|
||||
struct config_node *find_config_node(const struct config_node *cn,
|
||||
const char *path);
|
||||
|
||||
const char *find_config_str(const struct config_node *cn, const char *path,
|
||||
const char *fail);
|
||||
|
||||
int find_config_int(const struct config_node *cn, const char *path, int fail);
|
||||
|
||||
float find_config_float(const struct config_node *cn, const char *path,
|
||||
float fail);
|
||||
|
||||
/*
|
||||
* Understands (0, ~0), (y, n), (yes, no), (on,
|
||||
* off), (true, false).
|
||||
*/
|
||||
int find_config_bool(struct config_node *cn, const char *path,
|
||||
char sep, int fail);
|
||||
int find_config_bool(const struct config_node *cn, const char *path, int fail);
|
||||
|
||||
int get_config_uint32(const struct config_node *cn, const char *path,
|
||||
uint32_t *result);
|
||||
|
||||
int get_config_uint64(const struct config_node *cn, const char *path,
|
||||
uint64_t *result);
|
||||
|
||||
int get_config_uint32(struct config_node *cn, const char *path,
|
||||
char sep, uint32_t *result);
|
||||
|
||||
int get_config_uint64(struct config_node *cn, const char *path,
|
||||
char sep, uint64_t *result);
|
||||
int get_config_str(const struct config_node *cn, const char *path,
|
||||
char **result);
|
||||
|
||||
#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
|
||||
#define _LVM_DEFAULTS_H
|
||||
|
||||
|
||||
#define DEFAULT_SYS_DIR "/etc/lvm"
|
||||
|
||||
#define DEFAULT_ARCHIVE_ENABLED 1
|
||||
#define DEFAULT_BACKUP_ENABLED 1
|
||||
|
||||
@@ -19,16 +25,85 @@
|
||||
#define DEFAULT_ARCHIVE_DAYS 30
|
||||
#define DEFAULT_ARCHIVE_NUMBER 10
|
||||
|
||||
#define DEFAULT_SYS_DIR "/etc/lvm"
|
||||
#define DEFAULT_DEV_DIR "/dev"
|
||||
#define DEFAULT_PROC_DIR "/proc"
|
||||
#define DEFAULT_SYSFS_SCAN 1
|
||||
#define DEFAULT_MD_COMPONENT_DETECTION 1
|
||||
|
||||
#define DEFAULT_LOCK_DIR "/var/lock/lvm"
|
||||
#define DEFAULT_LOCKING_LIB "lvm2_locking.so"
|
||||
|
||||
#define DEFAULT_UMASK 0077
|
||||
|
||||
#ifdef READLINE_SUPPORT
|
||||
#define DEFAULT_MAX_HISTORY 100
|
||||
#ifdef LVM1_FALLBACK
|
||||
# define DEFAULT_FALLBACK_TO_LVM1 1
|
||||
#else
|
||||
# define DEFAULT_FALLBACK_TO_LVM1 0
|
||||
#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,copy_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,lv_kernel_major,lv_kernel_minor,origin,snap_percent,move_pv,copy_percent,lv_uuid"
|
||||
#define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid"
|
||||
#define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,dev_size,pv_uuid"
|
||||
#define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize"
|
||||
|
||||
#define DEFAULT_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 "dbg_malloc.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* FIXME: calculate this. */
|
||||
#define INT_SHIFT 5
|
||||
|
||||
bitset_t bitset_create(struct pool *mem, unsigned num_bits)
|
||||
{
|
||||
int n = (num_bits / BITS_PER_INT) + 2;
|
||||
int size = sizeof(int) * n;
|
||||
unsigned n = (num_bits / BITS_PER_INT) + 2;
|
||||
size_t size = sizeof(int) * n;
|
||||
unsigned *bs = pool_zalloc(mem, size);
|
||||
|
||||
if (!bs)
|
||||
@@ -33,7 +40,7 @@ void bitset_destroy(bitset_t bs)
|
||||
void bit_union(bitset_t out, bitset_t in1, bitset_t in2)
|
||||
{
|
||||
int i;
|
||||
for(i = (in1[0] / BITS_PER_INT) + 1; i; i--)
|
||||
for (i = (in1[0] / BITS_PER_INT) + 1; i; i--)
|
||||
out[i] = in1[i] | in2[i];
|
||||
}
|
||||
|
||||
@@ -58,7 +65,7 @@ int bit_get_next(bitset_t bs, int last_bit)
|
||||
|
||||
last_bit++; /* otherwise we'll return the same bit again */
|
||||
|
||||
while(last_bit < bs[0]) {
|
||||
while (last_bit < bs[0]) {
|
||||
word = last_bit >> INT_SHIFT;
|
||||
test = bs[word + 1];
|
||||
bit = last_bit & (BITS_PER_INT - 1);
|
||||
@@ -66,8 +73,8 @@ int bit_get_next(bitset_t bs, int last_bit)
|
||||
if ((bit = _test_word(test, bit)) >= 0)
|
||||
return (word * BITS_PER_INT) + bit;
|
||||
|
||||
last_bit = last_bit - (last_bit & (BITS_PER_INT - 1)) +
|
||||
BITS_PER_INT;
|
||||
last_bit = last_bit - (last_bit & (BITS_PER_INT - 1)) +
|
||||
BITS_PER_INT;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
@@ -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
|
||||
#define _LVM_BITSET_H
|
||||
|
||||
#include "lvm-types.h"
|
||||
#include "pool.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
typedef uint32_t *bitset_t;
|
||||
|
||||
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);
|
||||
int bit_get_first(bitset_t bs);
|
||||
int bit_get_next(bitset_t bs, int last_bit);
|
||||
|
||||
|
||||
#define BITS_PER_INT (sizeof(int) * CHAR_BIT)
|
||||
|
||||
#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 "log.h"
|
||||
|
||||
struct node {
|
||||
uint32_t key;
|
||||
@@ -40,14 +49,13 @@ static uint32_t _shuffle(uint32_t k)
|
||||
#if 1
|
||||
return ((k & 0xff) << 24 |
|
||||
(k & 0xff00) << 8 |
|
||||
(k & 0xff0000) >> 8 |
|
||||
(k & 0xff000000) >> 24);
|
||||
(k & 0xff0000) >> 8 | (k & 0xff000000) >> 24);
|
||||
#else
|
||||
return k;
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
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
|
||||
#define _LVM_BTREE_H
|
||||
|
||||
#include "lvm-types.h"
|
||||
#include "pool.h"
|
||||
|
||||
struct btree;
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
/*
|
||||
* 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 "log.h"
|
||||
|
||||
struct hash_node {
|
||||
struct hash_node *next;
|
||||
void *data;
|
||||
char key[1];
|
||||
int keylen;
|
||||
char key[0];
|
||||
};
|
||||
|
||||
struct hash_table {
|
||||
@@ -23,40 +31,49 @@ struct hash_table {
|
||||
|
||||
/* Permutation of the Integers 0 through 255 */
|
||||
static unsigned char _nums[] = {
|
||||
1, 14,110, 25, 97,174,132,119,138,170,125,118, 27,233,140, 51,
|
||||
87,197,177,107,234,169, 56, 68, 30, 7,173, 73,188, 40, 36, 65,
|
||||
49,213,104,190, 57,211,148,223, 48,115, 15, 2, 67,186,210, 28,
|
||||
12,181,103, 70, 22, 58, 75, 78,183,167,238,157,124,147,172,144,
|
||||
176,161,141, 86, 60, 66,128, 83,156,241, 79, 46,168,198, 41,254,
|
||||
178, 85,253,237,250,154,133, 88, 35,206, 95,116,252,192, 54,221,
|
||||
102,218,255,240, 82,106,158,201, 61, 3, 89, 9, 42,155,159, 93,
|
||||
166, 80, 50, 34,175,195,100, 99, 26,150, 16,145, 4, 33, 8,189,
|
||||
121, 64, 77, 72,208,245,130,122,143, 55,105,134, 29,164,185,194,
|
||||
193,239,101,242, 5,171,126, 11, 74, 59,137,228,108,191,232,139,
|
||||
6, 24, 81, 20,127, 17, 91, 92,251,151,225,207, 21, 98,113,112,
|
||||
84,226, 18,214,199,187, 13, 32, 94,220,224,212,247,204,196, 43,
|
||||
249,236, 45,244,111,182,153,136,129, 90,217,202, 19,165,231, 71,
|
||||
230,142, 96,227, 62,179,246,114,162, 53,160,215,205,180, 47,109,
|
||||
44, 38, 31,149,135, 0,216, 52, 63, 23, 37, 69, 39,117,146,184,
|
||||
163,200,222,235,248,243,219, 10,152,131,123,229,203, 76,120,209
|
||||
1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51,
|
||||
87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65,
|
||||
49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28,
|
||||
12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172,
|
||||
144,
|
||||
176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79, 46, 168, 198, 41, 254,
|
||||
178, 85, 253, 237, 250, 154, 133, 88, 35, 206, 95, 116, 252, 192, 54,
|
||||
221,
|
||||
102, 218, 255, 240, 82, 106, 158, 201, 61, 3, 89, 9, 42, 155, 159, 93,
|
||||
166, 80, 50, 34, 175, 195, 100, 99, 26, 150, 16, 145, 4, 33, 8, 189,
|
||||
121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185,
|
||||
194,
|
||||
193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232,
|
||||
139,
|
||||
6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112,
|
||||
84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196,
|
||||
43,
|
||||
249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231,
|
||||
71,
|
||||
230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47,
|
||||
109,
|
||||
44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184,
|
||||
163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120,
|
||||
209
|
||||
};
|
||||
|
||||
static struct hash_node *_create_node(const char *str)
|
||||
static struct hash_node *_create_node(const char *str, int len)
|
||||
{
|
||||
/* remember sizeof(n) includes an extra char from key[1],
|
||||
so not adding 1 to the strlen as you would expect */
|
||||
struct hash_node *n = dbg_malloc(sizeof(*n) + strlen(str));
|
||||
struct hash_node *n = dbg_malloc(sizeof(*n) + len);
|
||||
|
||||
if (n)
|
||||
strcpy(n->key, str);
|
||||
if (n) {
|
||||
memcpy(n->key, str, len);
|
||||
n->keylen = len;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static unsigned _hash(const char *str)
|
||||
static unsigned _hash(const char *str, uint32_t len)
|
||||
{
|
||||
unsigned long int h = 0, g;
|
||||
while (*str) {
|
||||
unsigned long h = 0, g, i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
h <<= 4;
|
||||
h += _nums[(int) *str++];
|
||||
g = h & ((unsigned long) 0xf << 16u);
|
||||
@@ -65,6 +82,7 @@ static unsigned _hash(const char *str)
|
||||
h ^= g >> 5u;
|
||||
}
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
@@ -83,7 +101,7 @@ struct hash_table *hash_create(unsigned size_hint)
|
||||
|
||||
/* round size hint up to a power of two */
|
||||
while (new_size < size_hint)
|
||||
new_size = new_size << 1;
|
||||
new_size = new_size << 1;
|
||||
|
||||
hc->num_slots = new_size;
|
||||
len = sizeof(*(hc->slots)) * new_size;
|
||||
@@ -94,7 +112,7 @@ struct hash_table *hash_create(unsigned size_hint)
|
||||
memset(hc->slots, 0, len);
|
||||
return hc;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
dbg_free(hc->slots);
|
||||
dbg_free(hc);
|
||||
return 0;
|
||||
@@ -119,32 +137,35 @@ void hash_destroy(struct hash_table *t)
|
||||
dbg_free(t);
|
||||
}
|
||||
|
||||
static inline struct hash_node **_find(struct hash_table *t, const char *key)
|
||||
static inline struct hash_node **_find(struct hash_table *t, const char *key,
|
||||
uint32_t len)
|
||||
{
|
||||
unsigned h = _hash(key) & (t->num_slots - 1);
|
||||
unsigned h = _hash(key, len) & (t->num_slots - 1);
|
||||
struct hash_node **c;
|
||||
|
||||
for(c = &t->slots[h]; *c; c = &((*c)->next))
|
||||
if(!strcmp(key, (*c)->key))
|
||||
for (c = &t->slots[h]; *c; c = &((*c)->next))
|
||||
if (!memcmp(key, (*c)->key, len))
|
||||
break;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void *hash_lookup(struct hash_table *t, const char *key)
|
||||
void *hash_lookup_binary(struct hash_table *t, const char *key,
|
||||
uint32_t len)
|
||||
{
|
||||
struct hash_node **c = _find(t, key);
|
||||
struct hash_node **c = _find(t, key, len);
|
||||
return *c ? (*c)->data : 0;
|
||||
}
|
||||
|
||||
int hash_insert(struct hash_table *t, const char *key, void *data)
|
||||
int hash_insert_binary(struct hash_table *t, const char *key,
|
||||
uint32_t len, void *data)
|
||||
{
|
||||
struct hash_node **c = _find(t, key);
|
||||
struct hash_node **c = _find(t, key, len);
|
||||
|
||||
if(*c)
|
||||
if (*c)
|
||||
(*c)->data = data;
|
||||
else {
|
||||
struct hash_node *n = _create_node(key);
|
||||
struct hash_node *n = _create_node(key, len);
|
||||
|
||||
if (!n)
|
||||
return 0;
|
||||
@@ -158,9 +179,10 @@ int hash_insert(struct hash_table *t, const char *key, void *data)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void hash_remove(struct hash_table *t, const char *key)
|
||||
void hash_remove_binary(struct hash_table *t, const char *key,
|
||||
uint32_t len)
|
||||
{
|
||||
struct hash_node **c = _find(t, key);
|
||||
struct hash_node **c = _find(t, key, len);
|
||||
|
||||
if (*c) {
|
||||
struct hash_node *old = *c;
|
||||
@@ -170,6 +192,21 @@ void hash_remove(struct hash_table *t, const char *key)
|
||||
}
|
||||
}
|
||||
|
||||
void *hash_lookup(struct hash_table *t, const char *key)
|
||||
{
|
||||
return hash_lookup_binary(t, key, strlen(key) + 1);
|
||||
}
|
||||
|
||||
int hash_insert(struct hash_table *t, const char *key, void *data)
|
||||
{
|
||||
return hash_insert_binary(t, key, strlen(key) + 1, data);
|
||||
}
|
||||
|
||||
void hash_remove(struct hash_table *t, const char *key)
|
||||
{
|
||||
hash_remove_binary(t, key, strlen(key) + 1);
|
||||
}
|
||||
|
||||
unsigned hash_get_num_entries(struct hash_table *t)
|
||||
{
|
||||
return t->num_nodes;
|
||||
@@ -202,7 +239,7 @@ void *hash_get_data(struct hash_table *t, struct hash_node *n)
|
||||
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;
|
||||
int i;
|
||||
@@ -220,7 +257,6 @@ struct hash_node *hash_get_first(struct hash_table *t)
|
||||
|
||||
struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n)
|
||||
{
|
||||
unsigned int h = _hash(n->key) & (t->num_slots - 1);
|
||||
unsigned h = _hash(n->key, n->keylen) & (t->num_slots - 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
|
||||
@@ -10,7 +19,7 @@
|
||||
struct hash_table;
|
||||
struct hash_node;
|
||||
|
||||
typedef void (*iterate_fn)(void *data);
|
||||
typedef void (*iterate_fn) (void *data);
|
||||
|
||||
struct hash_table *hash_create(unsigned size_hint);
|
||||
void hash_destroy(struct hash_table *t);
|
||||
@@ -20,6 +29,11 @@ void *hash_lookup(struct hash_table *t, const char *key);
|
||||
int hash_insert(struct hash_table *t, const char *key, void *data);
|
||||
void hash_remove(struct hash_table *t, const char *key);
|
||||
|
||||
void *hash_lookup_binary(struct hash_table *t, const char *key, uint32_t len);
|
||||
int hash_insert_binary(struct hash_table *t, const char *key, uint32_t len,
|
||||
void *data);
|
||||
void hash_remove_binary(struct hash_table *t, const char *key, uint32_t len);
|
||||
|
||||
unsigned hash_get_num_entries(struct hash_table *t);
|
||||
void hash_iter(struct hash_table *t, iterate_fn f);
|
||||
|
||||
@@ -33,4 +47,3 @@ struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n);
|
||||
v = hash_get_next(h, v))
|
||||
|
||||
#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
|
||||
@@ -13,11 +22,15 @@ struct list {
|
||||
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;
|
||||
}
|
||||
|
||||
static inline void list_add(struct list *head, struct list *elem) {
|
||||
static inline void list_add(struct list *head, struct list *elem)
|
||||
{
|
||||
assert(head->n);
|
||||
|
||||
elem->n = head;
|
||||
@@ -27,7 +40,8 @@ static inline void list_add(struct list *head, struct list *elem) {
|
||||
head->p = elem;
|
||||
}
|
||||
|
||||
static inline void list_add_h(struct list *head, struct list *elem) {
|
||||
static inline void list_add_h(struct list *head, struct list *elem)
|
||||
{
|
||||
assert(head->n);
|
||||
|
||||
elem->n = head->n;
|
||||
@@ -37,36 +51,62 @@ static inline void list_add_h(struct list *head, struct list *elem) {
|
||||
head->n = elem;
|
||||
}
|
||||
|
||||
static inline void list_del(struct list *elem) {
|
||||
static inline void list_del(struct list *elem)
|
||||
{
|
||||
elem->n->p = elem->p;
|
||||
elem->p->n = elem->n;
|
||||
}
|
||||
|
||||
static inline int list_empty(struct list *head) {
|
||||
static inline int list_empty(struct list *head)
|
||||
{
|
||||
return head->n == head;
|
||||
}
|
||||
|
||||
#define list_iterate(v, head) \
|
||||
for (v = (head)->n; v != head; v = v->n)
|
||||
static inline int list_end(struct list *head, struct list *elem)
|
||||
{
|
||||
return elem->n == head;
|
||||
}
|
||||
|
||||
#define list_iterate_safe(v, t, head) \
|
||||
for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
|
||||
|
||||
static inline int list_size(struct list *head) {
|
||||
int s = 0;
|
||||
struct list *v;
|
||||
|
||||
list_iterate(v, head)
|
||||
s++;
|
||||
|
||||
return s;
|
||||
static inline struct list *list_next(struct list *head, struct list *elem)
|
||||
{
|
||||
return (list_end(head, elem) ? NULL : elem->n);
|
||||
}
|
||||
|
||||
#define list_item(v, t) \
|
||||
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list))
|
||||
|
||||
/* Given a known element in a known structure, locate the struct list */
|
||||
#define list_head(v, t, e) \
|
||||
(((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->list)
|
||||
#define list_struct_base(v, t, h) \
|
||||
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->h))
|
||||
|
||||
/* 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
|
||||
|
||||
@@ -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
|
||||
@@ -12,9 +21,12 @@
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
/* Define some portable printing types */
|
||||
#define PRIsize_t "Zu"
|
||||
|
||||
struct str_list {
|
||||
struct list list;
|
||||
char *str;
|
||||
const char *str;
|
||||
};
|
||||
|
||||
#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 "log.h"
|
||||
#include "pool.h"
|
||||
#include "hash.h"
|
||||
#include "list.h"
|
||||
#include "lvm-types.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 <sys/param.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 btree_iter *current;
|
||||
@@ -46,42 +46,168 @@ static struct {
|
||||
|
||||
} _cache;
|
||||
|
||||
|
||||
#define _alloc(x) pool_alloc(_cache.mem, (x))
|
||||
#define _free(x) pool_free(_cache.mem, (x))
|
||||
|
||||
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;
|
||||
|
||||
if (!(dev = _alloc(sizeof(*dev)))) {
|
||||
stack;
|
||||
log_error("struct device allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev->flags = 0;
|
||||
list_init(&dev->aliases);
|
||||
dev->dev = d;
|
||||
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 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)
|
||||
{
|
||||
struct str_list *sl = _alloc(sizeof(*sl));
|
||||
struct list *ah;
|
||||
const char *oldpath;
|
||||
int prefer_old = 1;
|
||||
|
||||
if (!sl) {
|
||||
stack;
|
||||
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))) {
|
||||
stack;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -94,14 +220,15 @@ static int _insert_dev(const char *path, dev_t d)
|
||||
struct device *dev;
|
||||
|
||||
/* 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 */
|
||||
if (!(dev = _create_dev(d))) {
|
||||
if (!(dev = _dev_create(d))) {
|
||||
stack;
|
||||
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.");
|
||||
_free(dev);
|
||||
return 0;
|
||||
@@ -123,7 +250,7 @@ static int _insert_dev(const char *path, dev_t d)
|
||||
|
||||
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);
|
||||
if (r)
|
||||
snprintf(r, len, "%s/%s", dir, name);
|
||||
@@ -194,7 +321,18 @@ static int _insert(const char *path, int rec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (S_ISDIR(info.st_mode)) { /* add a directory */
|
||||
if (S_ISDIR(info.st_mode)) { /* add a directory */
|
||||
/* 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)
|
||||
r = _insert_dir(path);
|
||||
|
||||
@@ -230,6 +368,21 @@ static void _full_scan(void)
|
||||
_cache.has_scanned = 1;
|
||||
}
|
||||
|
||||
int dev_cache_has_scanned(void)
|
||||
{
|
||||
return _cache.has_scanned;
|
||||
}
|
||||
|
||||
void dev_cache_scan(int do_scan)
|
||||
{
|
||||
if (!do_scan)
|
||||
_cache.has_scanned = 1;
|
||||
else {
|
||||
_cache.has_scanned = 0;
|
||||
_full_scan();
|
||||
}
|
||||
}
|
||||
|
||||
int dev_cache_init(void)
|
||||
{
|
||||
_cache.names = NULL;
|
||||
@@ -255,12 +408,12 @@ int dev_cache_init(void)
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
dev_cache_exit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _check_closed(struct device *dev)
|
||||
static void _check_closed(struct device *dev)
|
||||
{
|
||||
if (dev->fd >= 0)
|
||||
log_err("Device '%s' has been left open.", dev_name(dev));
|
||||
@@ -268,16 +421,27 @@ void _check_closed(struct device *dev)
|
||||
|
||||
static inline void _check_for_open_devices(void)
|
||||
{
|
||||
hash_iter(_cache.names, (iterate_fn)_check_closed);
|
||||
hash_iter(_cache.names, (iterate_fn) _check_closed);
|
||||
}
|
||||
|
||||
void dev_cache_exit(void)
|
||||
{
|
||||
_check_for_open_devices();
|
||||
|
||||
pool_destroy(_cache.mem);
|
||||
if (_cache.names)
|
||||
_check_for_open_devices();
|
||||
|
||||
if (_cache.mem) {
|
||||
pool_destroy(_cache.mem);
|
||||
_cache.mem = NULL;
|
||||
}
|
||||
|
||||
if (_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)
|
||||
@@ -296,8 +460,10 @@ int dev_cache_add_dir(const char *path)
|
||||
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;
|
||||
}
|
||||
|
||||
strcpy(dl->dir, path);
|
||||
list_add(&_cache.dirs, &dl->list);
|
||||
@@ -306,20 +472,31 @@ int dev_cache_add_dir(const char *path)
|
||||
|
||||
/* Check cached device name is still valid before returning it */
|
||||
/* 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 */
|
||||
const char *dev_name_confirmed(struct device *dev)
|
||||
const char *dev_name_confirmed(struct device *dev, int quiet)
|
||||
{
|
||||
struct stat buf;
|
||||
char *name;
|
||||
const char *name;
|
||||
int r;
|
||||
|
||||
while ((r = stat(name = list_item(dev->aliases.n,
|
||||
struct str_list)->str, &buf)) ||
|
||||
while ((r = stat(name = list_item(dev->aliases.n,
|
||||
struct str_list)->str, &buf)) ||
|
||||
(buf.st_rdev != dev->dev)) {
|
||||
if (r < 0)
|
||||
log_sys_error("stat", name);
|
||||
log_error("Path %s no longer valid for device(%d,%d)",
|
||||
name, (int) MAJOR(dev->dev), (int) MINOR(dev->dev));
|
||||
if (r < 0) {
|
||||
if (quiet)
|
||||
log_sys_debug("stat", name);
|
||||
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 */
|
||||
hash_remove(_cache.names, name);
|
||||
@@ -342,7 +519,6 @@ const char *dev_name_confirmed(struct device *dev)
|
||||
return dev_name(dev);
|
||||
}
|
||||
|
||||
|
||||
struct device *dev_cache_get(const char *name, struct dev_filter *f)
|
||||
{
|
||||
struct stat buf;
|
||||
@@ -366,8 +542,10 @@ struct dev_iter *dev_iter_create(struct dev_filter *f)
|
||||
{
|
||||
struct dev_iter *di = dbg_malloc(sizeof(*di));
|
||||
|
||||
if (!di)
|
||||
if (!di) {
|
||||
log_error("dev_iter allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_full_scan();
|
||||
di->current = btree_first(_cache.devices);
|
||||
@@ -399,4 +577,3 @@ struct device *dev_iter_get(struct dev_iter *iter)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
#define _LVM_DEV_CACHE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "lvm-types.h"
|
||||
#include "device.h"
|
||||
|
||||
@@ -15,22 +23,24 @@
|
||||
* predicate for devices.
|
||||
*/
|
||||
struct dev_filter {
|
||||
int (*passes_filter)(struct dev_filter *f, struct device *dev);
|
||||
void (*destroy)(struct dev_filter *f);
|
||||
int (*passes_filter) (struct dev_filter * f, struct device * dev);
|
||||
void (*destroy) (struct dev_filter * f);
|
||||
void *private;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* The global device cache.
|
||||
*/
|
||||
int dev_cache_init(void);
|
||||
void dev_cache_exit(void);
|
||||
|
||||
/* Trigger(1) or avoid(0) a scan */
|
||||
void dev_cache_scan(int do_scan);
|
||||
int dev_cache_has_scanned(void);
|
||||
|
||||
int dev_cache_add_dir(const char *path);
|
||||
struct device *dev_cache_get(const char *name, struct dev_filter *f);
|
||||
|
||||
|
||||
/*
|
||||
* Object for iterating through the cache.
|
||||
*/
|
||||
|
||||
@@ -1,24 +1,220 @@
|
||||
/*
|
||||
* 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 "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 <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/fs.h> // UGH!!! for BLKSSZGET
|
||||
|
||||
int dev_get_size(struct device *dev, uint64_t *size)
|
||||
#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
|
||||
|
||||
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(const struct device *dev, uint64_t *size)
|
||||
{
|
||||
int fd;
|
||||
long s;
|
||||
const char *name = dev_name(dev);
|
||||
|
||||
log_very_verbose("Getting size of %s", name);
|
||||
@@ -27,15 +223,14 @@ int dev_get_size(struct device *dev, uint64_t *size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: add 64 bit ioctl */
|
||||
if (ioctl(fd, BLKGETSIZE, &s) < 0) {
|
||||
log_sys_error("ioctl BLKGETSIZE", name);
|
||||
if (ioctl(fd, BLKGETSIZE64, size) < 0) {
|
||||
log_sys_error("ioctl BLKGETSIZE64", name);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*size >>= BLKSIZE_SHIFT; /* Convert to sectors */
|
||||
close(fd);
|
||||
*size = (uint64_t) s;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -62,47 +257,122 @@ int dev_get_sectsize(struct device *dev, uint32_t *size)
|
||||
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;
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dev->fd >= 0) {
|
||||
log_error("Device '%s' has already been opened", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((stat(name, &buf) < 0) || (buf.st_rdev != dev->dev)) {
|
||||
if (!(dev->flags & DEV_REGULAR) &&
|
||||
((stat(name, &buf) < 0) || (buf.st_rdev != dev->dev))) {
|
||||
log_error("%s: stat failed: Has device name changed?", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((dev->fd = open(name, flags)) < 0) {
|
||||
#ifdef O_DIRECT_SUPPORT
|
||||
if (direct)
|
||||
flags |= O_DIRECT;
|
||||
#endif
|
||||
|
||||
#ifdef O_NOATIME
|
||||
/* Don't update atime on device inodes */
|
||||
if (!(dev->flags & DEV_REGULAR))
|
||||
flags |= O_NOATIME;
|
||||
#endif
|
||||
|
||||
if ((dev->fd = open(name, flags, 0777)) < 0) {
|
||||
log_sys_error("open", name);
|
||||
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);
|
||||
dev_close(dev);
|
||||
dev->fd = -1;
|
||||
return 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;
|
||||
}
|
||||
|
||||
static void _flush(int fd)
|
||||
int dev_open_quiet(struct device *dev)
|
||||
{
|
||||
if (ioctl(fd, BLKFLSBUF, 0))
|
||||
log_error("couldn't flush device.");
|
||||
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) {
|
||||
log_error("Attempt to close device '%s' "
|
||||
@@ -110,134 +380,127 @@ int dev_close(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
_flush(dev->fd);
|
||||
#ifndef O_DIRECT_SUPPORT
|
||||
if (dev->flags & DEV_ACCESSED_W)
|
||||
dev_flush(dev);
|
||||
#endif
|
||||
|
||||
if (close(dev->fd))
|
||||
log_sys_error("close", dev_name(dev));
|
||||
|
||||
dev->fd = -1;
|
||||
/* FIXME lookup device in cache to get vgname and see if it's locked? */
|
||||
if (--dev->open_count < 1 && (immediate || !vgs_locked()))
|
||||
_close(dev);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: factor common code out.
|
||||
int dev_close(struct device *dev)
|
||||
{
|
||||
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 tot = 0;
|
||||
int r;
|
||||
|
||||
while (tot < count) {
|
||||
do
|
||||
n = read(fd, buf, count - tot);
|
||||
while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));
|
||||
if (!dev->open_count)
|
||||
return 0;
|
||||
|
||||
if (n <= 0)
|
||||
return tot ? tot : n;
|
||||
r = dev_write(dev, dev->end, len, buffer);
|
||||
dev->end += (uint64_t) len;
|
||||
|
||||
tot += n;
|
||||
buf += n;
|
||||
}
|
||||
|
||||
return tot;
|
||||
#ifndef O_DIRECT_SUPPORT
|
||||
dev_flush(dev);
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
int64_t dev_read(struct device *dev, uint64_t offset,
|
||||
int64_t len, void *buffer)
|
||||
int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer)
|
||||
{
|
||||
const char *name = dev_name(dev);
|
||||
int fd = dev->fd;
|
||||
struct device_area where;
|
||||
|
||||
if (fd < 0) {
|
||||
log_err("Attempt to read an unopened device (%s).", name);
|
||||
if (!dev->open_count)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lseek(fd, offset, SEEK_SET) < 0) {
|
||||
log_sys_error("lseek", name);
|
||||
return 0;
|
||||
}
|
||||
where.dev = dev;
|
||||
where.start = offset;
|
||||
where.size = len;
|
||||
|
||||
return _read(fd, buffer, len);
|
||||
dev->flags |= DEV_ACCESSED_W;
|
||||
|
||||
return _aligned_io(&where, buffer, 1);
|
||||
}
|
||||
|
||||
int _write(int fd, const void *buf, size_t count)
|
||||
int dev_zero(struct device *dev, uint64_t offset, size_t len)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
return _write(fd, buffer, len);
|
||||
}
|
||||
|
||||
int dev_zero(struct device *dev, uint64_t offset, int64_t len)
|
||||
{
|
||||
int64_t r, s;
|
||||
size_t s;
|
||||
char buffer[4096];
|
||||
const char *name = dev_name(dev);
|
||||
int fd = dev->fd;
|
||||
|
||||
if (fd < 0) {
|
||||
log_error("Attempt to zero part of an unopened device %s",
|
||||
name);
|
||||
if (!dev_open(dev)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lseek(fd, offset, SEEK_SET) < 0) {
|
||||
log_sys_error("lseek", name);
|
||||
return 0;
|
||||
}
|
||||
if ((offset % SECTOR_SIZE) || (len % SECTOR_SIZE))
|
||||
log_debug("Wiping %s at %" PRIu64 " length %" PRIsize_t,
|
||||
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));
|
||||
while (1) {
|
||||
s = len > sizeof(buffer) ? sizeof(buffer) : len;
|
||||
r = _write(fd, buffer, s);
|
||||
|
||||
if (r <= 0)
|
||||
if (!dev_write(dev, offset, s, buffer))
|
||||
break;
|
||||
|
||||
len -= r;
|
||||
if (!len) {
|
||||
r = 1;
|
||||
len -= s;
|
||||
if (!len)
|
||||
break;
|
||||
}
|
||||
|
||||
offset += s;
|
||||
}
|
||||
|
||||
dev->flags |= DEV_ACCESSED_W;
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
/* FIXME: Always display error */
|
||||
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
|
||||
* 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 file is part of LVM2.
|
||||
*
|
||||
* This LVM library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
* 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 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 <sys/types.h>
|
||||
#if 0
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/genhd.h>
|
||||
|
||||
#include "dbg_malloc.h"
|
||||
#include "log.h"
|
||||
@@ -34,13 +33,6 @@
|
||||
#include "metadata.h"
|
||||
#include "device.h"
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/genhd.h>
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
int _get_partition_type(struct dev_filter *filter, struct device *d);
|
||||
|
||||
#define MINOR_PART(dm, d) (MINOR((d)->dev) % dev_max_partitions(dm, (d)->dev))
|
||||
|
||||
@@ -1,25 +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
|
||||
#define _LVM_DEVICE_H
|
||||
|
||||
#include "lvm-types.h"
|
||||
#include "list.h"
|
||||
#include "uuid.h"
|
||||
#include <fcntl.h>
|
||||
|
||||
#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.
|
||||
* pointer comparisons are valid.
|
||||
*/
|
||||
struct device {
|
||||
struct list aliases; /* struct str_list from lvm-types.h */
|
||||
struct list aliases; /* struct str_list from lvm-types.h */
|
||||
dev_t dev;
|
||||
|
||||
/* private */
|
||||
int fd;
|
||||
int open_count;
|
||||
uint32_t flags;
|
||||
uint64_t end;
|
||||
struct list open_list;
|
||||
|
||||
char pvid[ID_LEN + 1];
|
||||
};
|
||||
|
||||
struct device_list {
|
||||
@@ -27,32 +46,58 @@ struct device_list {
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
struct device_area {
|
||||
struct device *dev;
|
||||
uint64_t start; /* Bytes */
|
||||
uint64_t size; /* Bytes */
|
||||
};
|
||||
|
||||
/*
|
||||
* All io should use these routines.
|
||||
*/
|
||||
int dev_get_size(struct device *dev, uint64_t *size);
|
||||
int dev_get_size(const struct device *dev, uint64_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_immediate(struct device *dev);
|
||||
void dev_close_all(void);
|
||||
|
||||
int64_t dev_read(struct device *dev,
|
||||
uint64_t offset, int64_t len, void *buffer);
|
||||
int64_t dev_write(struct device *dev,
|
||||
uint64_t offset, int64_t len, void *buffer);
|
||||
int dev_zero(struct device *dev, uint64_t offset, int64_t len);
|
||||
static inline int dev_fd(struct device *dev)
|
||||
{
|
||||
return dev->fd;
|
||||
}
|
||||
|
||||
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) {
|
||||
return list_item(dev->aliases.n, struct str_list)->str;
|
||||
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 :
|
||||
"unknown device";
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,65 +1,202 @@
|
||||
/*
|
||||
* 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
|
||||
* 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 file is part of LVM2.
|
||||
*
|
||||
* This LVM library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* 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
|
||||
* 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 "dbg_malloc.h"
|
||||
#include "log.h"
|
||||
#include "display.h"
|
||||
#include "activate.h"
|
||||
#include "uuid.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include "segtypes.h"
|
||||
|
||||
#define SIZE_BUF 128
|
||||
|
||||
char *display_size(uint64_t size, size_len_t sl)
|
||||
static struct {
|
||||
alloc_policy_t alloc;
|
||||
const char *str;
|
||||
} _policies[] = {
|
||||
{
|
||||
ALLOC_CONTIGUOUS, "contiguous"}, {
|
||||
ALLOC_NORMAL, "normal"}, {
|
||||
ALLOC_ANYWHERE, "anywhere"}, {
|
||||
ALLOC_INHERIT, "inherit"}
|
||||
};
|
||||
|
||||
static int _num_policies = sizeof(_policies) / sizeof(*_policies);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* Special case for old metadata */
|
||||
if(!strcmp("next free", str))
|
||||
return ALLOC_NORMAL;
|
||||
|
||||
log_error("Unrecognised allocation policy %s", str);
|
||||
return ALLOC_INVALID;
|
||||
}
|
||||
|
||||
/* Size supplied in sectors */
|
||||
const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
|
||||
{
|
||||
int s;
|
||||
ulong byte = 1024 * 1024 * 1024;
|
||||
int suffix = 1, precision;
|
||||
uint64_t byte = UINT64_C(0);
|
||||
uint64_t units = UINT64_C(1024);
|
||||
char *size_buf = NULL;
|
||||
char *size_str[][2] = {
|
||||
{"Terabyte", "TB"},
|
||||
{"Gigabyte", "GB"},
|
||||
{"Megabyte", "MB"},
|
||||
{"Kilobyte", "KB"},
|
||||
{"", ""}
|
||||
const char *size_str[][3] = {
|
||||
{" Terabyte", " TB", "T"},
|
||||
{" Gigabyte", " GB", "G"},
|
||||
{" Megabyte", " MB", "M"},
|
||||
{" Kilobyte", " KB", "K"},
|
||||
{"", "", ""},
|
||||
{" Byte ", " B ", "B"},
|
||||
{" Units ", " Un", "U"},
|
||||
{" Sectors ", " Se", "S"},
|
||||
{" ", " ", " "},
|
||||
};
|
||||
|
||||
if (!(size_buf = dbg_malloc(SIZE_BUF))) {
|
||||
if (!(size_buf = pool_alloc(cmd->mem, SIZE_BUF))) {
|
||||
log_error("no memory for size display buffer");
|
||||
return NULL;
|
||||
return "";
|
||||
}
|
||||
|
||||
if (size == 0LL)
|
||||
sprintf(size_buf, "0");
|
||||
else {
|
||||
suffix = cmd->current_settings.suffix;
|
||||
|
||||
for (s = 0; s < 8; s++)
|
||||
if (toupper((int) cmd->current_settings.unit_type) ==
|
||||
*size_str[s][2])
|
||||
break;
|
||||
|
||||
if (size == 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(512);
|
||||
} else {
|
||||
size /= 2;
|
||||
suffix = 1;
|
||||
if (cmd->current_settings.unit_type == 'H')
|
||||
units = UINT64_C(1000);
|
||||
else
|
||||
units = UINT64_C(1024);
|
||||
byte = units * units * units;
|
||||
s = 0;
|
||||
while (size_str[s] && size < byte)
|
||||
s++, byte /= 1024;
|
||||
snprintf(size_buf, SIZE_BUF - 1,
|
||||
"%.2f %s", (float) size / byte, size_str[s][sl]);
|
||||
s++, byte /= units;
|
||||
}
|
||||
|
||||
/* Caller to deallocate */
|
||||
/* FIXME Make precision configurable */
|
||||
switch(toupper((int) cmd->current_settings.unit_type)) {
|
||||
case 'B':
|
||||
case 'S':
|
||||
precision = 0;
|
||||
break;
|
||||
default:
|
||||
precision = 2;
|
||||
}
|
||||
|
||||
snprintf(size_buf, SIZE_BUF - 1, "%.*f%s", precision,
|
||||
(double) size / byte, suffix ? size_str[s][sl] : "");
|
||||
|
||||
return size_buf;
|
||||
}
|
||||
|
||||
@@ -75,26 +212,28 @@ void pvdisplay_colons(struct physical_volume *pv)
|
||||
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,
|
||||
/* FIXME pv->pv_number, Derive or remove? */
|
||||
pv->status, /* FIXME Support old or new format here? */
|
||||
pv->status & ALLOCATABLE_PV, /* FIXME remove? */
|
||||
pv->status & ALLOCATABLE_PV, /* FIXME remove? */
|
||||
/* FIXME pv->lv_cur, Remove? */
|
||||
pv->pe_size / 2,
|
||||
pv->pe_count,
|
||||
pv->pe_count - pv->pe_allocated,
|
||||
pv->pe_allocated, *uuid ? uuid : "none");
|
||||
pv->pe_count - pv->pe_alloc_count,
|
||||
pv->pe_alloc_count, *uuid ? uuid : "none");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void pvdisplay_full(struct physical_volume *pv)
|
||||
/* FIXME Include label fields */
|
||||
void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
void *handle)
|
||||
{
|
||||
char uuid[64];
|
||||
char *size, *size1; /*, *size2; */
|
||||
const char *size;
|
||||
|
||||
uint64_t pe_free;
|
||||
uint32_t pe_free;
|
||||
|
||||
if (!pv)
|
||||
return;
|
||||
@@ -109,64 +248,66 @@ void pvdisplay_full(struct physical_volume *pv)
|
||||
log_print("VG Name %s%s", pv->vg_name,
|
||||
pv->status & EXPORTED_VG ? " (exported)" : "");
|
||||
|
||||
size = display_size((uint64_t) pv->size / 2, SIZE_SHORT);
|
||||
size = display_size(cmd, (uint64_t) pv->size, SIZE_SHORT);
|
||||
if (pv->pe_size && pv->pe_count) {
|
||||
size1 = display_size((pv->size - pv->pe_count * pv->pe_size)
|
||||
/ 2, SIZE_SHORT);
|
||||
|
||||
/******** FIXME display LVM on-disk data size
|
||||
size2 = display_size(pv->size / 2, SIZE_SHORT);
|
||||
size2 = display_size(pv->size, SIZE_SHORT);
|
||||
********/
|
||||
|
||||
log_print("PV Size %s" " / not usable %s", /* [LVM: %s]", */
|
||||
size, size1); /* , size2); */
|
||||
size,
|
||||
display_size(cmd, (pv->size -
|
||||
pv->pe_count * pv->pe_size),
|
||||
SIZE_SHORT));
|
||||
|
||||
dbg_free(size1);
|
||||
/* dbg_free(size2); */
|
||||
} else
|
||||
log_print("PV Size %s", size);
|
||||
dbg_free(size);
|
||||
|
||||
/*********FIXME Anything use this?
|
||||
log_print("PV# %u", pv->pv_number);
|
||||
**********/
|
||||
/* PV number not part of LVM2 design
|
||||
log_print("PV# %u", pv->pv_number);
|
||||
*/
|
||||
|
||||
pe_free = pv->pe_count - pv->pe_allocated;
|
||||
pe_free = pv->pe_count - pv->pe_alloc_count;
|
||||
if (pv->pe_count && (pv->status & ALLOCATABLE_PV))
|
||||
log_print("Allocatable yes %s",
|
||||
(!pe_free && pv->pe_count) ? "(but full)" : "");
|
||||
else
|
||||
log_print("Allocatable NO");
|
||||
|
||||
/*********FIXME
|
||||
log_print("Cur LV %u", pv->lv_cur);
|
||||
*********/
|
||||
log_print("PE Size (KByte) %" PRIu64, pv->pe_size / 2);
|
||||
/* LV count is no longer available when displaying PV
|
||||
log_print("Cur LV %u", vg->lv_count);
|
||||
*/
|
||||
log_print("PE Size (KByte) %" PRIu32, pv->pe_size / 2);
|
||||
log_print("Total PE %u", pv->pe_count);
|
||||
log_print("Free PE %" PRIu64, pe_free);
|
||||
log_print("Allocated PE %u", pv->pe_allocated);
|
||||
|
||||
#ifdef LVM_FUTURE
|
||||
printf("Stale PE %u", pv->pe_stale);
|
||||
#endif
|
||||
|
||||
log_print("Free PE %" PRIu32, pe_free);
|
||||
log_print("Allocated PE %u", pv->pe_alloc_count);
|
||||
log_print("PV UUID %s", *uuid ? uuid : "none");
|
||||
log_print(" ");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv)
|
||||
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct physical_volume *pv, void *handle)
|
||||
{
|
||||
char uuid[64];
|
||||
|
||||
if (!pv)
|
||||
return 0;
|
||||
|
||||
if (!id_write_format(&pv->id, uuid, sizeof(uuid))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_print("PV Name %s ", dev_name(pv->dev));
|
||||
/* FIXME pv->pv_number); */
|
||||
log_print("PV UUID %s", *uuid ? uuid : "none");
|
||||
log_print("PV Status %sallocatable",
|
||||
(pv->status & ALLOCATABLE_PV) ? "" : "NOT ");
|
||||
log_print("Total PE / Free PE %u / %u",
|
||||
pv->pe_count, pv->pe_count - pv->pe_allocated);
|
||||
pv->pe_count, pv->pe_count - pv->pe_alloc_count);
|
||||
|
||||
log_print(" ");
|
||||
return 0;
|
||||
@@ -175,7 +316,7 @@ int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg, struct phy
|
||||
void lvdisplay_colons(struct logical_volume *lv)
|
||||
{
|
||||
int inkernel;
|
||||
struct dm_info info;
|
||||
struct lvinfo info;
|
||||
inkernel = lv_info(lv, &info) && info.exists;
|
||||
|
||||
log_print("%s%s/%s:%s:%d:%d:-1:%d:%" PRIu64 ":%d:-1:%d:%d:%d:%d",
|
||||
@@ -183,27 +324,24 @@ void lvdisplay_colons(struct logical_volume *lv)
|
||||
lv->vg->name,
|
||||
lv->name,
|
||||
lv->vg->name,
|
||||
(lv->status & (LVM_READ | LVM_WRITE)) >> 8,
|
||||
inkernel ? 1 : 0,
|
||||
(lv->status & (LVM_READ | LVM_WRITE)) >> 8, inkernel ? 1 : 0,
|
||||
/* FIXME lv->lv_number, */
|
||||
inkernel ? info.open_count : 0, lv->size, lv->le_count,
|
||||
/* FIXME Add num allocated to struct! lv->lv_allocated_le, */
|
||||
((lv->status & ALLOC_STRICT) +
|
||||
(lv->status & ALLOC_CONTIGUOUS) * 2), lv->read_ahead,
|
||||
inkernel ? info.major : -1,
|
||||
inkernel ? info.minor : -1
|
||||
);
|
||||
(lv->alloc == ALLOC_CONTIGUOUS ? 2 : 0), lv->read_ahead,
|
||||
inkernel ? info.major : -1, inkernel ? info.minor : -1);
|
||||
return;
|
||||
}
|
||||
|
||||
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
void *handle)
|
||||
{
|
||||
char *size;
|
||||
uint32_t alloc;
|
||||
struct dm_info info;
|
||||
int inkernel;
|
||||
struct lvinfo info;
|
||||
int inkernel, snap_active;
|
||||
char uuid[64];
|
||||
struct snapshot *snap;
|
||||
struct snapshot *snap = NULL;
|
||||
struct list *slh, *snaplist;
|
||||
float snap_percent; /* fused, fsize; */
|
||||
|
||||
if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) {
|
||||
stack;
|
||||
@@ -223,59 +361,37 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
log_print("LV Write Access %s",
|
||||
(lv->status & LVM_WRITE) ? "read/write" : "read only");
|
||||
|
||||
if ((snap = find_cow(lv)))
|
||||
log_print("Snapshot of %s", snap->origin->name);
|
||||
if (lv_is_origin(lv)) {
|
||||
log_print("LV snapshot status source of");
|
||||
|
||||
/******* FIXME Snapshot
|
||||
if (lv->status & (LVM_SNAPSHOT_ORG | LVM_SNAPSHOT)) {
|
||||
if (lvm_tab_vg_read_with_pv_and_lv(vg_name, &vg) < 0) {
|
||||
ret = -LVM_ELV_SHOW_VG_READ_WITH_PV_AND_LV;
|
||||
goto lv_show_end;
|
||||
}
|
||||
printf("LV snapshot status ");
|
||||
if (vg_check_active(vg_name) == TRUE) {
|
||||
vg_t *vg_core;
|
||||
if ((ret = vg_status_with_pv_and_lv(vg_name, &vg_core)) == 0) {
|
||||
lv_t *lv_ptr =
|
||||
vg_core->
|
||||
lv[lv_get_index_by_name(vg_core, lv->lv_name)];
|
||||
if (lv_ptr->lv_access & LV_SNAPSHOT) {
|
||||
if (lv_ptr->lv_status & LV_ACTIVE)
|
||||
printf("active ");
|
||||
else
|
||||
printf("INACTIVE ");
|
||||
snaplist = find_snapshots(lv);
|
||||
list_iterate(slh, snaplist) {
|
||||
snap = list_item(slh, struct snapshot_list)->snapshot;
|
||||
snap_active = lv_snapshot_percent(snap->cow,
|
||||
&snap_percent);
|
||||
if (!snap_active || snap_percent < 0 ||
|
||||
snap_percent >= 100) snap_active = 0;
|
||||
log_print(" %s%s/%s [%s]",
|
||||
lv->vg->cmd->dev_dir, lv->vg->name,
|
||||
snap->cow->name,
|
||||
(snap_active > 0) ? "active" : "INACTIVE");
|
||||
}
|
||||
if (lv_ptr->lv_access & LV_SNAPSHOT_ORG) {
|
||||
printf("source of\n");
|
||||
while (lv_ptr->lv_snapshot_next != NULL) {
|
||||
lv_ptr = lv_ptr->lv_snapshot_next;
|
||||
printf(" %s [%s]\n",
|
||||
lv_ptr->lv_name,
|
||||
(lv_ptr->
|
||||
lv_status & LV_ACTIVE) ? "active" :
|
||||
"INACTIVE");
|
||||
}
|
||||
vg_free(vg_core, TRUE);
|
||||
} else {
|
||||
printf("destination for %s\n",
|
||||
lv_ptr->lv_snapshot_org->lv_name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("INACTIVE ");
|
||||
if (lv->lv_access & LV_SNAPSHOT_ORG)
|
||||
printf("original\n");
|
||||
else
|
||||
printf("snapshot\n");
|
||||
snap = NULL;
|
||||
} else if ((snap = find_cow(lv))) {
|
||||
snap_active = lv_snapshot_percent(lv, &snap_percent);
|
||||
if (!snap_active || snap_percent < 0 || snap_percent >= 100)
|
||||
snap_active = 0;
|
||||
log_print("LV snapshot status %s destination for %s%s/%s",
|
||||
(snap_active > 0) ? "active" : "INACTIVE",
|
||||
lv->vg->cmd->dev_dir, lv->vg->name,
|
||||
snap->origin->name);
|
||||
}
|
||||
}
|
||||
***********/
|
||||
|
||||
if (inkernel && info.suspended)
|
||||
log_print("LV Status suspended");
|
||||
else
|
||||
log_print("LV Status %savailable",
|
||||
inkernel ? "" : "NOT ");
|
||||
inkernel ? "" : "NOT ");
|
||||
|
||||
/********* FIXME lv_number
|
||||
log_print("LV # %u", lv->lv_number + 1);
|
||||
@@ -284,103 +400,60 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
if (inkernel)
|
||||
log_print("# open %u", info.open_count);
|
||||
|
||||
/********
|
||||
#ifdef LVM_FUTURE
|
||||
printf("Mirror copies %u\n", lv->lv_mirror_copies);
|
||||
printf("Consistency recovery ");
|
||||
if (lv->lv_recovery | LV_BADBLOCK_ON)
|
||||
printf("bad blocks\n");
|
||||
else
|
||||
printf("none\n");
|
||||
printf("Schedule %u\n", lv->lv_schedule);
|
||||
#endif
|
||||
********/
|
||||
log_print("LV Size %s",
|
||||
display_size(cmd,
|
||||
snap ? snap->origin->size : lv->size,
|
||||
SIZE_SHORT));
|
||||
|
||||
size = display_size(lv->size / 2, SIZE_SHORT);
|
||||
log_print("LV Size %s", size);
|
||||
dbg_free(size);
|
||||
|
||||
log_print("Current LE %u", lv->le_count);
|
||||
log_print("Current LE %u",
|
||||
snap ? snap->origin->le_count : lv->le_count);
|
||||
|
||||
/********** FIXME allocation
|
||||
log_print("Allocated LE %u", lv->allocated_le);
|
||||
**********/
|
||||
|
||||
/********** FIXME Snapshot
|
||||
if (lv->lv_access & LV_SNAPSHOT) {
|
||||
printf("snapshot chunk size %s\n",
|
||||
(dummy = lvm_show_size(lv->lv_chunk_size / 2, SHORT)));
|
||||
dbg_free(dummy);
|
||||
dummy = NULL;
|
||||
if (lv->lv_remap_end > 0) {
|
||||
lv_remap_ptr = lv->lv_remap_ptr;
|
||||
if (lv_remap_ptr > lv->lv_remap_end)
|
||||
lv_remap_ptr = lv->lv_remap_end;
|
||||
dummy = lvm_show_size(lv_remap_ptr *
|
||||
lv->lv_chunk_size / 2, SHORT);
|
||||
dummy1 = lvm_show_size(lv->lv_remap_end *
|
||||
lv->lv_chunk_size / 2, SHORT);
|
||||
printf("Allocated to snapshot %.2f%% [%s/%s]\n",
|
||||
(float) lv_remap_ptr * 100 / lv->lv_remap_end,
|
||||
dummy, dummy1);
|
||||
dbg_free(dummy);
|
||||
dbg_free(dummy1);
|
||||
dummy =
|
||||
lvm_show_size((vg->
|
||||
lv[lv_get_index_by_number
|
||||
(vg,
|
||||
lv->lv_number)]->lv_size -
|
||||
lv->lv_remap_end * lv->lv_chunk_size) / 2,
|
||||
SHORT);
|
||||
printf("Allocated to COW-table %s\n", dummy);
|
||||
dbg_free(dummy);
|
||||
}
|
||||
}
|
||||
******************/
|
||||
|
||||
log_print("Segments %u", list_size(&lv->segments));
|
||||
|
||||
/********* FIXME Stripes & stripesize for each segment
|
||||
log_print("Stripe size (KByte) %u", lv->stripesize / 2);
|
||||
***********/
|
||||
|
||||
/**************
|
||||
#ifdef LVM_FUTURE
|
||||
printf("Bad block ");
|
||||
if (lv->lv_badblock == LV_BADBLOCK_ON)
|
||||
printf("on\n");
|
||||
else
|
||||
printf("off\n");
|
||||
#endif
|
||||
***************/
|
||||
if (snap) {
|
||||
if (snap_percent == -1)
|
||||
snap_percent = 100;
|
||||
|
||||
/* FIXME next free == ALLOC_SIMPLE */
|
||||
alloc = lv->status & (ALLOC_STRICT | ALLOC_CONTIGUOUS);
|
||||
log_print("Allocation %s%s%s%s",
|
||||
!(alloc & (ALLOC_STRICT | ALLOC_CONTIGUOUS)) ? "next free" :
|
||||
"", (alloc == ALLOC_STRICT) ? "strict" : "",
|
||||
(alloc == ALLOC_CONTIGUOUS) ? "contiguous" : "",
|
||||
(alloc ==
|
||||
(ALLOC_STRICT | ALLOC_CONTIGUOUS)) ? "strict/contiguous" :
|
||||
"");
|
||||
log_print("Snapshot chunk size %s",
|
||||
display_size(cmd, (uint64_t) snap->chunk_size,
|
||||
SIZE_SHORT));
|
||||
|
||||
/*
|
||||
size = display_size(lv->size, SIZE_SHORT);
|
||||
sscanf(size, "%f", &fsize);
|
||||
fused = fsize * snap_percent / 100;
|
||||
*/
|
||||
log_print("Allocated to snapshot %.2f%% ", /* [%.2f/%s]", */
|
||||
snap_percent); /*, fused, size); */
|
||||
/* dbg_free(size); */
|
||||
}
|
||||
|
||||
/********** FIXME Snapshot
|
||||
size = ???
|
||||
log_print("Allocated to COW-table %s", size);
|
||||
dbg_free(size);
|
||||
}
|
||||
******************/
|
||||
|
||||
log_print("Allocation %s", get_alloc_string(lv->alloc));
|
||||
log_print("Read ahead sectors %u", lv->read_ahead);
|
||||
|
||||
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);
|
||||
|
||||
/****************
|
||||
#ifdef LVM_FUTURE
|
||||
printf("IO Timeout (seconds) ");
|
||||
if (lv->lv_io_timeout == 0)
|
||||
printf("default\n\n");
|
||||
else
|
||||
printf("%lu\n\n", lv->lv_io_timeout);
|
||||
#endif
|
||||
*************/
|
||||
}
|
||||
|
||||
if (inkernel)
|
||||
log_print("Block device %d:%d", info.major,
|
||||
log_print("Block device %d:%d", info.major,
|
||||
info.minor);
|
||||
|
||||
log_print(" ");
|
||||
@@ -388,53 +461,52 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _display_stripe(struct stripe_segment *seg, int s, const char *pre)
|
||||
void display_stripe(const 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,
|
||||
seg->area[s].pv ? dev_name(seg->area[s].pv->dev) : "Missing");
|
||||
if (seg->area[s].u.pv.pv)
|
||||
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)
|
||||
log_print("%sphysical extents\t%d to %d", pre,
|
||||
seg->area[s].pe, seg->area[s].pe + len - 1);
|
||||
if (seg->area[s].u.lv.lv)
|
||||
log_print("%sLogical extents\t%d to %d", pre,
|
||||
seg->area[s].u.lv.le,
|
||||
seg->area[s].u.lv.le + seg->area_len - 1);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int lvdisplay_segments(struct logical_volume *lv)
|
||||
{
|
||||
int s;
|
||||
struct list *segh;
|
||||
struct stripe_segment *seg;
|
||||
struct lv_segment *seg;
|
||||
|
||||
log_print("--- Segments ---");
|
||||
|
||||
list_iterate (segh, &lv->segments) {
|
||||
seg = list_item(segh, struct stripe_segment);
|
||||
|
||||
log_print("logical extent %d to %d:",
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
log_print("Logical extent %u to %u:",
|
||||
seg->le, seg->le + seg->len - 1);
|
||||
|
||||
if (seg->stripes == 1)
|
||||
_display_stripe(seg, 0, " ");
|
||||
log_print(" Type\t\t%s", seg->segtype->ops->name(seg));
|
||||
|
||||
else {
|
||||
log_print(" stripes\t\t%d", seg->stripes);
|
||||
log_print(" stripe size\t\t%d", seg->stripe_size);
|
||||
|
||||
for (s = 0; s < seg->stripes; s++) {
|
||||
log_print(" stripe %d:", s);
|
||||
_display_stripe(seg, s, " ");
|
||||
}
|
||||
}
|
||||
log_print(" ");
|
||||
if (seg->segtype->ops->display)
|
||||
seg->segtype->ops->display(seg);
|
||||
}
|
||||
|
||||
log_print(" ");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vgdisplay_extents(struct volume_group *vg)
|
||||
{
|
||||
return;
|
||||
@@ -443,12 +515,23 @@ void vgdisplay_extents(struct volume_group *vg)
|
||||
void vgdisplay_full(struct volume_group *vg)
|
||||
{
|
||||
uint32_t access;
|
||||
char *s1;
|
||||
uint32_t active_pvs;
|
||||
char uuid[64];
|
||||
|
||||
if (vg->status & PARTIAL_VG)
|
||||
active_pvs = list_size(&vg->pvs);
|
||||
else
|
||||
active_pvs = vg->pv_count;
|
||||
|
||||
log_print("--- Volume group ---");
|
||||
log_print("VG Name %s", vg->name);
|
||||
log_print("System ID %s", vg->system_id);
|
||||
log_print("Format %s", vg->fid->fmt->name);
|
||||
if (vg->fid->fmt->features & FMT_MDAS) {
|
||||
log_print("Metadata Areas %d",
|
||||
list_size(&vg->fid->metadata_areas));
|
||||
log_print("Metadata Sequence No %d", vg->seqno);
|
||||
}
|
||||
access = vg->status & (LVM_READ | LVM_WRITE);
|
||||
log_print("VG Access %s%s%s%s",
|
||||
access == (LVM_READ | LVM_WRITE) ? "read/write" : "",
|
||||
@@ -458,9 +541,9 @@ void vgdisplay_full(struct volume_group *vg)
|
||||
log_print("VG Status %s%sresizable",
|
||||
vg->status & EXPORTED_VG ? "exported/" : "",
|
||||
vg->status & RESIZEABLE_VG ? "" : "NOT ");
|
||||
/******* FIXME vg number
|
||||
log_print ("VG # %u\n", vg->vg_number);
|
||||
********/
|
||||
/* vg number not part of LVM2 design
|
||||
log_print ("VG # %u\n", vg->vg_number);
|
||||
*/
|
||||
if (vg->status & CLUSTERED) {
|
||||
log_print("Clustered yes");
|
||||
log_print("Shared %s",
|
||||
@@ -468,41 +551,37 @@ void vgdisplay_full(struct volume_group *vg)
|
||||
}
|
||||
log_print("MAX LV %u", vg->max_lv);
|
||||
log_print("Cur LV %u", vg->lv_count);
|
||||
/****** FIXME Open LVs
|
||||
log_print ( "Open LV %u", vg->lv_open);
|
||||
*******/
|
||||
log_print("Open LV %u", lvs_in_vg_opened(vg));
|
||||
/****** FIXME Max LV Size
|
||||
log_print ( "MAX LV Size %s",
|
||||
( s1 = display_size ( LVM_LV_SIZE_MAX(vg) / 2, SIZE_SHORT)));
|
||||
( s1 = display_size ( LVM_LV_SIZE_MAX(vg), SIZE_SHORT)));
|
||||
free ( s1);
|
||||
*********/
|
||||
log_print("Max PV %u", vg->max_pv);
|
||||
log_print("Cur PV %u", vg->pv_count);
|
||||
/******* FIXME act PVs
|
||||
log_print ( "Act PV %u", vg->pv_act);
|
||||
*********/
|
||||
log_print("Act PV %u", active_pvs);
|
||||
|
||||
s1 = display_size((uint64_t) vg->extent_count * (vg->extent_size / 2), SIZE_SHORT);
|
||||
log_print("VG Size %s", s1);
|
||||
dbg_free(s1);
|
||||
log_print("VG Size %s",
|
||||
display_size(vg->cmd,
|
||||
(uint64_t) vg->extent_count * vg->extent_size,
|
||||
SIZE_SHORT));
|
||||
|
||||
s1 = display_size(vg->extent_size / 2, SIZE_SHORT);
|
||||
log_print("PE Size %s", s1);
|
||||
dbg_free(s1);
|
||||
log_print("PE Size %s",
|
||||
display_size(vg->cmd, (uint64_t) vg->extent_size,
|
||||
SIZE_SHORT));
|
||||
|
||||
log_print("Total PE %u", vg->extent_count);
|
||||
|
||||
s1 =
|
||||
display_size(((uint64_t)
|
||||
vg->extent_count - vg->free_count) *
|
||||
(vg->extent_size / 2), SIZE_SHORT);
|
||||
log_print("Alloc PE / Size %u / %s",
|
||||
vg->extent_count - vg->free_count, s1);
|
||||
dbg_free(s1);
|
||||
vg->extent_count - vg->free_count,
|
||||
display_size(vg->cmd,
|
||||
((uint64_t) vg->extent_count - vg->free_count) *
|
||||
vg->extent_size, SIZE_SHORT));
|
||||
|
||||
s1 = display_size((uint64_t) vg->free_count * (vg->extent_size / 2), SIZE_SHORT);
|
||||
log_print("Free PE / Size %u / %s", vg->free_count, s1);
|
||||
dbg_free(s1);
|
||||
log_print("Free PE / Size %u / %s", vg->free_count,
|
||||
display_size(vg->cmd,
|
||||
(uint64_t) vg->free_count * vg->extent_size,
|
||||
SIZE_SHORT));
|
||||
|
||||
if (!id_write_format(&vg->id, uuid, sizeof(uuid))) {
|
||||
stack;
|
||||
@@ -517,22 +596,88 @@ void vgdisplay_full(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;
|
||||
}
|
||||
|
||||
void vgdisplay_short(struct volume_group *vg)
|
||||
{
|
||||
char *s1, *s2, *s3;
|
||||
s1 = display_size(vg->extent_count * vg->extent_size / 2, SIZE_SHORT);
|
||||
s2 =
|
||||
display_size((vg->extent_count - vg->free_count) * vg->extent_size /
|
||||
2, SIZE_SHORT);
|
||||
s3 = display_size(vg->free_count * vg->extent_size / 2, SIZE_SHORT);
|
||||
log_print("\"%s\" %-9s [%-9s used / %s free]", vg->name,
|
||||
/********* FIXME if "open" print "/used" else print "/idle"??? ******/
|
||||
s1, s2, s3);
|
||||
dbg_free(s1);
|
||||
dbg_free(s2);
|
||||
dbg_free(s3);
|
||||
display_size(vg->cmd,
|
||||
(uint64_t) vg->extent_count * vg->extent_size,
|
||||
SIZE_SHORT),
|
||||
display_size(vg->cmd,
|
||||
((uint64_t) vg->extent_count -
|
||||
vg->free_count) * vg->extent_size,
|
||||
SIZE_SHORT),
|
||||
display_size(vg->cmd,
|
||||
(uint64_t) vg->free_count * vg->extent_size,
|
||||
SIZE_SHORT));
|
||||
return;
|
||||
}
|
||||
|
||||
void display_formats(struct cmd_context *cmd)
|
||||
{
|
||||
struct format_type *fmt;
|
||||
|
||||
list_iterate_items(fmt, &cmd->formats) {
|
||||
log_print("%s", fmt->name);
|
||||
}
|
||||
}
|
||||
|
||||
void display_segtypes(struct cmd_context *cmd)
|
||||
{
|
||||
struct segment_type *segtype;
|
||||
|
||||
list_iterate_items(segtype, &cmd->segtypes) {
|
||||
log_print("%s", segtype->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
* 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 file is part of LVM2.
|
||||
*
|
||||
* This LVM library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* 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
|
||||
* 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_DISPLAY_H
|
||||
@@ -25,23 +20,38 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {SIZE_LONG=0, SIZE_SHORT=1} size_len_t;
|
||||
typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1, SIZE_UNIT = 2 } size_len_t;
|
||||
|
||||
uint64_t units_to_bytes(const char *units, char *unit_type);
|
||||
|
||||
/* Specify size in KB */
|
||||
char *display_size(uint64_t size, size_len_t sl);
|
||||
const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl);
|
||||
char *display_uuid(char *uuidstr);
|
||||
void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre);
|
||||
|
||||
void pvdisplay_colons(struct physical_volume *pv);
|
||||
void pvdisplay_full(struct physical_volume *pv);
|
||||
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv);
|
||||
void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
void *handle);
|
||||
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct physical_volume *pv, void *handle);
|
||||
|
||||
void lvdisplay_colons(struct logical_volume *lv);
|
||||
int lvdisplay_segments(struct logical_volume *lv);
|
||||
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv);
|
||||
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
void *handle);
|
||||
|
||||
void vgdisplay_extents(struct volume_group *vg);
|
||||
void vgdisplay_full(struct volume_group *vg);
|
||||
void vgdisplay_colons(struct volume_group *vg);
|
||||
void vgdisplay_short(struct volume_group *vg);
|
||||
|
||||
void display_formats(struct cmd_context *cmd);
|
||||
void display_segtypes(struct cmd_context *cmd);
|
||||
|
||||
/*
|
||||
* Allocation policy display conversion routines.
|
||||
*/
|
||||
const char *get_alloc_string(alloc_policy_t alloc);
|
||||
alloc_policy_t get_alloc_from_string(const char *str);
|
||||
|
||||
#endif
|
||||
|
||||
103
lib/error/errseg.c
Normal file
103
lib/error/errseg.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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 "pool.h"
|
||||
#include "list.h"
|
||||
#include "toolcontext.h"
|
||||
#include "segtypes.h"
|
||||
#include "display.h"
|
||||
#include "text_export.h"
|
||||
#include "text_import.h"
|
||||
#include "config.h"
|
||||
#include "str_list.h"
|
||||
#include "targets.h"
|
||||
#include "lvm-string.h"
|
||||
#include "activate.h"
|
||||
|
||||
static const char *_name(const struct lv_segment *seg)
|
||||
{
|
||||
return seg->segtype->name;
|
||||
}
|
||||
|
||||
static int _merge_segments(struct lv_segment *seg1, struct lv_segment *seg2)
|
||||
{
|
||||
seg1->len += seg2->len;
|
||||
seg1->area_len += seg2->area_len;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
|
||||
struct config_tree *cft, void **target_state,
|
||||
struct lv_segment *seg, char *params,
|
||||
size_t paramsize, const char **target, int *pos,
|
||||
uint32_t *pvmove_mirror_count)
|
||||
{
|
||||
/* error */
|
||||
|
||||
*target = "error";
|
||||
*params = '\0';
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _target_present(void)
|
||||
{
|
||||
static int checked = 0;
|
||||
static int present = 0;
|
||||
|
||||
if (!checked)
|
||||
present = target_present("error");
|
||||
|
||||
checked = 1;
|
||||
return present;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void _destroy(const struct segment_type *segtype)
|
||||
{
|
||||
dbg_free((void *) segtype);
|
||||
}
|
||||
|
||||
static struct segtype_handler _error_ops = {
|
||||
name:_name,
|
||||
merge_segments:_merge_segments,
|
||||
#ifdef DEVMAPPER_SUPPORT
|
||||
compose_target_line:_compose_target_line,
|
||||
target_present:_target_present,
|
||||
#endif
|
||||
destroy:_destroy,
|
||||
};
|
||||
|
||||
struct segment_type *init_error_segtype(struct cmd_context *cmd)
|
||||
{
|
||||
struct segment_type *segtype = dbg_malloc(sizeof(*segtype));
|
||||
|
||||
if (!segtype) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
segtype->cmd = cmd;
|
||||
segtype->ops = &_error_ops;
|
||||
segtype->name = "error";
|
||||
segtype->private = NULL;
|
||||
segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
return segtype;
|
||||
}
|
||||
@@ -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 "dbg_malloc.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
@@ -20,6 +28,8 @@ static int _and_p(struct dev_filter *f, struct device *dev)
|
||||
filters++;
|
||||
}
|
||||
|
||||
log_debug("Using %s", dev_name(dev));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -36,36 +46,32 @@ static void _destroy(struct dev_filter *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 *cf;
|
||||
va_list ap;
|
||||
int i;
|
||||
struct dev_filter **filters_copy, *cft;
|
||||
|
||||
if (!filters) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(cf = dbg_malloc(sizeof(*cf)))) {
|
||||
stack;
|
||||
dbg_free(filters);
|
||||
if (!(filters_copy = dbg_malloc(sizeof(*filters) * (n + 1)))) {
|
||||
log_error("composite filters allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
va_start(ap, n);
|
||||
for (i = 0; i < n; i++) {
|
||||
struct dev_filter *f = va_arg(ap, struct dev_filter *);
|
||||
filters[i] = f;
|
||||
memcpy(filters_copy, filters, sizeof(*filters) * n);
|
||||
filters_copy[n] = NULL;
|
||||
|
||||
if (!(cft = dbg_malloc(sizeof(*cft)))) {
|
||||
log_error("compsoite filters allocation failed");
|
||||
dbg_free(filters_copy);
|
||||
return NULL;
|
||||
}
|
||||
filters[i] = NULL;
|
||||
va_end(ap);
|
||||
|
||||
cf->passes_filter = _and_p;
|
||||
cf->destroy = _destroy;
|
||||
cf->private = filters;
|
||||
cft->passes_filter = _and_p;
|
||||
cft->destroy = _destroy;
|
||||
cft->private = filters_copy;
|
||||
|
||||
return cf;
|
||||
return cft;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -9,6 +18,6 @@
|
||||
|
||||
#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
|
||||
|
||||
98
lib/filters/filter-md.c
Normal file
98
lib/filters/filter-md.c
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2004 Luca Berra
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "filter-md.h"
|
||||
#include "metadata.h"
|
||||
|
||||
#ifdef linux
|
||||
|
||||
/* Lifted from <linux/raid/md_p.h> because of difficulty including it */
|
||||
|
||||
#define MD_SB_MAGIC 0xa92b4efc
|
||||
#define MD_RESERVED_BYTES (64 * 1024)
|
||||
#define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512)
|
||||
#define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) \
|
||||
- MD_RESERVED_SECTORS)
|
||||
|
||||
static int _ignore_md(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
uint64_t size, sector;
|
||||
uint32_t md_magic;
|
||||
|
||||
if (!dev_get_size(dev, &size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (size < MD_RESERVED_SECTORS * 2)
|
||||
/*
|
||||
* We could ignore it since it is obviously too
|
||||
* small, but that's not our job.
|
||||
*/
|
||||
return 1;
|
||||
|
||||
if (!dev_open(dev)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sector = MD_NEW_SIZE_SECTORS(size);
|
||||
|
||||
/* Check if it is an md component device. */
|
||||
if (dev_read(dev, sector << SECTOR_SHIFT, sizeof(uint32_t), &md_magic)) {
|
||||
if (md_magic == MD_SB_MAGIC) {
|
||||
log_debug("%s: Skipping md component device",
|
||||
dev_name(dev));
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _destroy(struct dev_filter *f)
|
||||
{
|
||||
dbg_free(f);
|
||||
}
|
||||
|
||||
struct dev_filter *md_filter_create(void)
|
||||
{
|
||||
struct dev_filter *f;
|
||||
|
||||
if (!(f = dbg_malloc(sizeof(*f)))) {
|
||||
log_error("md filter allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f->passes_filter = _ignore_md;
|
||||
f->destroy = _destroy;
|
||||
f->private = NULL;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct dev_filter *md_filter_create(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
23
lib/filters/filter-md.h
Normal file
23
lib/filters/filter-md.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2004 Luca Berra
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_FILTER_MD_H
|
||||
#define _LVM_FILTER_MD_H
|
||||
|
||||
#include "dev-cache.h"
|
||||
|
||||
struct dev_filter *md_filter_create(void);
|
||||
|
||||
#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 "dev-cache.h"
|
||||
#include "hash.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "log.h"
|
||||
#include "filter-persistent.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
@@ -34,8 +41,12 @@ static int _init_hash(struct pfilter *pf)
|
||||
if (pf->devices)
|
||||
hash_destroy(pf->devices);
|
||||
|
||||
pf->devices = hash_create(128);
|
||||
return pf->devices ? 1 : 0;
|
||||
if (!(pf->devices = hash_create(128))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int persistent_filter_wipe(struct dev_filter *f)
|
||||
@@ -43,18 +54,21 @@ int persistent_filter_wipe(struct dev_filter *f)
|
||||
struct pfilter *pf = (struct pfilter *) f->private;
|
||||
|
||||
hash_wipe(pf->devices);
|
||||
/* Trigger complete device scan */
|
||||
dev_cache_scan(1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_array(struct pfilter *pf, struct config_file *cf,
|
||||
static int _read_array(struct pfilter *pf, struct config_tree *cft,
|
||||
const char *path, void *data)
|
||||
{
|
||||
struct config_node *cn;
|
||||
const struct config_node *cn;
|
||||
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'",
|
||||
path, pf->file);
|
||||
path, pf->file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -65,13 +79,15 @@ static int _read_array(struct pfilter *pf, struct config_file *cf,
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != CFG_STRING) {
|
||||
log_verbose("Devices array contains a value "
|
||||
"which is not a string ... ignoring");
|
||||
"which is not a string ... ignoring");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hash_insert(pf->devices, cv->v.str, data))
|
||||
log_verbose("Couldn't add '%s' to filter ... ignoring",
|
||||
cv->v.str);
|
||||
cv->v.str);
|
||||
/* Populate dev_cache ourselves */
|
||||
dev_cache_get(cv->v.str, NULL);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -81,28 +97,35 @@ int persistent_filter_load(struct dev_filter *f)
|
||||
struct pfilter *pf = (struct pfilter *) f->private;
|
||||
|
||||
int r = 0;
|
||||
struct config_file *cf;
|
||||
struct config_tree *cft;
|
||||
|
||||
if (!(cf = create_config_file())) {
|
||||
if (!(cft = create_config_tree(pf->file))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!read_config(cf, pf->file)) {
|
||||
if (!read_config_file(cft)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
_read_array(pf, cf, "persistent_filter_cache/valid_devices",
|
||||
_read_array(pf, cft, "persistent_filter_cache/valid_devices",
|
||||
PF_GOOD_DEVICE);
|
||||
_read_array(pf, cf, "persistent_filter_cache/invalid_devices",
|
||||
PF_BAD_DEVICE);
|
||||
/* We don't gain anything by holding invalid devices */
|
||||
/* _read_array(pf, 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;
|
||||
}
|
||||
|
||||
out:
|
||||
destroy_config_file(cf);
|
||||
log_very_verbose("Loaded persistent filter cache from %s", pf->file);
|
||||
|
||||
out:
|
||||
destroy_config_tree(cft);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -147,11 +170,18 @@ int persistent_filter_dump(struct dev_filter *f)
|
||||
"- not writing to %s", pf->file);
|
||||
return 0;
|
||||
}
|
||||
if (!dev_cache_has_scanned()) {
|
||||
log_very_verbose("Device cache incomplete - not writing "
|
||||
"to %s", pf->file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_very_verbose("Dumping persistent device cache to %s", pf->file);
|
||||
|
||||
fp = fopen(pf->file, "w");
|
||||
if (!fp) {
|
||||
log_sys_error("fopen", pf->file);
|
||||
if (errno != EROFS)
|
||||
log_sys_error("fopen", pf->file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -159,7 +189,8 @@ int persistent_filter_dump(struct dev_filter *f)
|
||||
fprintf(fp, "persistent_filter_cache {\n");
|
||||
|
||||
_write_array(pf, fp, "valid_devices", PF_GOOD_DEVICE);
|
||||
_write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE);
|
||||
/* We don't gain anything by remembering invalid devices */
|
||||
/* _write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE); */
|
||||
|
||||
fprintf(fp, "}\n");
|
||||
fclose(fp);
|
||||
@@ -175,7 +206,7 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
|
||||
|
||||
if (!l) {
|
||||
l = pf->real->passes_filter(pf->real, dev) ?
|
||||
PF_GOOD_DEVICE : PF_BAD_DEVICE;
|
||||
PF_GOOD_DEVICE : PF_BAD_DEVICE;
|
||||
|
||||
list_iterate(ah, &dev->aliases) {
|
||||
sl = list_item(ah, struct str_list);
|
||||
@@ -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)
|
||||
@@ -232,7 +267,7 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
|
||||
|
||||
return f;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
dbg_free(pf->file);
|
||||
if (pf->devices)
|
||||
hash_destroy(pf->devices);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 "filter-regex.h"
|
||||
#include "matcher.h"
|
||||
#include "device.h"
|
||||
#include "bitset.h"
|
||||
#include "log.h"
|
||||
#include "list.h"
|
||||
|
||||
struct rfilter {
|
||||
@@ -19,7 +28,7 @@ struct rfilter {
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
@@ -28,11 +37,11 @@ static int _extract_pattern(struct pool *mem, const char *pat,
|
||||
*/
|
||||
switch (*pat) {
|
||||
case 'a':
|
||||
bit_set(accept, index);
|
||||
bit_set(accept, ix);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
bit_clear(accept, index);
|
||||
bit_clear(accept, ix);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -42,7 +51,7 @@ static int _extract_pattern(struct pool *mem, const char *pat,
|
||||
pat++;
|
||||
|
||||
/*
|
||||
* get the seperator
|
||||
* get the separator
|
||||
*/
|
||||
switch (*pat) {
|
||||
case '(':
|
||||
@@ -75,12 +84,12 @@ static int _extract_pattern(struct pool *mem, const char *pat,
|
||||
*/
|
||||
ptr = r + strlen(r) - 1;
|
||||
if (*ptr != sep) {
|
||||
log_info("invalid seperator at end of regex");
|
||||
log_info("invalid separator at end of regex");
|
||||
return 0;
|
||||
}
|
||||
*ptr = '\0';
|
||||
|
||||
regex[index] = r;
|
||||
regex[ix] = r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -89,7 +98,8 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
||||
struct pool *scratch;
|
||||
struct config_value *v;
|
||||
char **regex;
|
||||
int count = 0, i, r = 0;
|
||||
unsigned count = 0;
|
||||
int i, r = 0;
|
||||
|
||||
if (!(scratch = pool_create(1024))) {
|
||||
stack;
|
||||
@@ -128,8 +138,7 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
||||
* the matcher gives.
|
||||
*/
|
||||
for (v = val, i = count - 1; v; v = v->next, i--)
|
||||
if (!_extract_pattern(scratch, v->v.str,
|
||||
regex, rf->accept, i)) {
|
||||
if (!_extract_pattern(scratch, v->v.str, regex, rf->accept, i)) {
|
||||
log_info("invalid filter pattern");
|
||||
goto out;
|
||||
}
|
||||
@@ -137,12 +146,12 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
||||
/*
|
||||
* build the matcher.
|
||||
*/
|
||||
if (!(rf->engine = matcher_create(rf->mem,
|
||||
(const char **) regex, count)))
|
||||
if (!(rf->engine = matcher_create(rf->mem, (const char **) regex,
|
||||
count)))
|
||||
stack;
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
out:
|
||||
pool_destroy(scratch);
|
||||
return r;
|
||||
}
|
||||
@@ -162,6 +171,8 @@ static int _accept_p(struct dev_filter *f, struct device *dev)
|
||||
if (bit(rf->accept, m)) {
|
||||
|
||||
if (!first) {
|
||||
log_debug("%s: New preferred name",
|
||||
sl->str);
|
||||
list_del(&sl->list);
|
||||
list_add_h(&dev->aliases, &sl->list);
|
||||
}
|
||||
@@ -221,8 +232,7 @@ struct dev_filter *regex_filter_create(struct config_value *patterns)
|
||||
f->private = rf;
|
||||
return f;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
pool_destroy(mem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
300
lib/filters/filter-sysfs.c
Normal file
300
lib/filters/filter-sysfs.c
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* 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;
|
||||
unsigned char dtype;
|
||||
struct stat info;
|
||||
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;
|
||||
}
|
||||
|
||||
dtype = d->d_type;
|
||||
|
||||
if (dtype == DT_UNKNOWN) {
|
||||
if (stat(path, &info) >= 0) {
|
||||
if (S_ISDIR(info.st_mode))
|
||||
dtype = DT_DIR;
|
||||
else if (S_ISREG(info.st_mode))
|
||||
dtype = DT_REG;
|
||||
}
|
||||
}
|
||||
|
||||
if (dtype == DT_DIR) {
|
||||
if (!_read_devs(ds, path)) {
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((dtype == 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
|
||||
* 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.
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* lvm is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* 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 GNU CC; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* 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 "log.h"
|
||||
#include "lib.h"
|
||||
#include "dev-cache.h"
|
||||
#include "filter.h"
|
||||
#include "lvm-string.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define NUMBER_OF_MAJORS 256
|
||||
#define NUMBER_OF_MAJORS 4096
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int max_partitions;
|
||||
const char *name;
|
||||
const int max_partitions;
|
||||
} device_info_t;
|
||||
|
||||
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 */
|
||||
{"sd", 16}, /* SCSI disk */
|
||||
{"md", 16}, /* Multiple Disk driver (SoftRAID) */
|
||||
@@ -55,81 +52,67 @@ static device_info_t device_info[] = {
|
||||
{"cciss", 16}, /* Compaq CCISS array */
|
||||
{"ubd", 16}, /* User-mode virtual block device */
|
||||
{"ataraid", 16}, /* ATA Raid */
|
||||
{"drbd", 16}, /* Distributed Replicated Block Device */
|
||||
{"power2", 16}, /* EMC Powerpath */
|
||||
{"i2o_block", 16}, /* i2o Block Disk */
|
||||
{"iseries/vd", 8}, /* iSeries disks */
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
static int *scan_proc_dev(const char *proc);
|
||||
|
||||
static int passes_lvm_type_device_filter(struct dev_filter *f,
|
||||
struct device *dev)
|
||||
static int _passes_lvm_type_device_filter(struct dev_filter *f,
|
||||
struct device *dev)
|
||||
{
|
||||
int fd;
|
||||
const char *name = dev_name(dev);
|
||||
|
||||
/* Is this a recognised device type? */
|
||||
if (!(((int *) f->private)[MAJOR(dev->dev)]))
|
||||
return 0;
|
||||
|
||||
/* Check it's accessible */
|
||||
if ((fd = open(name, O_RDONLY)) < 0) {
|
||||
log_debug("Unable to open %s: %s", name, strerror(errno));
|
||||
if (!(((int *) f->private)[MAJOR(dev->dev)])) {
|
||||
log_debug("%s: Skipping: Unrecognised LVM device type %"
|
||||
PRIu64, name, (uint64_t) MAJOR(dev->dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
/* Check it's accessible */
|
||||
if ((fd = open(name, O_RDONLY)) < 0) {
|
||||
log_debug("%s: Skipping: open failed: %s", name,
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dev_filter *lvm_type_filter_create(const char *proc)
|
||||
{
|
||||
struct dev_filter *f;
|
||||
|
||||
if (!(f = dbg_malloc(sizeof (struct dev_filter)))) {
|
||||
log_error("LVM type filter allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f->passes_filter = passes_lvm_type_device_filter;
|
||||
f->destroy = lvm_type_filter_destroy;
|
||||
|
||||
if (!(f->private = scan_proc_dev(proc)))
|
||||
return NULL;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
int md_major(void)
|
||||
{
|
||||
return _md_major;
|
||||
}
|
||||
|
||||
void lvm_type_filter_destroy(struct dev_filter *f)
|
||||
{
|
||||
dbg_free(f->private);
|
||||
dbg_free(f);
|
||||
return;
|
||||
}
|
||||
|
||||
static int *scan_proc_dev(const char *proc)
|
||||
static int *_scan_proc_dev(const char *proc, const struct config_node *cn)
|
||||
{
|
||||
char line[80];
|
||||
char proc_devices[PATH_MAX];
|
||||
FILE *pd = NULL;
|
||||
int ret = 0;
|
||||
int i, j = 0;
|
||||
int line_maj = 0;
|
||||
int blocksection = 0;
|
||||
int dev_len = 0;
|
||||
|
||||
size_t dev_len = 0;
|
||||
struct config_value *cv;
|
||||
int *max_partitions_by_major;
|
||||
char *name;
|
||||
|
||||
if (!(max_partitions_by_major = dbg_malloc(sizeof (int) * NUMBER_OF_MAJORS))) {
|
||||
/* FIXME Make this sparse */
|
||||
if (!(max_partitions_by_major =
|
||||
dbg_malloc(sizeof(int) * NUMBER_OF_MAJORS))) {
|
||||
log_error("Filter failed to allocate max_partitions_by_major");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(proc_devices, sizeof(proc_devices),
|
||||
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),
|
||||
"%s/devices", proc) < 0) {
|
||||
log_error("Failed to create /proc/devices string");
|
||||
return NULL;
|
||||
@@ -140,7 +123,7 @@ static int *scan_proc_dev(const char *proc)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(max_partitions_by_major, 0, sizeof (int) * NUMBER_OF_MAJORS);
|
||||
memset(max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS);
|
||||
while (fgets(line, 80, pd) != NULL) {
|
||||
i = 0;
|
||||
while (line[i] == ' ' && line[i] != '\0')
|
||||
@@ -168,16 +151,48 @@ static int *scan_proc_dev(const char *proc)
|
||||
_md_major = line_maj;
|
||||
|
||||
/* Go through the valid device names and if there is a
|
||||
match store max number of partitions */
|
||||
match store max number of partitions */
|
||||
for (j = 0; device_info[j].name != NULL; j++) {
|
||||
|
||||
dev_len = strlen(device_info[j].name);
|
||||
if (dev_len <= strlen(line + i)
|
||||
&& !strncmp(device_info[j].name, line + i, dev_len)
|
||||
&& (line_maj < NUMBER_OF_MAJORS)) {
|
||||
if (dev_len <= strlen(line + i) &&
|
||||
!strncmp(device_info[j].name, line + i, dev_len) &&
|
||||
(line_maj < NUMBER_OF_MAJORS)) {
|
||||
max_partitions_by_major[line_maj] =
|
||||
device_info[j].max_partitions;
|
||||
ret++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (max_partitions_by_major[line_maj] || !cn)
|
||||
continue;
|
||||
|
||||
/* Check devices/types for local variations */
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != CFG_STRING) {
|
||||
log_error("Expecting string in devices/types "
|
||||
"in config file");
|
||||
return NULL;
|
||||
}
|
||||
dev_len = strlen(cv->v.str);
|
||||
name = cv->v.str;
|
||||
cv = cv->next;
|
||||
if (!cv || cv->type != CFG_INT) {
|
||||
log_error("Max partition count missing for %s "
|
||||
"in devices/types in config file",
|
||||
name);
|
||||
return NULL;
|
||||
}
|
||||
if (!cv->v.i) {
|
||||
log_error("Zero partition count invalid for "
|
||||
"%s in devices/types in config file",
|
||||
name);
|
||||
return NULL;
|
||||
}
|
||||
if (dev_len <= strlen(line + i) &&
|
||||
!strncmp(name, line + i, dev_len) &&
|
||||
(line_maj < NUMBER_OF_MAJORS)) {
|
||||
max_partitions_by_major[line_maj] = cv->v.i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -185,3 +200,31 @@ static int *scan_proc_dev(const char *proc)
|
||||
fclose(pd);
|
||||
return max_partitions_by_major;
|
||||
}
|
||||
|
||||
struct dev_filter *lvm_type_filter_create(const char *proc,
|
||||
const 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,40 @@
|
||||
/*
|
||||
* 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
|
||||
* 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.
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* lvm is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* 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 GNU CC; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* 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_H
|
||||
#define _LVM_FILTER_H
|
||||
|
||||
struct dev_filter *lvm_type_filter_create(const char *);
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef linux
|
||||
# define MAJOR(dev) ((dev & 0xfff00) >> 8)
|
||||
# define MINOR(dev) ((dev & 0xff) | ((dev >> 12) & 0xfff00))
|
||||
# define MKDEV(ma,mi) ((mi & 0xff) | (ma << 8) | ((mi & ~0xff) << 12))
|
||||
#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,
|
||||
const struct config_node *cn);
|
||||
|
||||
void lvm_type_filter_destroy(struct dev_filter *f);
|
||||
|
||||
int md_major(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
1
lib/format1/.exported_symbols
Normal file
1
lib/format1/.exported_symbols
Normal file
@@ -0,0 +1 @@
|
||||
init_format
|
||||
36
lib/format1/Makefile.in
Normal file
36
lib/format1/Makefile.in
Normal file
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# 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 $(top_srcdir)/make.tmpl
|
||||
|
||||
install: liblvm2format1.so
|
||||
$(INSTALL) -D $(OWNER) $(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 "dbg_malloc.h"
|
||||
#include "pool.h"
|
||||
#include "xlate.h"
|
||||
#include "log.h"
|
||||
#include "vgcache.h"
|
||||
#include "filter.h"
|
||||
#include "lvmcache.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/kdev_t.h>
|
||||
|
||||
#define fail do {stack; return 0;} while(0)
|
||||
#define xx16(v) disk->v = xlate16(disk->v)
|
||||
@@ -96,7 +101,7 @@ static void _xlate_vgd(struct vg_disk *disk)
|
||||
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;
|
||||
|
||||
@@ -112,16 +117,17 @@ static void _xlate_extents(struct pe_disk *extents, int count)
|
||||
static int _munge_formats(struct pv_disk *pvd)
|
||||
{
|
||||
uint32_t pe_start;
|
||||
int b, e;
|
||||
|
||||
switch (pvd->version) {
|
||||
case 1:
|
||||
pvd->pe_start = ((pvd->pe_on_disk.base +
|
||||
pvd->pe_on_disk.size) / SECTOR_SIZE);
|
||||
pvd->pe_on_disk.size) >> SECTOR_SHIFT);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
pvd->version = 1;
|
||||
pe_start = pvd->pe_start * SECTOR_SIZE;
|
||||
pe_start = pvd->pe_start << SECTOR_SHIFT;
|
||||
pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base;
|
||||
break;
|
||||
|
||||
@@ -129,37 +135,88 @@ static int _munge_formats(struct pv_disk *pvd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* UUID too long? */
|
||||
if (pvd->pv_uuid[ID_LEN]) {
|
||||
/* Retain ID_LEN chars from end */
|
||||
for (e = ID_LEN; e < sizeof(pvd->pv_uuid); e++) {
|
||||
if (!pvd->pv_uuid[e]) {
|
||||
e--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (b = 0; b < ID_LEN; b++) {
|
||||
pvd->pv_uuid[b] = pvd->pv_uuid[++e - ID_LEN];
|
||||
/* FIXME Remove all invalid chars */
|
||||
if (pvd->pv_uuid[b] == '/')
|
||||
pvd->pv_uuid[b] = '#';
|
||||
}
|
||||
memset(&pvd->pv_uuid[ID_LEN], 0, sizeof(pvd->pv_uuid) - ID_LEN);
|
||||
}
|
||||
|
||||
/* If UUID is missing, create one */
|
||||
if (pvd->pv_uuid[0] == '\0')
|
||||
uuid_from_num(pvd->pv_uuid, pvd->pv_number);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int read_pvd(struct device *dev, struct pv_disk *pvd)
|
||||
/*
|
||||
* If exported, remove "PV_EXP" from end of VG name
|
||||
*/
|
||||
static void _munge_exported_vg(struct pv_disk *pvd)
|
||||
{
|
||||
if (dev_read(dev, 0, sizeof(*pvd), pvd) != sizeof(*pvd)) {
|
||||
log_very_verbose("Failed to read PV data from %s",
|
||||
dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
int l;
|
||||
size_t s;
|
||||
|
||||
/* Return if PV not in a VG */
|
||||
if ((!*pvd->vg_name))
|
||||
return;
|
||||
/* FIXME also check vgd->status & VG_EXPORTED? */
|
||||
|
||||
l = strlen(pvd->vg_name);
|
||||
s = sizeof(EXPORTED_TAG);
|
||||
if (!strncmp(pvd->vg_name + l - s + 1, EXPORTED_TAG, s)) {
|
||||
pvd->vg_name[l - s + 1] = '\0';
|
||||
pvd->pv_status |= VG_EXPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
int munge_pvd(struct device *dev, struct pv_disk *pvd)
|
||||
{
|
||||
_xlate_pvd(pvd);
|
||||
|
||||
if (pvd->id[0] != 'H' || pvd->id[1] != 'M') {
|
||||
log_very_verbose("%s does not have a valid PV identifier",
|
||||
log_very_verbose("%s does not have a valid LVM1 PV identifier",
|
||||
dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_munge_formats(pvd)) {
|
||||
log_very_verbose("Unknown metadata version %d found on %s",
|
||||
pvd->version, dev_name(dev));
|
||||
log_very_verbose("format1: Unknown metadata version %d "
|
||||
"found on %s", pvd->version, dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If VG is exported, set VG name back to the real name */
|
||||
_munge_exported_vg(pvd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_lvd(struct device *dev, ulong pos, struct lv_disk *disk)
|
||||
static int _read_pvd(struct device *dev, struct pv_disk *pvd)
|
||||
{
|
||||
if (dev_read(dev, pos, sizeof(*disk), disk) != sizeof(*disk))
|
||||
if (!dev_read(dev, UINT64_C(0), sizeof(*pvd), pvd)) {
|
||||
log_very_verbose("Failed to read PV data from %s",
|
||||
dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return munge_pvd(dev, pvd);
|
||||
}
|
||||
|
||||
static int _read_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
|
||||
{
|
||||
if (!dev_read(dev, pos, sizeof(*disk), disk))
|
||||
fail;
|
||||
|
||||
_xlate_lvd(disk);
|
||||
@@ -170,12 +227,19 @@ static int _read_lvd(struct device *dev, ulong pos, struct lv_disk *disk)
|
||||
static int _read_vgd(struct disk_list *data)
|
||||
{
|
||||
struct vg_disk *vgd = &data->vgd;
|
||||
ulong pos = data->pvd.vg_on_disk.base;
|
||||
if (dev_read(data->dev, pos, sizeof(*vgd), vgd) != sizeof(*vgd))
|
||||
uint64_t pos = data->pvd.vg_on_disk.base;
|
||||
if (!dev_read(data->dev, pos, sizeof(*vgd), vgd))
|
||||
fail;
|
||||
|
||||
_xlate_vgd(vgd);
|
||||
|
||||
if ((vgd->lv_max > MAX_LV) || (vgd->pv_max > MAX_PV))
|
||||
fail;
|
||||
|
||||
/* If UUID is missing, create one */
|
||||
if (vgd->vg_uuid[0] == '\0')
|
||||
uuid_from_num(vgd->vg_uuid, vgd->vg_number);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -184,12 +248,11 @@ static int _read_uuids(struct disk_list *data)
|
||||
int num_read = 0;
|
||||
struct uuid_list *ul;
|
||||
char buffer[NAME_LEN];
|
||||
ulong pos = data->pvd.pv_uuidlist_on_disk.base;
|
||||
ulong end = pos + data->pvd.pv_uuidlist_on_disk.size;
|
||||
uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
|
||||
uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
|
||||
|
||||
while (pos < end && num_read < data->vgd.pv_cur) {
|
||||
if (dev_read(data->dev, pos, sizeof(buffer), buffer) !=
|
||||
sizeof(buffer))
|
||||
if (!dev_read(data->dev, pos, sizeof(buffer), buffer))
|
||||
fail;
|
||||
|
||||
if (!(ul = pool_alloc(data->mem, sizeof(*ul))))
|
||||
@@ -214,8 +277,8 @@ static inline int _check_lvd(struct lv_disk *lvd)
|
||||
|
||||
static int _read_lvs(struct disk_list *data)
|
||||
{
|
||||
int i, read = 0;
|
||||
ulong pos;
|
||||
unsigned int i, read = 0;
|
||||
uint64_t pos;
|
||||
struct lvd_list *ll;
|
||||
struct vg_disk *vgd = &data->vgd;
|
||||
|
||||
@@ -243,12 +306,12 @@ static int _read_extents(struct disk_list *data)
|
||||
{
|
||||
size_t len = sizeof(struct pe_disk) * data->pvd.pe_total;
|
||||
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)
|
||||
fail;
|
||||
|
||||
if (dev_read(data->dev, pos, len, extents) != len)
|
||||
if (!dev_read(data->dev, pos, len, extents))
|
||||
fail;
|
||||
|
||||
_xlate_extents(extents, data->pvd.pe_total);
|
||||
@@ -257,113 +320,101 @@ static int _read_extents(struct disk_list *data)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If exported, remove "PV_EXP" from end of VG name
|
||||
*/
|
||||
static void _munge_exported_vg(struct disk_list *data)
|
||||
{
|
||||
int l, s;
|
||||
|
||||
/* Return if PV not in a VG or VG not exported */
|
||||
if ((!*data->pvd.vg_name) ||
|
||||
!(data->vgd.vg_status & VG_EXPORTED))
|
||||
return;
|
||||
|
||||
l = strlen(data->pvd.vg_name);
|
||||
s = sizeof(EXPORTED_TAG);
|
||||
if (!strncmp(data->pvd.vg_name + l - s + 1, EXPORTED_TAG, s))
|
||||
data->pvd.vg_name[l - s + 1] = '\0';
|
||||
|
||||
data->pvd.pv_status |= VG_EXPORTED;
|
||||
}
|
||||
|
||||
static struct disk_list *__read_disk(struct device *dev, struct pool *mem,
|
||||
static struct disk_list *__read_disk(const struct format_type *fmt,
|
||||
struct device *dev, struct pool *mem,
|
||||
const char *vg_name)
|
||||
{
|
||||
struct disk_list *data = pool_alloc(mem, sizeof(*data));
|
||||
struct disk_list *dl = pool_alloc(mem, sizeof(*dl));
|
||||
const char *name = dev_name(dev);
|
||||
struct lvmcache_info *info;
|
||||
|
||||
if (!data) {
|
||||
if (!dl) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data->dev = dev;
|
||||
data->mem = mem;
|
||||
list_init(&data->uuids);
|
||||
list_init(&data->lvds);
|
||||
dl->dev = dev;
|
||||
dl->mem = mem;
|
||||
list_init(&dl->uuids);
|
||||
list_init(&dl->lvds);
|
||||
|
||||
if (!read_pvd(dev, &data->pvd)) {
|
||||
if (!_read_pvd(dev, &dl->pvd)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
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 ?
|
||||
*/
|
||||
if (!*data->pvd.vg_name) {
|
||||
log_very_verbose("%s is not a member of any VG", name);
|
||||
if (!*dl->pvd.vg_name) {
|
||||
log_very_verbose("%s is not a member of any format1 VG", name);
|
||||
|
||||
/* Update VG cache */
|
||||
vgcache_add(data->pvd.vg_name, NULL, dev);
|
||||
/* vgcache_add(dl->pvd.vg_name, NULL, dev, fmt); */
|
||||
|
||||
return (vg_name) ? NULL : data;
|
||||
return (vg_name) ? NULL : dl;
|
||||
}
|
||||
|
||||
if (!_read_vgd(data)) {
|
||||
if (!_read_vgd(dl)) {
|
||||
log_error("Failed to read VG data from PV (%s)", name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* If VG is exported, set VG name back to the real name */
|
||||
_munge_exported_vg(data);
|
||||
|
||||
/* Update VG cache with what we found */
|
||||
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, dev);
|
||||
/* vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt); */
|
||||
|
||||
if (vg_name && strcmp(vg_name, data->pvd.vg_name)) {
|
||||
if (vg_name && strcmp(vg_name, dl->pvd.vg_name)) {
|
||||
log_very_verbose("%s is not a member of the VG %s",
|
||||
name, vg_name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_read_uuids(data)) {
|
||||
if (!_read_uuids(dl)) {
|
||||
log_error("Failed to read PV uuid list from %s", name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_read_lvs(data)) {
|
||||
if (!_read_lvs(dl)) {
|
||||
log_error("Failed to read LV's from %s", name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_read_extents(data)) {
|
||||
if (!_read_extents(dl)) {
|
||||
log_error("Failed to read extents from %s", name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
log_very_verbose("Found %s in %sVG %s", name,
|
||||
(data->vgd.vg_status & VG_EXPORTED) ? "exported " : "",
|
||||
data->pvd.vg_name);
|
||||
log_very_verbose("Found %s in %sVG %s", name,
|
||||
(dl->vgd.vg_status & VG_EXPORTED) ? "exported " : "",
|
||||
dl->pvd.vg_name);
|
||||
|
||||
return data;
|
||||
return dl;
|
||||
|
||||
bad:
|
||||
pool_free(data->mem, data);
|
||||
pool_free(dl->mem, dl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct disk_list *read_disk(struct device *dev, struct pool *mem,
|
||||
const char *vg_name)
|
||||
struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
|
||||
struct pool *mem, const char *vg_name)
|
||||
{
|
||||
struct disk_list *r;
|
||||
|
||||
if (!dev_open(dev, O_RDONLY)) {
|
||||
if (!dev_open(dev)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = __read_disk(dev, mem, vg_name);
|
||||
r = __read_disk(fmt, dev, mem, vg_name);
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
@@ -378,16 +429,16 @@ static void _add_pv_to_list(struct list *head, struct disk_list *data)
|
||||
|
||||
list_iterate(pvdh, head) {
|
||||
pvd = &list_item(pvdh, struct disk_list)->pvd;
|
||||
if (!strncmp(data->pvd.pv_uuid, pvd->pv_uuid,
|
||||
if (!strncmp(data->pvd.pv_uuid, pvd->pv_uuid,
|
||||
sizeof(pvd->pv_uuid))) {
|
||||
if (MAJOR(data->dev->dev) != md_major()) {
|
||||
log_very_verbose("Ignoring duplicate PV %s on "
|
||||
"%s", pvd->pv_uuid,
|
||||
"%s", pvd->pv_uuid,
|
||||
dev_name(data->dev));
|
||||
return;
|
||||
}
|
||||
log_very_verbose("Duplicate PV %s - using md %s",
|
||||
pvd->pv_uuid, dev_name(data->dev));
|
||||
log_very_verbose("Duplicate PV %s - using md %s",
|
||||
pvd->pv_uuid, dev_name(data->dev));
|
||||
list_del(pvdh);
|
||||
break;
|
||||
}
|
||||
@@ -400,20 +451,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
|
||||
* so we can free off all the memory if something goes wrong.
|
||||
*/
|
||||
int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
|
||||
struct pool *mem, struct list *head)
|
||||
int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
|
||||
struct dev_filter *filter, struct pool *mem,
|
||||
struct list *head)
|
||||
{
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
struct disk_list *data = NULL;
|
||||
|
||||
struct list *pvdh, *pvdh2;
|
||||
struct list *vgih;
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
|
||||
/* Fast path if we already saw this VG and cached the list of PVs */
|
||||
if ((pvdh = vgcache_find(vg_name))) {
|
||||
list_iterate(pvdh2, pvdh) {
|
||||
dev = list_item(pvdh2, struct pvdev_list)->dev;
|
||||
if (!(data = read_disk(dev, mem, vg_name)))
|
||||
if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) &&
|
||||
vginfo->infos.n) {
|
||||
list_iterate(vgih, &vginfo->infos) {
|
||||
dev = list_item(vgih, struct lvmcache_info)->dev;
|
||||
if (dev && !(data = read_disk(fmt, dev, mem, vg_name)))
|
||||
break;
|
||||
_add_pv_to_list(head, data);
|
||||
}
|
||||
@@ -424,9 +477,9 @@ int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
|
||||
list_size(head) == data->vgd.pv_cur))
|
||||
return 1;
|
||||
|
||||
/* Something changed. Remove the hints. */
|
||||
/* Failed */
|
||||
list_init(head);
|
||||
vgcache_del(vg_name);
|
||||
/* vgcache_del(vg_name); */
|
||||
}
|
||||
|
||||
if (!(iter = dev_iter_create(filter))) {
|
||||
@@ -436,7 +489,7 @@ int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
|
||||
|
||||
/* Otherwise do a complete scan */
|
||||
for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
|
||||
if ((data = read_disk(dev, mem, vg_name))) {
|
||||
if ((data = read_disk(fmt, dev, mem, vg_name))) {
|
||||
_add_pv_to_list(head, data);
|
||||
}
|
||||
}
|
||||
@@ -451,10 +504,10 @@ int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
|
||||
static int _write_vgd(struct disk_list *data)
|
||||
{
|
||||
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);
|
||||
if (dev_write(data->dev, pos, sizeof(*vgd), vgd) != sizeof(*vgd))
|
||||
if (!dev_write(data->dev, pos, sizeof(*vgd), vgd))
|
||||
fail;
|
||||
|
||||
_xlate_vgd(vgd);
|
||||
@@ -466,8 +519,8 @@ static int _write_uuids(struct disk_list *data)
|
||||
{
|
||||
struct uuid_list *ul;
|
||||
struct list *uh;
|
||||
ulong pos = data->pvd.pv_uuidlist_on_disk.base;
|
||||
ulong end = pos + data->pvd.pv_uuidlist_on_disk.size;
|
||||
uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
|
||||
uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
|
||||
|
||||
list_iterate(uh, &data->uuids) {
|
||||
if (pos >= end) {
|
||||
@@ -477,7 +530,7 @@ static int _write_uuids(struct disk_list *data)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
pos += NAME_LEN;
|
||||
@@ -486,10 +539,10 @@ static int _write_uuids(struct disk_list *data)
|
||||
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);
|
||||
if (dev_write(dev, pos, sizeof(*disk), disk) != sizeof(*disk))
|
||||
if (!dev_write(dev, pos, sizeof(*disk), disk))
|
||||
fail;
|
||||
|
||||
_xlate_lvd(disk);
|
||||
@@ -500,7 +553,7 @@ static int _write_lvd(struct device *dev, ulong pos, struct lv_disk *disk)
|
||||
static int _write_lvs(struct disk_list *data)
|
||||
{
|
||||
struct list *lvh;
|
||||
ulong pos;
|
||||
uint64_t pos, offset;
|
||||
|
||||
pos = data->pvd.lv_on_disk.base;
|
||||
|
||||
@@ -513,10 +566,14 @@ static int _write_lvs(struct disk_list *data)
|
||||
list_iterate(lvh, &data->lvds) {
|
||||
struct lvd_list *ll = list_item(lvh, struct lvd_list);
|
||||
|
||||
if (!_write_lvd(data->dev, pos, &ll->lvd))
|
||||
fail;
|
||||
offset = sizeof(struct lv_disk) * ll->lvd.lv_number;
|
||||
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;
|
||||
@@ -526,10 +583,10 @@ static int _write_extents(struct disk_list *data)
|
||||
{
|
||||
size_t len = sizeof(struct pe_disk) * data->pvd.pe_total;
|
||||
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);
|
||||
if (dev_write(data->dev, pos, len, extents) != len)
|
||||
if (!dev_write(data->dev, pos, len, extents))
|
||||
fail;
|
||||
|
||||
_xlate_extents(extents, data->pvd.pe_total);
|
||||
@@ -540,19 +597,19 @@ static int _write_extents(struct disk_list *data)
|
||||
static int _write_pvd(struct disk_list *data)
|
||||
{
|
||||
char *buf;
|
||||
ulong pos = data->pvd.pv_on_disk.base;
|
||||
ulong size = data->pvd.pv_on_disk.size;
|
||||
uint64_t pos = data->pvd.pv_on_disk.base;
|
||||
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.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure that the gap between the PV structure and
|
||||
/* Make sure that the gap between the PV structure and
|
||||
the next one is zeroed in order to make non LVM tools
|
||||
happy (idea from AED) */
|
||||
buf = dbg_malloc(size);
|
||||
if(!buf) {
|
||||
if (!buf) {
|
||||
log_err("Couldn't allocate temporary PV buffer.");
|
||||
return 0;
|
||||
}
|
||||
@@ -560,8 +617,8 @@ static int _write_pvd(struct disk_list *data)
|
||||
memset(buf, 0, size);
|
||||
memcpy(buf, &data->pvd, sizeof(struct pv_disk));
|
||||
|
||||
_xlate_pvd((struct pv_disk *)buf);
|
||||
if (dev_write(data->dev, pos, size, buf) != size) {
|
||||
_xlate_pvd((struct pv_disk *) buf);
|
||||
if (!dev_write(data->dev, pos, size, buf)) {
|
||||
dbg_free(buf);
|
||||
fail;
|
||||
}
|
||||
@@ -573,7 +630,8 @@ static int _write_pvd(struct disk_list *data)
|
||||
/*
|
||||
* assumes the device has been opened.
|
||||
*/
|
||||
static int __write_all_pvd(struct disk_list *data)
|
||||
static int __write_all_pvd(const struct format_type *fmt,
|
||||
struct disk_list *data)
|
||||
{
|
||||
const char *pv_name = dev_name(data->dev);
|
||||
|
||||
@@ -582,18 +640,19 @@ static int __write_all_pvd(struct disk_list *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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); */
|
||||
/*
|
||||
* Stop here for orphan pv's.
|
||||
*/
|
||||
if (data->pvd.vg_name[0] == '\0') {
|
||||
if (!test_mode())
|
||||
vgcache_add(data->pvd.vg_name, NULL, data->dev);
|
||||
/* if (!test_mode())
|
||||
vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt); */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!test_mode())
|
||||
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev);
|
||||
/* if (!test_mode())
|
||||
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev,
|
||||
fmt); */
|
||||
|
||||
if (!_write_vgd(data)) {
|
||||
log_error("Failed to write VG data to %s", pv_name);
|
||||
@@ -621,16 +680,16 @@ static int __write_all_pvd(struct disk_list *data)
|
||||
/*
|
||||
* opens the device and hands to the above fn.
|
||||
*/
|
||||
static int _write_all_pvd(struct disk_list *data)
|
||||
static int _write_all_pvd(const struct format_type *fmt, struct disk_list *data)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!dev_open(data->dev, O_WRONLY)) {
|
||||
if (!dev_open(data->dev)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = __write_all_pvd(data);
|
||||
r = __write_all_pvd(fmt, data);
|
||||
|
||||
if (!dev_close(data->dev))
|
||||
stack;
|
||||
@@ -643,17 +702,17 @@ static int _write_all_pvd(struct disk_list *data)
|
||||
* little sanity checking, so make sure correct
|
||||
* data is passed to here.
|
||||
*/
|
||||
int write_disks(struct list *pvs)
|
||||
int write_disks(const struct format_type *fmt, struct list *pvs)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct disk_list *dl;
|
||||
|
||||
list_iterate(pvh, pvs) {
|
||||
dl = list_item(pvh, struct disk_list);
|
||||
if (!(_write_all_pvd(dl)))
|
||||
if (!(_write_all_pvd(fmt, dl)))
|
||||
fail;
|
||||
|
||||
log_very_verbose("Successfully wrote data to %s",
|
||||
log_very_verbose("Successfully wrote data to %s",
|
||||
dev_name(dl->dev));
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user