mirror of
git://sourceware.org/git/lvm2.git
synced 2025-11-02 04:23:50 +03:00
Compare commits
521 Commits
CLUSTER_TA
...
old-beta4
Author | SHA1 | Date | |
---|---|---|---|
|
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 | ||
|
2e09783302 | ||
|
49734114b3 | ||
|
950d9d6ee7 | ||
|
f7974aee2e | ||
|
c870a82621 | ||
|
984929a001 | ||
|
7f9e2c1db8 | ||
|
324e8389dc | ||
|
6f448c5a38 | ||
|
ec43efbb20 | ||
|
3ed065de37 | ||
|
8152f0d72c | ||
|
f8047f4736 | ||
|
b93c66dc2d | ||
|
ac877b3065 | ||
|
dee8abfdde | ||
|
cef3841d73 | ||
|
3cd5e8a041 | ||
|
515b5f866e | ||
|
321f62bf92 | ||
|
f94fa47b52 | ||
|
c502f8a722 | ||
|
59b4868ac3 | ||
|
3634e12cce | ||
|
6d45445391 | ||
|
4f47e268cc | ||
|
0035b31cdb | ||
|
f2565aee03 | ||
|
5bd85668dd | ||
|
20f990b6ce | ||
|
6821379586 | ||
|
73b040eb49 | ||
|
49aa4b2e1e | ||
|
972241c74c | ||
|
680750e3c2 | ||
|
5e7d4d9d15 | ||
|
1e57e60613 | ||
|
3ac7ce605a | ||
|
b720dea9f0 | ||
|
c80722aefe | ||
|
a84fa69f28 | ||
|
e33781e59f | ||
|
8824bc7ece | ||
|
c2e3b0e448 | ||
|
f61a38e85a | ||
|
d23e948216 | ||
|
58bdaa31f0 | ||
|
b6491d88a6 | ||
|
f6061ba62e | ||
|
427899ddce | ||
|
c4ab7d2dbd | ||
|
0fd2ba033f | ||
|
ed38939a93 | ||
|
c7ee26ce5a | ||
|
909b8cb303 | ||
|
b0277370cf | ||
|
2ec8656bea | ||
|
b2ef256910 | ||
|
63d6ce95db | ||
|
a9532b189c | ||
|
844545411f | ||
|
4e23a2b9b8 | ||
|
5deba027eb | ||
|
fc8b7efc6f | ||
|
a1c2d9c0f3 | ||
|
4ca49a0501 | ||
|
493c53d090 | ||
|
b27e956d35 | ||
|
35ebed75c6 | ||
|
7bfdb5f77f | ||
|
8d8c02317f | ||
|
a34482feab | ||
|
cbdc8fd4a6 | ||
|
8d3afaa53c | ||
|
7ced9ef3df | ||
|
e8a9ae7e80 | ||
|
73a88ab3d3 | ||
|
aaed82738a | ||
|
de7f7b96db | ||
|
1a669b3e68 | ||
|
333af9b13a | ||
|
a5bca5e240 | ||
|
c885633e02 | ||
|
ca7e20b7ca | ||
|
545e11a3d7 | ||
|
44f5287664 | ||
|
cf510897f1 | ||
|
1d171345f8 | ||
|
4fa7e1cd49 | ||
|
acd008298e | ||
|
83a8021515 | ||
|
cf88dfb1db | ||
|
8937c4b481 | ||
|
cc6af10a4d | ||
|
6d94578955 | ||
|
08442ab71e | ||
|
10d91d213f | ||
|
b7a3b06994 | ||
|
5f12c37f23 | ||
|
585edebccd | ||
|
9921c62234 | ||
|
1ac76d2e16 | ||
|
6e983bf400 | ||
|
6a8fd4fa6e | ||
|
3698eaa2d2 | ||
|
8d97ca433c | ||
|
23cc65e537 | ||
|
2f5a3c2bbe | ||
|
f6485616cd | ||
|
6544fb43d9 | ||
|
a954b32dcc | ||
|
426dc7836c | ||
|
ff941ffc16 | ||
|
a063c201df | ||
|
e2be3fa0aa | ||
|
609da6fb50 | ||
|
fc9f3ccec3 | ||
|
f7baa67a0a | ||
|
e8d78c2cdb | ||
|
9d33366092 | ||
|
f5d61515c2 | ||
|
711a04a972 | ||
|
e5b470a3f1 | ||
|
31820e1e22 | ||
|
4849e8cd6d | ||
|
77e3b460aa | ||
|
b5321001f8 | ||
|
38eba9f5ea | ||
|
ea6f399454 | ||
|
f8bf2d7b7d | ||
|
c4856caebb | ||
|
fc1030bb22 | ||
|
9eb6cad8dc | ||
|
0fa2a78dce | ||
|
a56fa1558b | ||
|
261c73a997 | ||
|
929c1333ca | ||
|
286a79d94d | ||
|
8b951f99da | ||
|
abb449bca0 | ||
|
bd084028d1 | ||
|
138a27570b | ||
|
c2ed40a74f | ||
|
a7e7a00cab | ||
|
64a31ab3cd | ||
|
71958bc0f1 | ||
|
366ec35612 | ||
|
3738f6e8ae | ||
|
051a8e2af1 | ||
|
2f43f28d5e | ||
|
b64769754b | ||
|
a97daa18d1 | ||
|
b6556dce8b | ||
|
aa8d8bc8b5 | ||
|
0800dcfdc4 | ||
|
12b0101e94 | ||
|
021b391a02 | ||
|
d11e2b6057 | ||
|
264d90e7e5 | ||
|
f9f3da9e78 | ||
|
6435b49153 | ||
|
f9aa2941cf | ||
|
5a933d4bee | ||
|
5536aea0df | ||
|
976666d216 | ||
|
9a5bcd4392 | ||
|
812060a118 | ||
|
089b5052e6 | ||
|
874e5d72f4 | ||
|
6b11de1329 | ||
|
2245a7ad8d | ||
|
ee5ec1b870 | ||
|
74ccfe851b | ||
|
e1c24bd5a2 | ||
|
1349b79728 | ||
|
d294d7604c | ||
|
01df2cf464 | ||
|
45b7322488 | ||
|
b3055e992f | ||
|
3da548565c | ||
|
a975e85548 | ||
|
c4b5ade752 | ||
|
a4b61b0794 | ||
|
f6011184b8 | ||
|
74de118c6e | ||
|
9c25e77c17 | ||
|
440113e67e | ||
|
a11b60c445 | ||
|
a6052681ad | ||
|
482d50536a | ||
|
25c79a4fcd | ||
|
02946144ac | ||
|
71a360e9a3 | ||
|
f7912d88b1 | ||
|
975101d7d2 | ||
|
ef58c5ff55 | ||
|
e10221804a | ||
|
284ed9ee0e | ||
|
5d7b961997 | ||
|
c699a5c4b4 | ||
|
1f4ceb89cf | ||
|
0934ca0040 | ||
|
4738f892c2 | ||
|
33004fcf33 | ||
|
34d214c166 | ||
|
a56cd92a1e | ||
|
7251348507 | ||
|
01cd5c84d6 | ||
|
e210599fa6 | ||
|
dbe7cee7e9 | ||
|
7370d88ceb | ||
|
34458e0c57 | ||
|
05c8c3abf2 | ||
|
e9d464b4d3 | ||
|
6968c3ab9b | ||
|
131a8a9650 | ||
|
379ecbf9a9 | ||
|
7b9dfa9a28 | ||
|
fbd0f5eed2 | ||
|
5970f904ae | ||
|
8cbcb2868d | ||
|
8ff2a4b026 | ||
|
ae14d205a5 | ||
|
ec5d560ec5 | ||
|
fb543b53c0 | ||
|
39c16422e2 | ||
|
4d5b273ebe | ||
|
ed6a860fad | ||
|
423e579292 | ||
|
ee11aa9e75 | ||
|
c46d20fa92 | ||
|
dc8d17574c | ||
|
5c17cd04c8 | ||
|
67ada02076 | ||
|
32d94c2eaf | ||
|
687b39a12a | ||
|
705af407bf | ||
|
080052da2e | ||
|
ef735fd92a | ||
|
17c16dcafc | ||
|
a89b3018fb | ||
|
851e2ebd32 | ||
|
1225ce7fe8 | ||
|
7e77a31b96 | ||
|
d146b9002f | ||
|
1f9d567b23 | ||
|
ed1b3a023c | ||
|
1ca18f501a | ||
|
49588ccd98 | ||
|
098dedc092 | ||
|
b06f6b9545 | ||
|
ba3cb94999 | ||
|
74c67fbf4b | ||
|
32b46e4910 | ||
|
ecf5539ed2 | ||
|
ac9db4e4d5 | ||
|
0eb96094b0 | ||
|
30b3ac7dc5 | ||
|
0092790c7d | ||
|
28909d8a51 | ||
|
b20cfbb7b6 | ||
|
97639bd0a8 | ||
|
161ec73c96 | ||
|
957d6bea15 | ||
|
f8b6e5b414 | ||
|
1ab450870e | ||
|
de45f4884c | ||
|
5da1f3e7c8 | ||
|
983014952b | ||
|
55298019a3 | ||
|
a1ffc3f271 | ||
|
2fb60aa997 | ||
|
f5ec76537a | ||
|
728491fd2b | ||
|
d9d3f2b9e4 | ||
|
3fe4864f65 | ||
|
0b156f22a4 | ||
|
35b1d93813 | ||
|
d770851ac0 | ||
|
989e7b1033 | ||
|
c4e0eb7b49 | ||
|
71f5d0dac7 | ||
|
561b0c4381 | ||
|
995fbc7330 | ||
|
10ab8949c4 | ||
|
c441202fea | ||
|
ca261b0bee | ||
|
52f3709f67 | ||
|
c2ca6187fe | ||
|
671a13d295 | ||
|
14c3e2eccf | ||
|
08e5b852c2 | ||
|
1c9606c824 | ||
|
3cd47b5c9b | ||
|
aedc729087 | ||
|
5f7cfa3fa9 | ||
|
0083f30af5 | ||
|
4a06f05ef5 | ||
|
8f37cadce8 | ||
|
a11603ca6c | ||
|
86274842e9 | ||
|
cf9c955a44 | ||
|
55d828c35f | ||
|
cdff28aca6 | ||
|
b9da39274f | ||
|
c379aa5782 | ||
|
9dcabac9dd | ||
|
794f3a2b9f | ||
|
2066121b7c | ||
|
0c4067f143 | ||
|
8aa69243b7 | ||
|
8697263bde | ||
|
ea25c4f65c | ||
|
82ac3ebd7e | ||
|
13cb94909c | ||
|
b57ca2a763 | ||
|
83c49e9745 | ||
|
e15771d78d | ||
|
6edc4920ba | ||
|
302bb1bd93 | ||
|
529b1bceee | ||
|
42cd47d32e | ||
|
711d884c2e | ||
|
183d1c4674 | ||
|
faed63a0bb | ||
|
53bff262f8 | ||
|
3251a708e4 | ||
|
b5dbdbf7b2 | ||
|
a9649e92c9 | ||
|
b561f1fa8b | ||
|
cecd7491b5 | ||
|
55a66322b5 | ||
|
155c31a2d7 | ||
|
a89ce91089 | ||
|
b897fe6700 | ||
|
548a351b06 | ||
|
4b1da57ca1 | ||
|
529aec7f25 | ||
|
1661e545cb | ||
|
ec71d08878 | ||
|
ac258b7dd7 | ||
|
0f57876233 | ||
|
1d25a3693d | ||
|
45fa428bf1 | ||
|
177fa80f1a | ||
|
3261261bfe | ||
|
d4de7934f8 | ||
|
c3475af809 | ||
|
b12f707812 | ||
|
22c0c34d60 | ||
|
a60b66f230 | ||
|
83f6e93628 | ||
|
222b5f0229 | ||
|
30aa383e26 | ||
|
676b401294 | ||
|
ebf57159de | ||
|
199d2aafec | ||
|
81952f56fd | ||
|
c5bac82b43 | ||
|
081b86109c | ||
|
8ac2028a75 | ||
|
264fed1c9f | ||
|
dd59f7b2c7 | ||
|
9245a760db | ||
|
b61b32bbc3 | ||
|
09b3914f5d | ||
|
fe644e4c9e | ||
|
7b09bf2156 | ||
|
987d0aae66 | ||
|
9cbcbc1c22 | ||
|
cfc4e2bc60 | ||
|
a03405fa81 | ||
|
d5c9ccbe6e | ||
|
e52772d65f | ||
|
1e3259e728 | ||
|
e905a20a60 | ||
|
88e2be7a33 | ||
|
8939131600 | ||
|
ba37ebff8b | ||
|
28f4cb7e07 | ||
|
db1e7102cd | ||
|
07eb7a5830 | ||
|
b7c6c685fa | ||
|
212134df70 | ||
|
6eeb5528f5 | ||
|
54fad845c9 | ||
|
d6c0de6fc7 | ||
|
649c8649f7 | ||
|
da2f53d1b1 | ||
|
405139e3b8 | ||
|
4f8d347171 | ||
|
bf0db4876c | ||
|
47a14884d6 | ||
|
3a7bbc8b08 | ||
|
1b1d65372c | ||
|
fd2faaa16e | ||
|
0609cdb9ea | ||
|
d3bb140f89 | ||
|
b31dc66628 | ||
|
09476171a6 | ||
|
33dee813b5 | ||
|
bb4e73c40b | ||
|
b1f23ffa94 | ||
|
b0e8cec1e7 | ||
|
5077ae19bc | ||
|
0d8447bf59 | ||
|
c6cf08a274 | ||
|
dc49ae519e | ||
|
904539476a | ||
|
3fbf02dc82 | ||
|
c9392a840d | ||
|
d164e8ab72 | ||
|
6dc62c9fb6 | ||
|
87a9684d66 | ||
|
94525e2f44 | ||
|
b408b1b3b9 | ||
|
27c2f09e32 | ||
|
19bc4d3349 | ||
|
f2b6c424d6 | ||
|
a49d4453e9 | ||
|
65e50087b9 | ||
|
2d90f759d9 | ||
|
4230ac7674 | ||
|
d96e9182e9 | ||
|
68c87b9616 | ||
|
7f8e9a0b6d | ||
|
81a229f2a5 | ||
|
8be7ae2733 | ||
|
846bca4cb1 | ||
|
f36f353789 | ||
|
939a2731ed |
2
BUGS
Normal file
2
BUGS
Normal file
@@ -0,0 +1,2 @@
|
||||
Snapshots under 2.4.18 can deadlock due to a bug in the VM system.
|
||||
2.4.19-pre8 is fine.
|
340
COPYING
Normal file
340
COPYING
Normal file
@@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
483
COPYING.LIB
Normal file
483
COPYING.LIB
Normal file
@@ -0,0 +1,483 @@
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the library GPL. It is
|
||||
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Library General Public License, applies to some
|
||||
specially designated Free Software Foundation software, and to any
|
||||
other libraries whose authors decide to use it. You can use it for
|
||||
your libraries, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if
|
||||
you distribute copies of the library, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link a program with the library, you must provide
|
||||
complete object files to the recipients so that they can relink them
|
||||
with the library, after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
Our method of protecting your rights has two steps: (1) copyright
|
||||
the library, and (2) offer you this license which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
Also, for each distributor's protection, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
library. If the library is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original
|
||||
version, so that any problems introduced by others will not reflect on
|
||||
the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that companies distributing free
|
||||
software will individually obtain patent licenses, thus in effect
|
||||
transforming the program into proprietary software. To prevent this,
|
||||
we have made it clear that any patent must be licensed for everyone's
|
||||
free use or not licensed at all.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the ordinary
|
||||
GNU General Public License, which was designed for utility programs. This
|
||||
license, the GNU Library General Public License, applies to certain
|
||||
designated libraries. This license is quite different from the ordinary
|
||||
one; be sure to read it in full, and don't assume that anything in it is
|
||||
the same as in the ordinary license.
|
||||
|
||||
The reason we have a separate public license for some libraries is that
|
||||
they blur the distinction we usually make between modifying or adding to a
|
||||
program and simply using it. Linking a program with a library, without
|
||||
changing the library, is in some sense simply using the library, and is
|
||||
analogous to running a utility program or application program. However, in
|
||||
a textual and legal sense, the linked executable is a combined work, a
|
||||
derivative of the original library, and the ordinary General Public License
|
||||
treats it as such.
|
||||
|
||||
Because of this blurred distinction, using the ordinary General
|
||||
Public License for libraries did not effectively promote software
|
||||
sharing, because most developers did not use the libraries. We
|
||||
concluded that weaker conditions might promote sharing better.
|
||||
|
||||
However, unrestricted linking of non-free programs would deprive the
|
||||
users of those programs of all benefit from the free status of the
|
||||
libraries themselves. This Library General Public License is intended to
|
||||
permit developers of non-free programs to use free libraries, while
|
||||
preserving your freedom as a user of such programs to change the free
|
||||
libraries that are incorporated in them. (We have not seen how to achieve
|
||||
this as regards changes in header files, but we have achieved it as regards
|
||||
changes in the actual functions of the Library.) The hope is that this
|
||||
will lead to faster development of free libraries.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, while the latter only
|
||||
works together with the library.
|
||||
|
||||
Note that it is possible for a library to be covered by the ordinary
|
||||
General Public License rather than by this special one.
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library which
|
||||
contains a notice placed by the copyright holder or other authorized
|
||||
party saying it may be distributed under the terms of this Library
|
||||
General Public License (also called "this License"). Each licensee is
|
||||
addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also compile or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
c) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
d) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the source code distributed need not include anything that is normally
|
||||
distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Library General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This 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 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 library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
45
INSTALL
Normal file
45
INSTALL
Normal file
@@ -0,0 +1,45 @@
|
||||
LVM2 installation
|
||||
=================
|
||||
|
||||
1) Install device-mapper
|
||||
|
||||
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
|
||||
and libdevmapper.so should be present.
|
||||
|
||||
The device-mapper is available from:
|
||||
ftp://ftp.sistina.com/pub/LVM2/device-mapper/
|
||||
|
||||
|
||||
2) Generate custom makefiles.
|
||||
|
||||
Run the 'configure' script from the top directory.
|
||||
|
||||
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.
|
||||
|
||||
Run 'make install' from the top directory.
|
||||
|
||||
|
||||
4) Create a configuration file
|
||||
|
||||
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 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.
|
||||
|
@@ -22,5 +22,14 @@ VPATH = @srcdir@
|
||||
|
||||
SUBDIRS = include man lib tools
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS += lib/format1 \
|
||||
test/mm test/device test/format1 test/regex test/filters
|
||||
endif
|
||||
|
||||
include make.tmpl
|
||||
|
||||
lib: include
|
||||
tools: include lib
|
||||
|
||||
|
||||
|
27
README
27
README
@@ -1,2 +1,25 @@
|
||||
This is pretty much empty so far...if you can't see subdirectories,
|
||||
try 'cvs -f update'
|
||||
This directory contains a beta release of LVM2, the new version of
|
||||
the userland LVM tools designed for the new device-mapper for
|
||||
the Linux kernel.
|
||||
|
||||
The device-mapper needs to be installed before compiling these LVM2 tools.
|
||||
|
||||
For more information about LVM2 read the 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/
|
||||
|
||||
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
|
||||
|
||||
Mailing list for discussion/bug reports etc.
|
||||
lvm-devel@sistina.com
|
||||
Subscribe from http://lists.sistina.com/mailman/listinfo/lvm-devel
|
||||
|
||||
|
35
TODO
35
TODO
@@ -1,35 +0,0 @@
|
||||
before alpha
|
||||
------------
|
||||
|
||||
FIXME review
|
||||
extra validation in format1 (must be done before alpha)
|
||||
status flag review (confirm all use of ->status is consistent)
|
||||
file system handling (being done)
|
||||
error message review
|
||||
correct handling of *existing* snapshots
|
||||
review statics
|
||||
review consistency checks for full compatibility with LVM1
|
||||
iospace split/rename
|
||||
|
||||
before beta1
|
||||
-----------
|
||||
|
||||
autobackup/text format
|
||||
export/import
|
||||
striping
|
||||
64bit review
|
||||
LVM1 compatible tool exit codes
|
||||
|
||||
before 2.0
|
||||
----------
|
||||
|
||||
partial activation
|
||||
atomic transactions
|
||||
bidirectional format1/format2 migration tool
|
||||
persistent minors
|
||||
stats
|
||||
snapshots
|
||||
pvmove
|
||||
|
||||
|
||||
|
86
WHATS_NEW
Normal file
86
WHATS_NEW
Normal file
@@ -0,0 +1,86 @@
|
||||
Mondy 18th November 2002
|
||||
========================
|
||||
|
||||
The new format of LVM metadata is ready for you to test!
|
||||
We expect it to be more efficient and more robust than the original format.
|
||||
It's more compact and supports transactional changes and replication.
|
||||
Should things go wrong on a system, it's human-readable (and editable).
|
||||
|
||||
Please report any problems you find to the mailing list,
|
||||
linux-lvm@sistina.com. The software has NOT yet been thoroughly
|
||||
tested and so quite possibly there'll still be some bugs in it.
|
||||
Be aware of the disclaimer in the COPYING file.
|
||||
|
||||
While testing, we recommend turning logging on in the configuration file
|
||||
to provide us with diagnostic information:
|
||||
log {
|
||||
file="/tmp/lvm2.log"
|
||||
level=6
|
||||
}
|
||||
|
||||
You should schedule regular backups of your configuration file and
|
||||
metadata backups and archives (normally kept under /etc/lvm).
|
||||
|
||||
Please read docs/example.conf and "man lvm.conf" to find out more about
|
||||
the configuration file.
|
||||
|
||||
To convert an existing volume group called vg1 to the new format using
|
||||
the default settings, use "vgconvert -M2 vg1". See "man vgconvert".
|
||||
|
||||
-M (or --metadatatype in its long form) is a new flag to indicate which
|
||||
format of metadata the command should use for anything it creates.
|
||||
Currently, the valid types are "lvm1" and "lvm2" and they can be
|
||||
abbreviated to "1" and "2" respectively. The default value for this
|
||||
flag can be changed in the global section in the config file.
|
||||
|
||||
Backwards-compatible support for the original LVM1 metadata format is
|
||||
maintained, but it can be moved into a shared library or removed
|
||||
completely with configure's --with-lvm1 option.
|
||||
|
||||
Under LVM2, the basic unit of metadata is the volume group. Different
|
||||
volume groups can use different formats of metadata - vg1 could use
|
||||
the original LVM1 format while vg2 used the new format - but you can't
|
||||
mix formats within a volume group. So to add a PV to an LVM2-format
|
||||
volume group you must run "pvcreate -M2" on it, followed by "vgextend".
|
||||
|
||||
With LVM2-format metadata, lvextend will let you specify striping
|
||||
parameters. So an LV could consist of two or more "segments" - the
|
||||
first segment could have 3 stripes while the second segment has just 2.
|
||||
|
||||
LVM2 maintains a backup of the current metadata for each volume group
|
||||
in /etc/lvm/backup, and puts copies of previous versions in
|
||||
/etc/lvm/archive. "vgcfgbackup" and "vgcfgrestore" can be used to
|
||||
create and restore from these files. If you fully understand what
|
||||
you're doing, metadata can be changed by editing a copy of a current
|
||||
backup file and using vgcfgrestore to reload it.
|
||||
|
||||
Please read the pvcreate man page for more information on the new
|
||||
format for metadata.
|
||||
|
||||
All tools that can change things have a --test flag which can be used
|
||||
to check the effect of a set of cmdline args without really making the
|
||||
changes.
|
||||
|
||||
|
||||
What's not finished?
|
||||
====================
|
||||
The internal cache. If you turn on debugging output you'll see lots of
|
||||
repeated disk reads, many of which will eventually get optimised out.
|
||||
|
||||
--test sometimes causes a command to fail (e.g. vgconvert --test) even
|
||||
though the real command would work: again, fixing this is waiting for
|
||||
the work on the cache.
|
||||
|
||||
Several of the tools do not yet contain the logic to handle full
|
||||
recovery: combinations of pvcreate and vgcfgrestore may sometimes be
|
||||
needed to restore metadata if a tool gets interrupted or crashes or
|
||||
finds something unexpected. This applies particularly to tools that
|
||||
work on more than one volume group at once (e.g. vgsplit).
|
||||
|
||||
Display output. Some metadata information cannot yet be displayed.
|
||||
Work has started on new display tools.
|
||||
|
||||
Recovery tools to salvage "lost" metadata directly from the disks:
|
||||
but we hope the new format will mean such tools are hardly ever needed!
|
||||
|
||||
|
257
configure
vendored
257
configure
vendored
@@ -17,14 +17,15 @@ ac_help="$ac_help
|
||||
ac_help="$ac_help
|
||||
--with-group=GROUP Set the group owner of installed files "
|
||||
ac_help="$ac_help
|
||||
--with-kernel_dir=DIR linux kernel source in DIR [/usr/src/linux]"
|
||||
--with-lvm1=TYPE LVM1 metadata support: internal/shared/none
|
||||
[TYPE=internal] "
|
||||
ac_help="$ac_help
|
||||
--enable-jobs=NUM Number of jobs to run simultaneously"
|
||||
ac_help="$ac_help
|
||||
--enable-static_link Use this to link the tools to the liblvm library
|
||||
statically. Default is dynamic linking"
|
||||
ac_help="$ac_help
|
||||
--disable-readline Disable readline support"
|
||||
--enable-readline Enable readline support"
|
||||
|
||||
# Initialize some variables set by options.
|
||||
# The variables have the same names as the options, with
|
||||
@@ -561,7 +562,7 @@ do
|
||||
# Extract the first word of "$ac_prog", so it can be a program name with args.
|
||||
set dummy $ac_prog; ac_word=$2
|
||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
|
||||
echo "configure:565: checking for $ac_word" >&5
|
||||
echo "configure:566: checking for $ac_word" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
@@ -593,7 +594,7 @@ done
|
||||
# Extract the first word of "gcc", so it can be a program name with args.
|
||||
set dummy gcc; ac_word=$2
|
||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
|
||||
echo "configure:597: checking for $ac_word" >&5
|
||||
echo "configure:598: checking for $ac_word" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
@@ -623,7 +624,7 @@ if test -z "$CC"; then
|
||||
# Extract the first word of "cc", so it can be a program name with args.
|
||||
set dummy cc; ac_word=$2
|
||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
|
||||
echo "configure:627: checking for $ac_word" >&5
|
||||
echo "configure:628: checking for $ac_word" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
@@ -674,7 +675,7 @@ fi
|
||||
# Extract the first word of "cl", so it can be a program name with args.
|
||||
set dummy cl; ac_word=$2
|
||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
|
||||
echo "configure:678: checking for $ac_word" >&5
|
||||
echo "configure:679: checking for $ac_word" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
@@ -706,7 +707,7 @@ fi
|
||||
fi
|
||||
|
||||
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
|
||||
echo "configure:710: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
|
||||
echo "configure:711: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
|
||||
|
||||
ac_ext=c
|
||||
# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
|
||||
@@ -717,12 +718,12 @@ cross_compiling=$ac_cv_prog_cc_cross
|
||||
|
||||
cat > conftest.$ac_ext << EOF
|
||||
|
||||
#line 721 "configure"
|
||||
#line 722 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
main(){return(0);}
|
||||
EOF
|
||||
if { (eval echo configure:726: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:727: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
ac_cv_prog_cc_works=yes
|
||||
# If we can't run a trivial program, we are probably using a cross compiler.
|
||||
if (./conftest; exit) 2>/dev/null; then
|
||||
@@ -748,12 +749,12 @@ if test $ac_cv_prog_cc_works = no; then
|
||||
{ echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
|
||||
fi
|
||||
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
|
||||
echo "configure:752: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
|
||||
echo "configure:753: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
|
||||
echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
|
||||
cross_compiling=$ac_cv_prog_cc_cross
|
||||
|
||||
echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
|
||||
echo "configure:757: checking whether we are using GNU C" >&5
|
||||
echo "configure:758: checking whether we are using GNU C" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
@@ -762,7 +763,7 @@ else
|
||||
yes;
|
||||
#endif
|
||||
EOF
|
||||
if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:766: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
|
||||
if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:767: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
|
||||
ac_cv_prog_gcc=yes
|
||||
else
|
||||
ac_cv_prog_gcc=no
|
||||
@@ -781,7 +782,7 @@ ac_test_CFLAGS="${CFLAGS+set}"
|
||||
ac_save_CFLAGS="$CFLAGS"
|
||||
CFLAGS=
|
||||
echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
|
||||
echo "configure:785: checking whether ${CC-cc} accepts -g" >&5
|
||||
echo "configure:786: checking whether ${CC-cc} accepts -g" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
@@ -824,7 +825,7 @@ fi
|
||||
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
|
||||
# ./install, which can be erroneously created by make from ./install.sh.
|
||||
echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
|
||||
echo "configure:828: checking for a BSD compatible install" >&5
|
||||
echo "configure:829: checking for a BSD compatible install" >&5
|
||||
if test -z "$INSTALL"; then
|
||||
if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
@@ -877,7 +878,7 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
|
||||
test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
|
||||
|
||||
echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
|
||||
echo "configure:881: checking whether ln -s works" >&5
|
||||
echo "configure:882: checking whether ln -s works" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
@@ -898,7 +899,7 @@ else
|
||||
fi
|
||||
|
||||
echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
|
||||
echo "configure:902: checking whether ${MAKE-make} sets \${MAKE}" >&5
|
||||
echo "configure:903: checking whether ${MAKE-make} sets \${MAKE}" >&5
|
||||
set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
@@ -927,7 +928,7 @@ fi
|
||||
# Extract the first word of "ranlib", so it can be a program name with args.
|
||||
set dummy ranlib; ac_word=$2
|
||||
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
|
||||
echo "configure:931: checking for $ac_word" >&5
|
||||
echo "configure:932: checking for $ac_word" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
@@ -960,12 +961,12 @@ for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
|
||||
do
|
||||
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
|
||||
echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
|
||||
echo "configure:964: checking for $ac_hdr that defines DIR" >&5
|
||||
echo "configure:965: checking for $ac_hdr that defines DIR" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 969 "configure"
|
||||
#line 970 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <sys/types.h>
|
||||
#include <$ac_hdr>
|
||||
@@ -973,7 +974,7 @@ int main() {
|
||||
DIR *dirp = 0;
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:977: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
if { (eval echo configure:978: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
rm -rf conftest*
|
||||
eval "ac_cv_header_dirent_$ac_safe=yes"
|
||||
else
|
||||
@@ -998,7 +999,7 @@ done
|
||||
# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
|
||||
if test $ac_header_dirent = dirent.h; then
|
||||
echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
|
||||
echo "configure:1002: checking for opendir in -ldir" >&5
|
||||
echo "configure:1003: checking for opendir in -ldir" >&5
|
||||
ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
|
||||
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
@@ -1006,7 +1007,7 @@ else
|
||||
ac_save_LIBS="$LIBS"
|
||||
LIBS="-ldir $LIBS"
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1010 "configure"
|
||||
#line 1011 "configure"
|
||||
#include "confdefs.h"
|
||||
/* Override any gcc2 internal prototype to avoid an error. */
|
||||
/* We use char because int might match the return type of a gcc2
|
||||
@@ -1017,7 +1018,7 @@ int main() {
|
||||
opendir()
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1021: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:1022: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
rm -rf conftest*
|
||||
eval "ac_cv_lib_$ac_lib_var=yes"
|
||||
else
|
||||
@@ -1039,7 +1040,7 @@ fi
|
||||
|
||||
else
|
||||
echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
|
||||
echo "configure:1043: checking for opendir in -lx" >&5
|
||||
echo "configure:1044: checking for opendir in -lx" >&5
|
||||
ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
|
||||
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
@@ -1047,7 +1048,7 @@ else
|
||||
ac_save_LIBS="$LIBS"
|
||||
LIBS="-lx $LIBS"
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1051 "configure"
|
||||
#line 1052 "configure"
|
||||
#include "confdefs.h"
|
||||
/* Override any gcc2 internal prototype to avoid an error. */
|
||||
/* We use char because int might match the return type of a gcc2
|
||||
@@ -1058,7 +1059,7 @@ int main() {
|
||||
opendir()
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1062: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:1063: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
rm -rf conftest*
|
||||
eval "ac_cv_lib_$ac_lib_var=yes"
|
||||
else
|
||||
@@ -1081,7 +1082,7 @@ fi
|
||||
fi
|
||||
|
||||
echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
|
||||
echo "configure:1085: checking how to run the C preprocessor" >&5
|
||||
echo "configure:1086: checking how to run the C preprocessor" >&5
|
||||
# On Suns, sometimes $CPP names a directory.
|
||||
if test -n "$CPP" && test -d "$CPP"; then
|
||||
CPP=
|
||||
@@ -1096,13 +1097,13 @@ else
|
||||
# On the NeXT, cc -E runs the code through the compiler's parser,
|
||||
# not just through cpp.
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1100 "configure"
|
||||
#line 1101 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <assert.h>
|
||||
Syntax Error
|
||||
EOF
|
||||
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
|
||||
{ (eval echo configure:1106: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
{ (eval echo configure:1107: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
|
||||
if test -z "$ac_err"; then
|
||||
:
|
||||
@@ -1113,13 +1114,13 @@ else
|
||||
rm -rf conftest*
|
||||
CPP="${CC-cc} -E -traditional-cpp"
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1117 "configure"
|
||||
#line 1118 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <assert.h>
|
||||
Syntax Error
|
||||
EOF
|
||||
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
|
||||
{ (eval echo configure:1123: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
{ (eval echo configure:1124: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
|
||||
if test -z "$ac_err"; then
|
||||
:
|
||||
@@ -1130,13 +1131,13 @@ else
|
||||
rm -rf conftest*
|
||||
CPP="${CC-cc} -nologo -E"
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1134 "configure"
|
||||
#line 1135 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <assert.h>
|
||||
Syntax Error
|
||||
EOF
|
||||
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
|
||||
{ (eval echo configure:1140: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
{ (eval echo configure:1141: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
|
||||
if test -z "$ac_err"; then
|
||||
:
|
||||
@@ -1161,12 +1162,12 @@ fi
|
||||
echo "$ac_t""$CPP" 1>&6
|
||||
|
||||
echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
|
||||
echo "configure:1165: checking for ANSI C header files" >&5
|
||||
echo "configure:1166: checking for ANSI C header files" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1170 "configure"
|
||||
#line 1171 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
@@ -1174,7 +1175,7 @@ else
|
||||
#include <float.h>
|
||||
EOF
|
||||
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
|
||||
{ (eval echo configure:1178: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
{ (eval echo configure:1179: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
|
||||
if test -z "$ac_err"; then
|
||||
rm -rf conftest*
|
||||
@@ -1191,7 +1192,7 @@ rm -f conftest*
|
||||
if test $ac_cv_header_stdc = yes; then
|
||||
# SunOS 4.x string.h does not declare mem*, contrary to ANSI.
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1195 "configure"
|
||||
#line 1196 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <string.h>
|
||||
EOF
|
||||
@@ -1209,7 +1210,7 @@ fi
|
||||
if test $ac_cv_header_stdc = yes; then
|
||||
# ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1213 "configure"
|
||||
#line 1214 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <stdlib.h>
|
||||
EOF
|
||||
@@ -1230,7 +1231,7 @@ if test "$cross_compiling" = yes; then
|
||||
:
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1234 "configure"
|
||||
#line 1235 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <ctype.h>
|
||||
#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
|
||||
@@ -1241,7 +1242,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
|
||||
exit (0); }
|
||||
|
||||
EOF
|
||||
if { (eval echo configure:1245: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
|
||||
if { (eval echo configure:1246: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
|
||||
then
|
||||
:
|
||||
else
|
||||
@@ -1268,17 +1269,17 @@ for ac_hdr in fcntl.h malloc.h sys/ioctl.h unistd.h
|
||||
do
|
||||
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
|
||||
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
|
||||
echo "configure:1272: checking for $ac_hdr" >&5
|
||||
echo "configure:1273: checking for $ac_hdr" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1277 "configure"
|
||||
#line 1278 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <$ac_hdr>
|
||||
EOF
|
||||
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
|
||||
{ (eval echo configure:1282: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
{ (eval echo configure:1283: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
|
||||
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
|
||||
if test -z "$ac_err"; then
|
||||
rm -rf conftest*
|
||||
@@ -1306,18 +1307,18 @@ done
|
||||
|
||||
|
||||
echo $ac_n "checking for working const""... $ac_c" 1>&6
|
||||
echo "configure:1310: checking for working const" >&5
|
||||
echo "configure:1311: checking for working const" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1315 "configure"
|
||||
#line 1316 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
int main() {
|
||||
|
||||
/* Ultrix mips cc rejects this. */
|
||||
typedef int charset[2]; const charset x;
|
||||
typedef int charset[2]; const charset x = {0,0};
|
||||
/* SunOS 4.1.1 cc rejects this. */
|
||||
char const *const *ccp;
|
||||
char **p;
|
||||
@@ -1360,7 +1361,7 @@ ccp = (char const *const *) p;
|
||||
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1364: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
if { (eval echo configure:1365: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
rm -rf conftest*
|
||||
ac_cv_c_const=yes
|
||||
else
|
||||
@@ -1381,21 +1382,21 @@ EOF
|
||||
fi
|
||||
|
||||
echo $ac_n "checking for inline""... $ac_c" 1>&6
|
||||
echo "configure:1385: checking for inline" >&5
|
||||
echo "configure:1386: checking for inline" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
ac_cv_c_inline=no
|
||||
for ac_kw in inline __inline__ __inline; do
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1392 "configure"
|
||||
#line 1393 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
int main() {
|
||||
} $ac_kw foo() {
|
||||
} int $ac_kw foo() {
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1399: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
if { (eval echo configure:1400: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
rm -rf conftest*
|
||||
ac_cv_c_inline=$ac_kw; break
|
||||
else
|
||||
@@ -1421,12 +1422,12 @@ EOF
|
||||
esac
|
||||
|
||||
echo $ac_n "checking for off_t""... $ac_c" 1>&6
|
||||
echo "configure:1425: checking for off_t" >&5
|
||||
echo "configure:1426: checking for off_t" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1430 "configure"
|
||||
#line 1431 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <sys/types.h>
|
||||
#if STDC_HEADERS
|
||||
@@ -1454,12 +1455,12 @@ EOF
|
||||
fi
|
||||
|
||||
echo $ac_n "checking for pid_t""... $ac_c" 1>&6
|
||||
echo "configure:1458: checking for pid_t" >&5
|
||||
echo "configure:1459: checking for pid_t" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1463 "configure"
|
||||
#line 1464 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <sys/types.h>
|
||||
#if STDC_HEADERS
|
||||
@@ -1487,12 +1488,12 @@ EOF
|
||||
fi
|
||||
|
||||
echo $ac_n "checking for size_t""... $ac_c" 1>&6
|
||||
echo "configure:1491: checking for size_t" >&5
|
||||
echo "configure:1492: checking for size_t" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1496 "configure"
|
||||
#line 1497 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <sys/types.h>
|
||||
#if STDC_HEADERS
|
||||
@@ -1520,12 +1521,12 @@ EOF
|
||||
fi
|
||||
|
||||
echo $ac_n "checking for st_rdev in struct stat""... $ac_c" 1>&6
|
||||
echo "configure:1524: checking for st_rdev in struct stat" >&5
|
||||
echo "configure:1525: checking for st_rdev in struct stat" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_struct_st_rdev'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1529 "configure"
|
||||
#line 1530 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -1533,7 +1534,7 @@ int main() {
|
||||
struct stat s; s.st_rdev;
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1537: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
if { (eval echo configure:1538: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
rm -rf conftest*
|
||||
ac_cv_struct_st_rdev=yes
|
||||
else
|
||||
@@ -1554,12 +1555,12 @@ EOF
|
||||
fi
|
||||
|
||||
echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
|
||||
echo "configure:1558: checking whether time.h and sys/time.h may both be included" >&5
|
||||
echo "configure:1559: checking whether time.h and sys/time.h may both be included" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1563 "configure"
|
||||
#line 1564 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
@@ -1568,7 +1569,7 @@ int main() {
|
||||
struct tm *tp;
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1572: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
if { (eval echo configure:1573: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
rm -rf conftest*
|
||||
ac_cv_header_time=yes
|
||||
else
|
||||
@@ -1609,15 +1610,21 @@ else
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --with-kernel_dir or --without-kernel_dir was given.
|
||||
if test "${with_kernel_dir+set}" = set; then
|
||||
withval="$with_kernel_dir"
|
||||
kernel_dir="$withval"
|
||||
# Check whether --with-lvm1 or --without-lvm1 was given.
|
||||
if test "${with_lvm1+set}" = set; then
|
||||
withval="$with_lvm1"
|
||||
LVM1="$withval"
|
||||
else
|
||||
kernel_dir=/usr/src/linux
|
||||
LVM1="internal"
|
||||
fi
|
||||
|
||||
|
||||
if [ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ];
|
||||
then { echo "configure: error: --with-lvm1 parameter invalid
|
||||
" 1>&2; exit 1; }
|
||||
exit
|
||||
fi;
|
||||
|
||||
# Check whether --enable-jobs or --disable-jobs was given.
|
||||
if test "${enable_jobs+set}" = set; then
|
||||
enableval="$enable_jobs"
|
||||
@@ -1642,7 +1649,7 @@ if test "${enable_readline+set}" = set; then
|
||||
\
|
||||
READLINE=$enableval
|
||||
else
|
||||
READLINE=yes
|
||||
READLINE=no
|
||||
fi
|
||||
|
||||
|
||||
@@ -1652,13 +1659,13 @@ fi;
|
||||
|
||||
if test $ac_cv_prog_gcc = yes; then
|
||||
echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
|
||||
echo "configure:1656: checking whether ${CC-cc} needs -traditional" >&5
|
||||
echo "configure:1663: checking whether ${CC-cc} needs -traditional" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
ac_pattern="Autoconf.*'x'"
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1662 "configure"
|
||||
#line 1669 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <sgtty.h>
|
||||
Autoconf TIOCGETP
|
||||
@@ -1676,7 +1683,7 @@ rm -f conftest*
|
||||
|
||||
if test $ac_cv_prog_gcc_traditional = no; then
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1680 "configure"
|
||||
#line 1687 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <termio.h>
|
||||
Autoconf TCGETA
|
||||
@@ -1698,12 +1705,12 @@ echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
|
||||
fi
|
||||
|
||||
echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
|
||||
echo "configure:1702: checking return type of signal handlers" >&5
|
||||
echo "configure:1709: checking return type of signal handlers" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1707 "configure"
|
||||
#line 1714 "configure"
|
||||
#include "confdefs.h"
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
@@ -1720,7 +1727,7 @@ int main() {
|
||||
int i;
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1724: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
if { (eval echo configure:1731: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
|
||||
rm -rf conftest*
|
||||
ac_cv_type_signal=void
|
||||
else
|
||||
@@ -1739,12 +1746,12 @@ EOF
|
||||
|
||||
|
||||
echo $ac_n "checking for vprintf""... $ac_c" 1>&6
|
||||
echo "configure:1743: checking for vprintf" >&5
|
||||
echo "configure:1750: checking for vprintf" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1748 "configure"
|
||||
#line 1755 "configure"
|
||||
#include "confdefs.h"
|
||||
/* System header to define __stub macros and hopefully few prototypes,
|
||||
which can conflict with char vprintf(); below. */
|
||||
@@ -1767,7 +1774,7 @@ vprintf();
|
||||
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1771: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:1778: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
rm -rf conftest*
|
||||
eval "ac_cv_func_vprintf=yes"
|
||||
else
|
||||
@@ -1791,12 +1798,12 @@ fi
|
||||
|
||||
if test "$ac_cv_func_vprintf" != yes; then
|
||||
echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
|
||||
echo "configure:1795: checking for _doprnt" >&5
|
||||
echo "configure:1802: checking for _doprnt" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1800 "configure"
|
||||
#line 1807 "configure"
|
||||
#include "confdefs.h"
|
||||
/* System header to define __stub macros and hopefully few prototypes,
|
||||
which can conflict with char _doprnt(); below. */
|
||||
@@ -1819,7 +1826,7 @@ _doprnt();
|
||||
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1823: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:1830: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
rm -rf conftest*
|
||||
eval "ac_cv_func__doprnt=yes"
|
||||
else
|
||||
@@ -1846,12 +1853,12 @@ fi
|
||||
for ac_func in mkdir rmdir uname
|
||||
do
|
||||
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
|
||||
echo "configure:1850: checking for $ac_func" >&5
|
||||
echo "configure:1857: checking for $ac_func" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1855 "configure"
|
||||
#line 1862 "configure"
|
||||
#include "confdefs.h"
|
||||
/* System header to define __stub macros and hopefully few prototypes,
|
||||
which can conflict with char $ac_func(); below. */
|
||||
@@ -1874,7 +1881,7 @@ $ac_func();
|
||||
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1878: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:1885: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
rm -rf conftest*
|
||||
eval "ac_cv_func_$ac_func=yes"
|
||||
else
|
||||
@@ -1902,14 +1909,14 @@ done
|
||||
if test x$READLINE = xyes; then
|
||||
|
||||
echo $ac_n "checking for library containing tgetent""... $ac_c" 1>&6
|
||||
echo "configure:1906: checking for library containing tgetent" >&5
|
||||
echo "configure:1913: checking for library containing tgetent" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_search_tgetent'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
ac_func_search_save_LIBS="$LIBS"
|
||||
ac_cv_search_tgetent="no"
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1913 "configure"
|
||||
#line 1920 "configure"
|
||||
#include "confdefs.h"
|
||||
/* Override any gcc2 internal prototype to avoid an error. */
|
||||
/* We use char because int might match the return type of a gcc2
|
||||
@@ -1920,7 +1927,7 @@ int main() {
|
||||
tgetent()
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1924: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:1931: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
rm -rf conftest*
|
||||
ac_cv_search_tgetent="none required"
|
||||
else
|
||||
@@ -1931,7 +1938,7 @@ rm -f conftest*
|
||||
test "$ac_cv_search_tgetent" = "no" && for i in ncurses curses termcap termlib; do
|
||||
LIBS="-l$i $ac_func_search_save_LIBS"
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1935 "configure"
|
||||
#line 1942 "configure"
|
||||
#include "confdefs.h"
|
||||
/* Override any gcc2 internal prototype to avoid an error. */
|
||||
/* We use char because int might match the return type of a gcc2
|
||||
@@ -1942,7 +1949,7 @@ int main() {
|
||||
tgetent()
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1946: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:1953: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
rm -rf conftest*
|
||||
ac_cv_search_tgetent="-l$i"
|
||||
break
|
||||
@@ -1976,7 +1983,7 @@ fi
|
||||
|
||||
if test x$READLINE = xyes; then
|
||||
echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6
|
||||
echo "configure:1980: checking for readline in -lreadline" >&5
|
||||
echo "configure:1987: checking for readline in -lreadline" >&5
|
||||
ac_lib_var=`echo readline'_'readline | sed 'y%./+-%__p_%'`
|
||||
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
@@ -1984,7 +1991,7 @@ else
|
||||
ac_save_LIBS="$LIBS"
|
||||
LIBS="-lreadline $LIBS"
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 1988 "configure"
|
||||
#line 1995 "configure"
|
||||
#include "confdefs.h"
|
||||
/* Override any gcc2 internal prototype to avoid an error. */
|
||||
/* We use char because int might match the return type of a gcc2
|
||||
@@ -1995,7 +2002,7 @@ int main() {
|
||||
readline()
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:1999: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
if { (eval echo configure:2006: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
rm -rf conftest*
|
||||
eval "ac_cv_lib_$ac_lib_var=yes"
|
||||
else
|
||||
@@ -2031,7 +2038,65 @@ package as well (which may be called readline-devel or something similar).
|
||||
|
||||
fi
|
||||
|
||||
echo $ac_n "checking for rl_completion_matches""... $ac_c" 1>&6
|
||||
echo "configure:2043: checking for rl_completion_matches" >&5
|
||||
if eval "test \"`echo '$''{'ac_cv_func_rl_completion_matches'+set}'`\" = set"; then
|
||||
echo $ac_n "(cached) $ac_c" 1>&6
|
||||
else
|
||||
cat > conftest.$ac_ext <<EOF
|
||||
#line 2048 "configure"
|
||||
#include "confdefs.h"
|
||||
/* System header to define __stub macros and hopefully few prototypes,
|
||||
which can conflict with char rl_completion_matches(); below. */
|
||||
#include <assert.h>
|
||||
/* Override any gcc2 internal prototype to avoid an error. */
|
||||
/* We use char because int might match the return type of a gcc2
|
||||
builtin and then its argument prototype would still apply. */
|
||||
char rl_completion_matches();
|
||||
|
||||
int main() {
|
||||
|
||||
/* The GNU C library defines this for functions which it implements
|
||||
to always fail with ENOSYS. Some functions are actually named
|
||||
something starting with __ and the normal name is an alias. */
|
||||
#if defined (__stub_rl_completion_matches) || defined (__stub___rl_completion_matches)
|
||||
choke me
|
||||
#else
|
||||
rl_completion_matches();
|
||||
#endif
|
||||
|
||||
; return 0; }
|
||||
EOF
|
||||
if { (eval echo configure:2071: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
|
||||
rm -rf conftest*
|
||||
eval "ac_cv_func_rl_completion_matches=yes"
|
||||
else
|
||||
echo "configure: failed program was:" >&5
|
||||
cat conftest.$ac_ext >&5
|
||||
rm -rf conftest*
|
||||
eval "ac_cv_func_rl_completion_matches=no"
|
||||
fi
|
||||
rm -f conftest*
|
||||
fi
|
||||
|
||||
if eval "test \"`echo '$ac_cv_func_'rl_completion_matches`\" = yes"; then
|
||||
echo "$ac_t""yes" 1>&6
|
||||
HAVE_RL_COMPLETION_MATCHES=yes
|
||||
else
|
||||
echo "$ac_t""no" 1>&6
|
||||
HAVE_RL_COMPLETION_MATCHES=no
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if test "-f VERSION"; then
|
||||
LVM_VERSION="\"`cat VERSION`\""
|
||||
else
|
||||
LVM_VERSION="Unknown"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2157,8 +2222,10 @@ Makefile \
|
||||
make.tmpl \
|
||||
include/Makefile \
|
||||
lib/Makefile \
|
||||
lib/format1/Makefile \
|
||||
man/Makefile \
|
||||
tools/Makefile \
|
||||
tools/version.h \
|
||||
test/mm/Makefile \
|
||||
test/device/Makefile \
|
||||
test/format1/Makefile \
|
||||
@@ -2208,9 +2275,11 @@ s%@CPP@%$CPP%g
|
||||
s%@JOBS@%$JOBS%g
|
||||
s%@STATIC_LINK@%$STATIC_LINK%g
|
||||
s%@READLINE@%$READLINE%g
|
||||
s%@kernel_dir@%$kernel_dir%g
|
||||
s%@LVM1@%$LVM1%g
|
||||
s%@HAVE_RL_COMPLETION_MATCHES@%$HAVE_RL_COMPLETION_MATCHES%g
|
||||
s%@OWNER@%$OWNER%g
|
||||
s%@GROUP@%$GROUP%g
|
||||
s%@LVM_VERSION@%$LVM_VERSION%g
|
||||
|
||||
CEOF
|
||||
EOF
|
||||
@@ -2257,8 +2326,10 @@ Makefile \
|
||||
make.tmpl \
|
||||
include/Makefile \
|
||||
lib/Makefile \
|
||||
lib/format1/Makefile \
|
||||
man/Makefile \
|
||||
tools/Makefile \
|
||||
tools/version.h \
|
||||
test/mm/Makefile \
|
||||
test/device/Makefile \
|
||||
test/format1/Makefile \
|
||||
|
38
configure.in
38
configure.in
@@ -61,11 +61,19 @@ AC_ARG_WITH(group,
|
||||
[ GROUP="$withval" ],
|
||||
[ GROUP="root" ])
|
||||
|
||||
dnl -- Where the linux src tree is
|
||||
AC_ARG_WITH(kernel_dir,
|
||||
[ --with-kernel_dir=DIR linux kernel source in DIR [/usr/src/linux]],
|
||||
[ kernel_dir="$withval" ],
|
||||
[ kernel_dir=/usr/src/linux ])
|
||||
dnl -- format1 inclusion type
|
||||
AC_ARG_WITH(lvm1,
|
||||
[ --with-lvm1=TYPE LVM1 metadata support: internal/shared/none
|
||||
[TYPE=internal] ],
|
||||
[ LVM1="$withval" ],
|
||||
[ LVM1="internal" ])
|
||||
|
||||
if [[ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]];
|
||||
then AC_MSG_ERROR(
|
||||
--with-lvm1 parameter invalid
|
||||
)
|
||||
exit
|
||||
fi;
|
||||
|
||||
AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=)
|
||||
|
||||
@@ -73,9 +81,9 @@ dnl Enables staticly linked tools
|
||||
AC_ARG_ENABLE(static_link, [ --enable-static_link Use this to link the tools to the liblvm library
|
||||
statically. Default is dynamic linking], STATIC_LINK=$enableval, STATIC_LINK=no)
|
||||
|
||||
dnl Disable readline
|
||||
AC_ARG_ENABLE(readline, [ --disable-readline Disable readline support], \
|
||||
READLINE=$enableval, READLINE=yes)
|
||||
dnl Enable readline
|
||||
AC_ARG_ENABLE(readline, [ --enable-readline Enable readline support], \
|
||||
READLINE=$enableval, READLINE=no)
|
||||
|
||||
dnl Mess with default exec_prefix
|
||||
if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
|
||||
@@ -118,15 +126,25 @@ 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)
|
||||
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(kernel_dir)
|
||||
AC_SUBST(LVM1)
|
||||
AC_SUBST(HAVE_RL_COMPLETION_MATCHES)
|
||||
AC_SUBST(OWNER)
|
||||
AC_SUBST(GROUP)
|
||||
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_OUTPUT( \
|
||||
@@ -134,8 +152,10 @@ Makefile \
|
||||
make.tmpl \
|
||||
include/Makefile \
|
||||
lib/Makefile \
|
||||
lib/format1/Makefile \
|
||||
man/Makefile \
|
||||
tools/Makefile \
|
||||
tools/version.h \
|
||||
test/mm/Makefile \
|
||||
test/device/Makefile \
|
||||
test/format1/Makefile \
|
||||
|
59
debian/changelog
vendored
Normal file
59
debian/changelog
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
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.
|
||||
* Convert from debian native package.
|
||||
|
||||
-- Andres Salomon <dilinger@mp3revolution.net> Wed, 6 Mar 2002 00:43:21 -0500
|
||||
|
||||
lvm2 (0.95.04cvs20020304) unstable; urgency=low
|
||||
|
||||
* CVS updated.
|
||||
* Enhance init script; create devmapper control device, etc.
|
||||
* Add dmsetup as a suggestion.
|
||||
* Add /etc/lvm/lvm.conf conffile.
|
||||
* Add undocumented(7) for the commands missing manpages.
|
||||
|
||||
-- Andres Salomon <dilinger@mp3revolution.net> Mon, 4 Mar 2002 04:51:26 -0500
|
||||
|
||||
lvm2 (0.95.02cvs20020220) unstable; urgency=low
|
||||
|
||||
* Initial Release.
|
||||
|
||||
-- Andres Salomon <dilinger@mp3revolution.net> Wed, 20 Feb 2002 03:17:25 -0500
|
||||
|
2
debian/conffiles
vendored
Normal file
2
debian/conffiles
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/etc/lvm/lvm.conf
|
||||
/etc/init.d/lvm2
|
20
debian/control
vendored
Normal file
20
debian/control
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
Source: lvm2
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Maintainer: Andres Salomon <dilinger@mp3revolution.net>
|
||||
Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev (>= 0.96.04), libreadline4-dev
|
||||
Standards-Version: 3.5.2
|
||||
|
||||
Package: lvm2
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}
|
||||
Conflicts: lvm10, lvm-common
|
||||
Replaces: lvm10, lvm-common
|
||||
Provides: lvm-binaries
|
||||
Suggests: dmsetup
|
||||
Description: The Linux Logical Volume Manager
|
||||
This is LVM2, the rewrite of The Linux Logical Volume Manager. LVM
|
||||
supports enterprise level volume management of disk and disk subsystems
|
||||
by grouping arbitrary disks into volume groups. The total capacity of
|
||||
volume groups can be allocated to logical volumes, which are accessed as
|
||||
regular block devices.
|
25
debian/copyright
vendored
Normal file
25
debian/copyright
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
This package was debianized by Andres Salomon <dilinger@mp3revolution.net> on
|
||||
Wed, 20 Feb 2002 03:17:25 -0500.
|
||||
|
||||
It was downloaded from http://www.sistina.com/products_lvm.htm
|
||||
|
||||
Upstream Author(s): LVM Development Team
|
||||
|
||||
Copyright (c) 2001-2002 LVM Development Team
|
||||
|
||||
LVM2 is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
LVM2 is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
|
||||
On Debian systems, the full text of the GPL can be found in
|
||||
/usr/share/common-licenses/GPL
|
4
debian/dirs
vendored
Normal file
4
debian/dirs
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
etc/lvm
|
||||
usr/share/man/man5
|
||||
usr/share/man/man8
|
||||
sbin
|
6
debian/docs
vendored
Normal file
6
debian/docs
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
BUGS
|
||||
INTRO
|
||||
README
|
||||
TODO
|
||||
VERSION
|
||||
doc/*
|
64
debian/init.d
vendored
Normal file
64
debian/init.d
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# lvm2 This script handles LVM2 initialization/shutdown.
|
||||
#
|
||||
# Written by Andres Salomon <dilinger@mp3revolution.net>.
|
||||
#
|
||||
|
||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin
|
||||
NAME=lvm2
|
||||
DESC=LVM
|
||||
|
||||
test -x /sbin/vgchange || exit 0
|
||||
modprobe dm-mod >/dev/null 2>&1
|
||||
|
||||
# Create necessary files in /dev for device-mapper
|
||||
create_devfiles() {
|
||||
DIR="/dev/mapper"
|
||||
FILE="$DIR/control"
|
||||
major=$(grep "[0-9] misc$" /proc/devices | sed 's/[ ]\+misc//')
|
||||
minor=$(grep "[0-9] device-mapper$" /proc/misc | sed 's/[ ]\+device-mapper//')
|
||||
|
||||
if test ! -d $DIR; then
|
||||
mkdir --mode=755 $DIR >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
if test ! -c $FILE -a ! -z "$minor"; then
|
||||
mknod --mode=600 $FILE c $major $minor >/dev/null 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n "Initializing $DESC: "
|
||||
create_devfiles
|
||||
vgchange -a y
|
||||
|
||||
# # Mount all LVM devices
|
||||
# for vg in $( vgchange -a y 2>/dev/null | grep active | awk -F\" '{print $2}' ); do
|
||||
# MTPT=$( grep $vg /etc/fstab | awk '{print $2}' )
|
||||
# mount $MTPT
|
||||
# done
|
||||
echo "$NAME."
|
||||
;;
|
||||
stop)
|
||||
echo -n "Shutting down $DESC: "
|
||||
# We don't really try all that hard to shut it down; far too many
|
||||
# things that can keep it from successfully shutting down.
|
||||
vgchange -a n
|
||||
echo "$NAME."
|
||||
;;
|
||||
restart|force-reload)
|
||||
echo -n "Restarting $DESC: "
|
||||
vgchange -a n
|
||||
sleep 1
|
||||
vgchange -a y
|
||||
echo "$NAME."
|
||||
;;
|
||||
*)
|
||||
echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
26
debian/manpages
vendored
Normal file
26
debian/manpages
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
debian/lvm2/usr/share/man/man5/lvm.conf.5
|
||||
debian/lvm2/usr/share/man/man8/lvchange.8
|
||||
debian/lvm2/usr/share/man/man8/lvcreate.8
|
||||
debian/lvm2/usr/share/man/man8/lvdisplay.8
|
||||
debian/lvm2/usr/share/man/man8/lvextend.8
|
||||
debian/lvm2/usr/share/man/man8/lvm.8
|
||||
debian/lvm2/usr/share/man/man8/lvmchange.8
|
||||
debian/lvm2/usr/share/man/man8/lvreduce.8
|
||||
debian/lvm2/usr/share/man/man8/lvremove.8
|
||||
debian/lvm2/usr/share/man/man8/lvrename.8
|
||||
debian/lvm2/usr/share/man/man8/lvscan.8
|
||||
debian/lvm2/usr/share/man/man8/pvchange.8
|
||||
debian/lvm2/usr/share/man/man8/pvcreate.8
|
||||
debian/lvm2/usr/share/man/man8/pvdisplay.8
|
||||
debian/lvm2/usr/share/man/man8/pvscan.8
|
||||
debian/lvm2/usr/share/man/man8/vgcfgbackup.8
|
||||
debian/lvm2/usr/share/man/man8/vgchange.8
|
||||
debian/lvm2/usr/share/man/man8/vgck.8
|
||||
debian/lvm2/usr/share/man/man8/vgcreate.8
|
||||
debian/lvm2/usr/share/man/man8/vgdisplay.8
|
||||
debian/lvm2/usr/share/man/man8/vgextend.8
|
||||
debian/lvm2/usr/share/man/man8/vgmerge.8
|
||||
debian/lvm2/usr/share/man/man8/vgreduce.8
|
||||
debian/lvm2/usr/share/man/man8/vgremove.8
|
||||
debian/lvm2/usr/share/man/man8/vgrename.8
|
||||
debian/lvm2/usr/share/man/man8/vgscan.8
|
120
debian/rules
vendored
Executable file
120
debian/rules
vendored
Executable file
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/make -f
|
||||
# Sample debian/rules that uses debhelper.
|
||||
# GNU copyright 1997 by Joey Hess.
|
||||
#
|
||||
# This version is for a hypothetical package that builds an
|
||||
# architecture-dependant package, as well as an architecture-independent
|
||||
# package.
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
# This is the debhelper compatibility version to use.
|
||||
export DH_COMPAT=3
|
||||
|
||||
# These are used for cross-compiling and for saving the configure script
|
||||
# from having to guess our platform (since we know it already)
|
||||
DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
|
||||
DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
|
||||
|
||||
ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
|
||||
CFLAGS += -g
|
||||
endif
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
INSTALL_PROGRAM += -s
|
||||
endif
|
||||
|
||||
configure: configure-stamp
|
||||
configure-stamp:
|
||||
dh_testdir
|
||||
# Add here commands to configure the package.
|
||||
./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/ --mandir=\$${prefix}/usr/share/man --infodir=\$${prefix}/usr/share/info
|
||||
|
||||
touch configure-stamp
|
||||
|
||||
build-arch: configure-stamp build-arch-stamp
|
||||
build-arch-stamp:
|
||||
dh_testdir
|
||||
|
||||
# Add here command to compile/build the package.
|
||||
$(MAKE)
|
||||
|
||||
touch build-arch-stamp
|
||||
|
||||
build-indep: configure-stamp build-indep-stamp
|
||||
build-indep-stamp:
|
||||
dh_testdir
|
||||
|
||||
# Add here command to compile/build the arch indep package.
|
||||
# It's ok not to do anything here, if you don't need to build
|
||||
# anything for this package.
|
||||
#/usr/bin/docbook-to-man debian/lvm2.sgml > lvm2.1
|
||||
|
||||
touch build-indep-stamp
|
||||
|
||||
build: build-arch build-indep
|
||||
|
||||
clean:
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
rm -f build-stamp configure-stamp
|
||||
|
||||
# Add here commands to clean up after the build process.
|
||||
-$(MAKE) distclean
|
||||
-test -r /usr/share/misc/config.sub && \
|
||||
cp -f /usr/share/misc/config.sub config.sub
|
||||
-test -r /usr/share/misc/config.guess && \
|
||||
cp -f /usr/share/misc/config.guess config.guess
|
||||
|
||||
|
||||
dh_clean
|
||||
|
||||
install: DH_OPTIONS=
|
||||
install: build
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_clean -k
|
||||
dh_installdirs
|
||||
|
||||
# Add here commands to install the package into debian/lvm2.
|
||||
$(MAKE) install prefix=$(CURDIR)/debian/lvm2
|
||||
install -m 0644 doc/example.conf debian/lvm2/etc/lvm/lvm.conf
|
||||
|
||||
|
||||
# Build architecture-independent files here.
|
||||
# Pass -i to all debhelper commands in this target to reduce clutter.
|
||||
binary-indep: build install
|
||||
# nada.
|
||||
|
||||
# Build architecture-dependent files here.
|
||||
binary-arch: build install
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
|
||||
# dh_installdebconf
|
||||
dh_installdocs
|
||||
dh_installexamples
|
||||
# dh_installlogrotate -a
|
||||
# dh_installemacsen -a
|
||||
# dh_installpam -a
|
||||
# dh_installmime -a
|
||||
dh_installinit --update-rcd-params="start 26 S . start 50 0 6 ."
|
||||
dh_installcron
|
||||
dh_installman
|
||||
dh_installinfo
|
||||
dh_undocumented
|
||||
dh_installchangelogs
|
||||
dh_strip
|
||||
dh_link
|
||||
dh_compress
|
||||
dh_fixperms
|
||||
dh_makeshlibs
|
||||
dh_installdeb
|
||||
# dh_perl -a
|
||||
dh_shlibdeps
|
||||
dh_gencontrol
|
||||
dh_md5sums
|
||||
dh_builddeb
|
||||
|
||||
binary: binary-indep binary-arch
|
||||
.PHONY: build clean binary-indep binary-arch binary install configure
|
14
debian/undocumented
vendored
Normal file
14
debian/undocumented
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
e2fsadm.8
|
||||
lvmdiskscan.8
|
||||
lvmsadc.8
|
||||
lvmsar.8
|
||||
lvresize.8
|
||||
pvdata.8
|
||||
pvmove.8
|
||||
pvresize.8
|
||||
version.8
|
||||
vgcfgrestore.8
|
||||
vgexport.8
|
||||
vgimport.8
|
||||
vgmknodes.8
|
||||
vgsplit.8
|
@@ -1 +0,0 @@
|
||||
Wow! This is really incredible documentation!
|
220
doc/example.conf
Normal file
220
doc/example.conf
Normal file
@@ -0,0 +1,220 @@
|
||||
# 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 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 you to configure which block devices should
|
||||
# be used by the LVM system.
|
||||
devices {
|
||||
|
||||
# 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 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).
|
||||
|
||||
# Remember to run vgscan after you change this parameter.
|
||||
|
||||
# By default we accept every block device:
|
||||
filter = [ "a/.*/" ]
|
||||
|
||||
# Exclude the cdrom drive
|
||||
# filter = [ "r|/dev/cdrom|" ]
|
||||
|
||||
# When testing I like to work with just loopback devices:
|
||||
# filter = [ "a/loop/", "r/.*/" ]
|
||||
|
||||
# Or maybe all loops and ide drives except hdc:
|
||||
# filter =[ "a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|" ]
|
||||
|
||||
# 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 safe to delete this file. vgscan regenerates it.
|
||||
cache = "/etc/lvm/.cache"
|
||||
|
||||
# You can turn off writing this cache file by setting this to 0.
|
||||
write_cache_state = 1
|
||||
}
|
||||
|
||||
# This section that allows you to configure the nature of the
|
||||
# information that LVM2 reports.
|
||||
log {
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
# Whether or not (1 or 0) to display the command name on each line output
|
||||
command_names = 0
|
||||
|
||||
# A prefix to use before the message text (but after the command name,
|
||||
# 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 tools use:
|
||||
# indent = 0
|
||||
# command_names = 1
|
||||
# prefix = " -- "
|
||||
}
|
||||
|
||||
# Configuration of metadata backups and archiving. In LVM2 when we
|
||||
# talk about a 'backup' we mean making a copy of the metadata for the
|
||||
# *current* system. The 'archive' contains old metadata configurations.
|
||||
# Backups are stored in a human readeable text format.
|
||||
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!
|
||||
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 ?
|
||||
retain_min = 10
|
||||
|
||||
# What is the minimum time you wish to keep an archive file for ?
|
||||
retain_days = 30
|
||||
}
|
||||
|
||||
# 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 LVM2 settings
|
||||
global {
|
||||
|
||||
# The file creation mask for any files and directories created.
|
||||
# Interpreted as octal if the first digit is zero.
|
||||
umask = 077
|
||||
|
||||
# Allow other users to read the files
|
||||
#umask = 022
|
||||
|
||||
# Enabling test mode means that no changes to the on disk metadata
|
||||
# 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
|
||||
|
||||
# The default metadata format that commands should use - "lvm1" or "lvm2".
|
||||
# The command line override is -M1 or -M2.
|
||||
# Defaults to "lvm1" if compiled in, else "lvm2".
|
||||
# format = "lvm1"
|
||||
|
||||
# Location of proc filesystem
|
||||
proc = "/proc"
|
||||
|
||||
# Type of locking to use. Defaults to file-based locking (1).
|
||||
# Turn locking off by setting to 0 (dangerous: risks metadata corruption
|
||||
# if LVM2 commands get run concurrently).
|
||||
locking_type = 1
|
||||
|
||||
# Local non-LV directory that holds file-based locks while commands are
|
||||
# in progress. A directory like /tmp that may get wiped on reboot is OK.
|
||||
locking_dir = "/var/lock/lvm"
|
||||
|
||||
# Other entries can go here to allow you to load shared libraries
|
||||
# e.g. if support for LVM1 metadata was compiled as a shared library use
|
||||
# format_libraries = "liblvm2format1.so"
|
||||
# Full pathnames can be given.
|
||||
|
||||
# Search this directory first for shared libraries.
|
||||
# library_dir = "/lib"
|
||||
}
|
||||
|
||||
|
||||
####################
|
||||
# Advanced section #
|
||||
####################
|
||||
|
||||
# Metadata settings
|
||||
#
|
||||
# metadata {
|
||||
# Default number of copies of metadata to hold on each PV. 0, 1 or 2.
|
||||
# It's best to leave this at 2.
|
||||
# You might want to override it from the command line with 0 or 1
|
||||
# when running pvcreate on new PVs which are to be added to large VGs.
|
||||
|
||||
# pvmetadatacopies = 2
|
||||
|
||||
# Approximate default size of on-disk metadata areas in sectors.
|
||||
# You should increase this if you have large volume groups or
|
||||
# you want to retain a large on-disk history of your metadata changes.
|
||||
|
||||
# pvmetadatasize = 255
|
||||
|
||||
# List of directories holding live copies of text format metadata.
|
||||
# These directories must not be on logical volumes!
|
||||
# It's possible to use LVM2 with a couple of directories here,
|
||||
# preferably on different (non-LV) filesystems, and with no other
|
||||
# on-disk metadata (pvmetadatacopies = 0). Or this can be in
|
||||
# addition to on-disk metadata areas.
|
||||
# The feature was originally added to simplify testing.
|
||||
#
|
||||
# Never edit any files in these directories by hand unless you
|
||||
# you are absolutely sure you know what you are doing! Use
|
||||
# the supplied toolset to make changes (e.g. vgcfgrestore).
|
||||
|
||||
# dirs = [ "/etc/lvm/metadata", "/mnt/disk2/lvm/metadata2" ]
|
||||
#}
|
||||
|
||||
|
52
doc/pvmove_outline.txt
Normal file
52
doc/pvmove_outline.txt
Normal file
@@ -0,0 +1,52 @@
|
||||
Let's say we have an LV, made up of three segments of different PV's,
|
||||
I've also added in the device major:minor as this will be useful
|
||||
later:
|
||||
|
||||
+-----------------------------+
|
||||
| PV1 | PV2 | PV3 | 254:3
|
||||
+----------+---------+--------+
|
||||
|
||||
|
||||
Now our hero decides to PV move PV2 to PV4:
|
||||
|
||||
1. Suspend our LV (254:3), this starts queueing all io, and flushes
|
||||
all pending io. Once the suspend has completed we are free to change
|
||||
the mapping table.
|
||||
|
||||
2. Set up *another* (254:4) device with the mapping table of our LV.
|
||||
|
||||
3. Load a new mapping table into (254:3) that has identity targets for
|
||||
parts that aren't moving, and a mirror target for parts that are.
|
||||
|
||||
4. Unsuspend (254:3)
|
||||
|
||||
So now we have:
|
||||
destination of copy
|
||||
+--------------------->--------------+
|
||||
| |
|
||||
+-----------------------------+ + -----------+
|
||||
| Identity | mirror | Ident. | 254:3 | PV4 |
|
||||
+----------+---------+--------+ +------------+
|
||||
| | |
|
||||
\/ \/ \/
|
||||
+-----------------------------+
|
||||
| PV1 | PV2 | PV3 | 254:4
|
||||
+----------+---------+--------+
|
||||
|
||||
Any writes to segment2 of the LV get intercepted by the mirror target
|
||||
who checks that that chunk has been copied to the new destination, if
|
||||
it hasn't it queues the initial copy and defers the current io until
|
||||
it has finished. Then the current io is written to *both* PV2 and the
|
||||
PV4.
|
||||
|
||||
5. When the copying has completed 254:3 is suspended/pending flushed.
|
||||
|
||||
6. 254:4 is taken down
|
||||
|
||||
7. metadata is updated on disk
|
||||
|
||||
8. 254:3 has new mapping table loaded:
|
||||
|
||||
+-----------------------------+
|
||||
| PV1 | PV4 | PV3 | 254:3
|
||||
+----------+---------+--------+
|
46
doc/testing.txt
Normal file
46
doc/testing.txt
Normal file
@@ -0,0 +1,46 @@
|
||||
Here's how I test new LVM2 builds without interfering with the stable
|
||||
LVM2 that is running the LV's on my development box.
|
||||
|
||||
1) Create a set of loopback devices.
|
||||
|
||||
2) Create a new directory to contain the LVM2 configuration files for
|
||||
this setup. (I use /etc/lvm_loops)
|
||||
|
||||
3) Write a suitable lvm.conf file, this goes in the directory you just
|
||||
created. eg, my /etc/lvm_loops/lvm.conf looks like:
|
||||
|
||||
log {
|
||||
file="/tmp/lvm2_loop.log"
|
||||
level=9
|
||||
verbose=0
|
||||
overwrite=1
|
||||
}
|
||||
|
||||
devices {
|
||||
scan = "/dev"
|
||||
filter = ["a/loop/", "r/.*/"]
|
||||
}
|
||||
|
||||
|
||||
The important this to note is the devices section which makes sure that
|
||||
only the loopback devices are considered for LVM2 operations.
|
||||
|
||||
4) When you want to use this test setup just set the environment
|
||||
variable LVM_SYSTEM_DIR to point to your config directory
|
||||
(/etc/lvm_loops in my case).
|
||||
|
||||
5) It's a good idea to do a vgscan to initialise the filters:
|
||||
|
||||
export LVM_SYSTEM_DIR=/etc/lvm_loops
|
||||
./lvm vgscan
|
||||
|
||||
where ./lvm is the new build of LVM2 that I'm trying out.
|
||||
|
||||
7) Test away. Make sure that you are explicit about which lvm
|
||||
executable you want to execute (eg, ./lvm if you are in
|
||||
LVM2/tools).
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -1 +0,0 @@
|
||||
The driver directory
|
@@ -1,104 +0,0 @@
|
||||
The main goal of this driver is to support volume management in
|
||||
general, not just for LVM. The kernel should provide general
|
||||
services, not support specific applications. eg, The driver has no
|
||||
concept of volume groups.
|
||||
|
||||
The driver does this by mapping sector ranges for the logical device
|
||||
onto 'targets'.
|
||||
|
||||
When the logical device is accessed, the make_request function looks
|
||||
up the correct target for the given sector, and then asks this target
|
||||
to do the remapping.
|
||||
|
||||
A btree structure is used to hold the sector range -> target mapping.
|
||||
Since we know all the entries in the btree in advance we can make a
|
||||
very compact tree, omitting pointers to child nodes, (child nodes
|
||||
locations can be calculated). Typical users would find they only have
|
||||
a handful of targets for each logical volume LV.
|
||||
|
||||
Benchmarking with bonnie++ suggests that this is certainly no slower
|
||||
than current LVM.
|
||||
|
||||
|
||||
Target types are not hard coded, instead the register_mapping_type
|
||||
function should be called. A target type is specified using three
|
||||
functions (see the header):
|
||||
|
||||
dm_ctr_fn - takes a string and contructs a target specific piece of
|
||||
context data.
|
||||
dm_dtr_fn - destroy contexts.
|
||||
dm_map_fn - function that takes a buffer_head and some previously
|
||||
constructed context and performs the remapping.
|
||||
|
||||
Currently there are two two trivial mappers, which are automatically
|
||||
registered: 'linear', and 'io_error'. Linear alone is enough to
|
||||
implement most of LVM.
|
||||
|
||||
|
||||
I do not like ioctl interfaces so this driver is currently controlled
|
||||
through a /proc interface. /proc/device-mapper/control allows you to
|
||||
create and remove devices by 'cat'ing a line of the following format:
|
||||
|
||||
create <device name> [minor no]
|
||||
remove <device name>
|
||||
|
||||
If you're not using devfs you'll have to do the mknod'ing yourself,
|
||||
otherwise the device will appear in /dev/device-mapper automatically.
|
||||
|
||||
/proc/device-mapper/<device name> accepts the mapping table:
|
||||
|
||||
begin
|
||||
<sector start> <length> <target name> <target args>...
|
||||
...
|
||||
end
|
||||
|
||||
where <target args> are specific to the target type, eg. for a linear
|
||||
mapping:
|
||||
|
||||
<sector start> <length> linear <major> <minor> <start>
|
||||
|
||||
and the io-err mapping:
|
||||
|
||||
<sector start> <length> io-err
|
||||
|
||||
The begin/end lines around the table are nasty, they should be handled
|
||||
by open/close of the file.
|
||||
|
||||
The interface is far from complete, currently loading a table either
|
||||
succeeds or fails, you have no way of knowing which line of the
|
||||
mapping table was erroneous. Also there is no way to get status
|
||||
information out, though this should be easy to add, either as another
|
||||
/proc file, or just by reading the same /proc/device-mapper/<device>
|
||||
file. I will be seperating the loading and validation of a table from
|
||||
the binding of a valid table to a device.
|
||||
|
||||
It has been suggested that I should implement a little custom
|
||||
filesystem rather than labouring with /proc. For example doing a
|
||||
mkdir foo in /wherever/device-mapper would create a new device. People
|
||||
waiting for a status change (eg, a mirror operation to complete) could
|
||||
poll a file. Does the community find this an acceptable way to go ?
|
||||
|
||||
|
||||
At the moment the table assumes 32 bit keys (sectors), the move to 64
|
||||
bits will involve no interface changes, since the tables will be read
|
||||
in as ascii data. A different table implementation can therefor be
|
||||
provided at another time. Either just by changing offset_t to 64
|
||||
bits, or maybe implementing a structure which looks up the keys in
|
||||
stages (ie, 32 bits at a time).
|
||||
|
||||
|
||||
More interesting targets:
|
||||
|
||||
striped mapping; given a stripe size and a number of device regions
|
||||
this would stripe data across the regions. Especially useful, since
|
||||
we could limit each striped region to a 32 bit area and then avoid
|
||||
nasty 64 bit %'s.
|
||||
|
||||
mirror mapping; would set off a kernel thread slowly copying data from
|
||||
one region to another, ensuring that any new writes got copied to both
|
||||
destinations correctly. Enabling us to implement a live pvmove
|
||||
correctly.
|
||||
|
||||
|
||||
|
||||
|
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* device-mapper.h
|
||||
*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changelog
|
||||
*
|
||||
* 14/08/2001 - First version [Joe Thornber]
|
||||
*/
|
||||
|
||||
#ifndef DEVICE_MAPPER_H
|
||||
#define DEVICE_MAPPER_H
|
||||
|
||||
#include <linux/major.h>
|
||||
|
||||
/* FIXME: Use value from local range for now, for co-existence with LVM 1 */
|
||||
#define DM_BLK_MAJOR 124
|
||||
|
||||
struct dm_table;
|
||||
struct dm_dev;
|
||||
typedef unsigned int offset_t;
|
||||
|
||||
typedef void (*dm_error_fn)(const char *message, void *private);
|
||||
|
||||
/*
|
||||
* constructor, destructor and map fn types
|
||||
*/
|
||||
typedef int (*dm_ctr_fn)(struct dm_table *t, offset_t b, offset_t l,
|
||||
char *args, void **context);
|
||||
|
||||
typedef void (*dm_dtr_fn)(struct dm_table *t, void *c);
|
||||
typedef int (*dm_map_fn)(struct buffer_head *bh, int rw, void *context);
|
||||
typedef int (*dm_err_fn)(struct buffer_head *bh, int rw, void *context);
|
||||
typedef char *(*dm_print_fn)(void *context);
|
||||
|
||||
/*
|
||||
* Contructors should call this to make sure any
|
||||
* destination devices are handled correctly
|
||||
* (ie. opened/closed).
|
||||
*/
|
||||
int dm_table_get_device(struct dm_table *t, const char *path,
|
||||
struct dm_dev **result);
|
||||
void dm_table_put_device(struct dm_table *table, struct dm_dev *d);
|
||||
|
||||
/*
|
||||
* information about a target type
|
||||
*/
|
||||
struct target_type {
|
||||
const char *name;
|
||||
struct module *module;
|
||||
dm_ctr_fn ctr;
|
||||
dm_dtr_fn dtr;
|
||||
dm_map_fn map;
|
||||
dm_err_fn err;
|
||||
dm_print_fn print;
|
||||
};
|
||||
|
||||
int dm_register_target(struct target_type *t);
|
||||
int dm_unregister_target(struct target_type *t);
|
||||
|
||||
static inline char *next_token(char **p)
|
||||
{
|
||||
static const char *delim = " \t";
|
||||
char *r;
|
||||
|
||||
do {
|
||||
r = strsep(p, delim);
|
||||
} while(r && *r == 0);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
#endif /* DEVICE_MAPPER_H */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* dm-linear.c
|
||||
*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/device-mapper.h>
|
||||
|
||||
#include "dm.h"
|
||||
|
||||
/*
|
||||
* linear: maps a linear range of a device.
|
||||
*/
|
||||
struct linear_c {
|
||||
long delta; /* FIXME: we need a signed offset type */
|
||||
struct dm_dev *dev;
|
||||
};
|
||||
|
||||
/*
|
||||
* construct a linear mapping.
|
||||
* <dev_path> <offset>
|
||||
*/
|
||||
static int linear_ctr(struct dm_table *t, offset_t b, offset_t l,
|
||||
char *args, void **context)
|
||||
{
|
||||
struct linear_c *lc;
|
||||
unsigned int start;
|
||||
int r = -EINVAL;
|
||||
char *tok;
|
||||
char *path;
|
||||
char *p = args;
|
||||
|
||||
*context = "No device path given";
|
||||
path = next_token(&p);
|
||||
if (!path)
|
||||
goto bad;
|
||||
|
||||
*context = "No initial offset given";
|
||||
tok = next_token(&p);
|
||||
if (!tok)
|
||||
goto bad;
|
||||
start = simple_strtoul(tok, NULL, 10);
|
||||
|
||||
*context = "Cannot allocate linear context private structure";
|
||||
lc = kmalloc(sizeof(lc), GFP_KERNEL);
|
||||
if (lc == NULL)
|
||||
goto bad;
|
||||
|
||||
*context = "Cannot get target device";
|
||||
r = dm_table_get_device(t, path, &lc->dev);
|
||||
if (r)
|
||||
goto bad_free;
|
||||
|
||||
lc->delta = (int) start - (int) b;
|
||||
*context = lc;
|
||||
return 0;
|
||||
|
||||
bad_free:
|
||||
kfree(lc);
|
||||
bad:
|
||||
return r;
|
||||
}
|
||||
|
||||
static void linear_dtr(struct dm_table *t, void *c)
|
||||
{
|
||||
struct linear_c *lc = (struct linear_c *) c;
|
||||
dm_table_put_device(t, lc->dev);
|
||||
kfree(c);
|
||||
}
|
||||
|
||||
static int linear_map(struct buffer_head *bh, int rw, void *context)
|
||||
{
|
||||
struct linear_c *lc = (struct linear_c *) context;
|
||||
|
||||
bh->b_rdev = lc->dev->dev;
|
||||
bh->b_rsector = bh->b_rsector + lc->delta;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Debugging use only.
|
||||
*/
|
||||
static char *linear_print(void *context)
|
||||
{
|
||||
struct linear_c *lc = (struct linear_c *)context;
|
||||
static char buf[256];
|
||||
sprintf(buf, " %lu", lc->delta);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static struct target_type linear_target = {
|
||||
name: "linear",
|
||||
module: THIS_MODULE,
|
||||
ctr: linear_ctr,
|
||||
dtr: linear_dtr,
|
||||
map: linear_map,
|
||||
print: linear_print,
|
||||
};
|
||||
|
||||
static int __init linear_init(void)
|
||||
{
|
||||
int r = dm_register_target(&linear_target);
|
||||
|
||||
if (r < 0)
|
||||
printk(KERN_ERR
|
||||
"Device mapper: Linear: register failed %d\n", r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void __exit linear_exit(void)
|
||||
{
|
||||
int r = dm_unregister_target(&linear_target);
|
||||
|
||||
if (r < 0)
|
||||
printk(KERN_ERR
|
||||
"Device mapper: Linear: unregister failed %d\n", r);
|
||||
}
|
||||
|
||||
module_init(linear_init);
|
||||
module_exit(linear_exit);
|
||||
|
||||
MODULE_AUTHOR("Joe Thornber <thornber@uk.sistina.com>");
|
||||
MODULE_DESCRIPTION("Device Mapper: Linear mapping");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@@ -1,340 +0,0 @@
|
||||
/*
|
||||
* dm-table.c
|
||||
*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changelog
|
||||
*
|
||||
* 16/08/2001 - First version [Joe Thornber]
|
||||
*/
|
||||
|
||||
#include "dm.h"
|
||||
|
||||
/* ceiling(n / size) * size */
|
||||
static inline ulong round_up(ulong n, ulong size)
|
||||
{
|
||||
ulong r = n % size;
|
||||
return n + (r ? (size - r) : 0);
|
||||
}
|
||||
|
||||
/* ceiling(n / size) */
|
||||
static inline ulong div_up(ulong n, ulong size)
|
||||
{
|
||||
return round_up(n, size) / size;
|
||||
}
|
||||
|
||||
/* similar to ceiling(log_size(n)) */
|
||||
static uint int_log(ulong n, ulong base)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
while (n > 1) {
|
||||
n = div_up(n, base);
|
||||
result++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* return the highest key that you could lookup
|
||||
* from the n'th node on level l of the btree.
|
||||
*/
|
||||
static offset_t high(struct dm_table *t, int l, int n)
|
||||
{
|
||||
for (; l < t->depth - 1; l++)
|
||||
n = get_child(n, CHILDREN_PER_NODE - 1);
|
||||
|
||||
if (n >= t->counts[l])
|
||||
return (offset_t) -1;
|
||||
|
||||
return get_node(t, l, n)[KEYS_PER_NODE - 1];
|
||||
}
|
||||
|
||||
/*
|
||||
* fills in a level of the btree based on the
|
||||
* highs of the level below it.
|
||||
*/
|
||||
static int setup_btree_index(int l, struct dm_table *t)
|
||||
{
|
||||
int n, k;
|
||||
offset_t *node;
|
||||
|
||||
for (n = 0; n < t->counts[l]; n++) {
|
||||
node = get_node(t, l, n);
|
||||
|
||||
for (k = 0; k < KEYS_PER_NODE; k++)
|
||||
node[k] = high(t, l + 1, get_child(n, k));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* highs, and targets are managed as dynamic
|
||||
* arrays during a table load.
|
||||
*/
|
||||
static int alloc_targets(struct dm_table *t, int num)
|
||||
{
|
||||
offset_t *n_highs;
|
||||
struct target *n_targets;
|
||||
int n = t->num_targets;
|
||||
int size = (sizeof(struct target) + sizeof(offset_t)) * num;
|
||||
|
||||
n_highs = vmalloc(size);
|
||||
if (!n_highs)
|
||||
return -ENOMEM;
|
||||
|
||||
n_targets = (struct target *) (n_highs + num);
|
||||
|
||||
if (n) {
|
||||
memcpy(n_highs, t->highs, sizeof(*n_highs) * n);
|
||||
memcpy(n_targets, t->targets, sizeof(*n_targets) * n);
|
||||
}
|
||||
|
||||
vfree(t->highs);
|
||||
|
||||
t->num_allocated = num;
|
||||
t->highs = n_highs;
|
||||
t->targets = n_targets;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dm_table *dm_table_create(void)
|
||||
{
|
||||
struct dm_table *t = kmalloc(sizeof(struct dm_table), GFP_NOIO);
|
||||
|
||||
if (!t)
|
||||
return 0;
|
||||
|
||||
memset(t, 0, sizeof(*t));
|
||||
INIT_LIST_HEAD(&t->devices);
|
||||
|
||||
/* allocate a single nodes worth of targets to
|
||||
begin with */
|
||||
if (alloc_targets(t, KEYS_PER_NODE)) {
|
||||
kfree(t);
|
||||
t = 0;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static void free_devices(struct list_head *devices)
|
||||
{
|
||||
struct list_head *tmp, *next;
|
||||
|
||||
for (tmp = devices->next; tmp != devices; tmp = next) {
|
||||
struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
|
||||
next = tmp->next;
|
||||
kfree(dd);
|
||||
}
|
||||
}
|
||||
|
||||
void dm_table_destroy(struct dm_table *t)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* free the indexes (see dm_table_complete) */
|
||||
if (t->depth >= 2)
|
||||
vfree(t->index[t->depth - 2]);
|
||||
|
||||
|
||||
/* free the targets */
|
||||
for (i = 0; i < t->num_targets; i++) {
|
||||
struct target *tgt = &t->targets[i];
|
||||
if (tgt->type->dtr)
|
||||
tgt->type->dtr(t, tgt->private);
|
||||
}
|
||||
|
||||
vfree(t->highs);
|
||||
|
||||
/* free the device list */
|
||||
if (t->devices.next != &t->devices) {
|
||||
WARN("there are still devices present, someone isn't "
|
||||
"calling dm_table_remove_device");
|
||||
|
||||
free_devices(&t->devices);
|
||||
}
|
||||
|
||||
kfree(t);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks to see if we need to extend
|
||||
* highs or targets.
|
||||
*/
|
||||
static inline int check_space(struct dm_table *t)
|
||||
{
|
||||
if (t->num_targets >= t->num_allocated)
|
||||
return alloc_targets(t, t->num_allocated * 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* convert a device path to a kdev_t.
|
||||
*/
|
||||
int lookup_device(const char *path, kdev_t *dev)
|
||||
{
|
||||
int r;
|
||||
struct nameidata nd;
|
||||
struct inode *inode;
|
||||
|
||||
if (!path_init(path, LOOKUP_FOLLOW, &nd))
|
||||
return 0;
|
||||
|
||||
if ((r = path_walk(path, &nd)))
|
||||
goto bad;
|
||||
|
||||
inode = nd.dentry->d_inode;
|
||||
if (!inode) {
|
||||
r = -ENOENT;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!S_ISBLK(inode->i_mode)) {
|
||||
r = -EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
*dev = inode->i_rdev;
|
||||
|
||||
bad:
|
||||
path_release(&nd);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* see if we've already got a device in the list.
|
||||
*/
|
||||
static struct dm_dev *find_device(struct list_head *l, kdev_t dev)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
|
||||
for (tmp = l->next; tmp != l; tmp = tmp->next) {
|
||||
|
||||
struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
|
||||
if (dd->dev == dev)
|
||||
return dd;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* add a device to the list, or just increment the
|
||||
* usage count if it's already present.
|
||||
*/
|
||||
int dm_table_get_device(struct dm_table *t, const char *path,
|
||||
struct dm_dev **result)
|
||||
{
|
||||
int r;
|
||||
kdev_t dev;
|
||||
struct dm_dev *dd;
|
||||
|
||||
/* convert the path to a device */
|
||||
if ((r = lookup_device(path, &dev)))
|
||||
return r;
|
||||
|
||||
dd = find_device(&t->devices, dev);
|
||||
if (!dd) {
|
||||
dd = kmalloc(sizeof(*dd), GFP_KERNEL);
|
||||
if (!dd)
|
||||
return -ENOMEM;
|
||||
|
||||
dd->dev = dev;
|
||||
dd->bd = 0;
|
||||
atomic_set(&dd->count, 0);
|
||||
list_add(&dd->list, &t->devices);
|
||||
}
|
||||
atomic_inc(&dd->count);
|
||||
*result = dd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* decrement a devices use count and remove it if
|
||||
* neccessary.
|
||||
*/
|
||||
void dm_table_put_device(struct dm_table *t, struct dm_dev *dd)
|
||||
{
|
||||
if (atomic_dec_and_test(&dd->count)) {
|
||||
list_del(&dd->list);
|
||||
kfree(dd);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* adds a target to the map
|
||||
*/
|
||||
int dm_table_add_target(struct dm_table *t, offset_t high,
|
||||
struct target_type *type, void *private)
|
||||
{
|
||||
int r, n;
|
||||
|
||||
if ((r = check_space(t)))
|
||||
return r;
|
||||
|
||||
n = t->num_targets++;
|
||||
t->highs[n] = high;
|
||||
t->targets[n].type = type;
|
||||
t->targets[n].private = private;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int setup_indexes(struct dm_table *t)
|
||||
{
|
||||
int i, total = 0;
|
||||
offset_t *indexes;
|
||||
|
||||
/* allocate the space for *all* the indexes */
|
||||
for (i = t->depth - 2; i >= 0; i--) {
|
||||
t->counts[i] = div_up(t->counts[i + 1], CHILDREN_PER_NODE);
|
||||
total += t->counts[i];
|
||||
}
|
||||
|
||||
if (!(indexes = vmalloc(NODE_SIZE * total)))
|
||||
return -ENOMEM;
|
||||
|
||||
/* set up internal nodes, bottom-up */
|
||||
for (i = t->depth - 2, total = 0; i >= 0; i--) {
|
||||
t->index[i] = indexes + (KEYS_PER_NODE * t->counts[i]);
|
||||
setup_btree_index(i, t);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* builds the btree to index the map
|
||||
*/
|
||||
int dm_table_complete(struct dm_table *t)
|
||||
{
|
||||
int leaf_nodes, r = 0;
|
||||
|
||||
/* how many indexes will the btree have ? */
|
||||
leaf_nodes = div_up(t->num_targets, KEYS_PER_NODE);
|
||||
t->depth = 1 + int_log(leaf_nodes, CHILDREN_PER_NODE);
|
||||
|
||||
/* leaf layer has already been set up */
|
||||
t->counts[t->depth - 1] = leaf_nodes;
|
||||
t->index[t->depth - 1] = t->highs;
|
||||
|
||||
if (t->depth >= 2)
|
||||
r = setup_indexes(t);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(dm_table_get_device);
|
||||
EXPORT_SYMBOL(dm_table_put_device);
|
@@ -1,180 +0,0 @@
|
||||
/*
|
||||
* dm-target.c
|
||||
*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 16/08/2001 - First Version [Joe Thornber]
|
||||
*/
|
||||
|
||||
#include "dm.h"
|
||||
#include <linux/kmod.h>
|
||||
|
||||
struct tt_internal {
|
||||
struct target_type tt;
|
||||
|
||||
struct list_head list;
|
||||
long use;
|
||||
};
|
||||
|
||||
static LIST_HEAD(_targets);
|
||||
static rwlock_t _lock = RW_LOCK_UNLOCKED;
|
||||
|
||||
#define DM_MOD_NAME_SIZE 32
|
||||
|
||||
static inline struct tt_internal *__find_target_type(const char *name)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct tt_internal *ti;
|
||||
|
||||
for(tmp = _targets.next; tmp != &_targets; tmp = tmp->next) {
|
||||
|
||||
ti = list_entry(tmp, struct tt_internal, list);
|
||||
if (!strcmp(name, ti->tt.name))
|
||||
return ti;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct tt_internal *get_target_type(const char *name)
|
||||
{
|
||||
struct tt_internal *ti;
|
||||
|
||||
read_lock(&_lock);
|
||||
ti = __find_target_type(name);
|
||||
|
||||
if (ti) {
|
||||
if (ti->use == 0 && ti->tt.module)
|
||||
__MOD_INC_USE_COUNT(ti->tt.module);
|
||||
ti->use++;
|
||||
}
|
||||
read_unlock(&_lock);
|
||||
|
||||
return ti;
|
||||
}
|
||||
|
||||
static void load_module(const char *name)
|
||||
{
|
||||
char module_name[DM_MOD_NAME_SIZE] = "dm-";
|
||||
|
||||
/* Length check for strcat() below */
|
||||
if (strlen(name) > (DM_MOD_NAME_SIZE - 4))
|
||||
return;
|
||||
|
||||
strcat(module_name, name);
|
||||
request_module(module_name);
|
||||
}
|
||||
|
||||
struct target_type *dm_get_target_type(const char *name)
|
||||
{
|
||||
struct tt_internal *ti = get_target_type(name);
|
||||
|
||||
if (!ti) {
|
||||
load_module(name);
|
||||
ti = get_target_type(name);
|
||||
}
|
||||
|
||||
return ti ? &ti->tt : 0;
|
||||
}
|
||||
|
||||
void dm_put_target_type(struct target_type *t)
|
||||
{
|
||||
struct tt_internal *ti = (struct tt_internal *) t;
|
||||
|
||||
read_lock(&_lock);
|
||||
if (--ti->use == 0 && ti->tt.module)
|
||||
__MOD_DEC_USE_COUNT(ti->tt.module);
|
||||
|
||||
if (ti->use < 0)
|
||||
BUG();
|
||||
read_unlock(&_lock);
|
||||
}
|
||||
|
||||
static struct tt_internal *alloc_target(struct target_type *t)
|
||||
{
|
||||
struct tt_internal *ti = kmalloc(sizeof(*ti), GFP_KERNEL);
|
||||
|
||||
if (ti) {
|
||||
memset(ti, 0, sizeof(*ti));
|
||||
ti->tt = *t;
|
||||
}
|
||||
|
||||
return ti;
|
||||
}
|
||||
|
||||
int dm_register_target(struct target_type *t)
|
||||
{
|
||||
int rv = 0;
|
||||
struct tt_internal *ti = alloc_target(t);
|
||||
|
||||
if (!ti)
|
||||
return -ENOMEM;
|
||||
|
||||
write_lock(&_lock);
|
||||
if (__find_target_type(t->name))
|
||||
rv = -EEXIST;
|
||||
else
|
||||
list_add(&ti->list, &_targets);
|
||||
|
||||
write_unlock(&_lock);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int dm_unregister_target(struct target_type *t)
|
||||
{
|
||||
struct tt_internal *ti = (struct tt_internal *) t;
|
||||
int rv = -ETXTBSY;
|
||||
|
||||
write_lock(&_lock);
|
||||
if (ti->use == 0) {
|
||||
list_del(&ti->list);
|
||||
kfree(ti);
|
||||
rv = 0;
|
||||
}
|
||||
write_unlock(&_lock);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* io-err: always fails an io, useful for bringing
|
||||
* up LV's that have holes in them.
|
||||
*/
|
||||
static int io_err_ctr(struct dm_table *t, offset_t b, offset_t l,
|
||||
char *args, void **context)
|
||||
{
|
||||
*context = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void io_err_dtr(struct dm_table *t, void *c)
|
||||
{
|
||||
/* empty */
|
||||
}
|
||||
|
||||
static int io_err_map(struct buffer_head *bh, int rw, void *context)
|
||||
{
|
||||
buffer_IO_error(bh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct target_type error_target = {
|
||||
name: "error",
|
||||
ctr: io_err_ctr,
|
||||
dtr: io_err_dtr,
|
||||
map: io_err_map
|
||||
};
|
||||
|
||||
|
||||
int dm_target_init(void)
|
||||
{
|
||||
return dm_register_target(&error_target);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(dm_register_target);
|
||||
EXPORT_SYMBOL(dm_unregister_target);
|
||||
|
@@ -1,963 +0,0 @@
|
||||
/*
|
||||
* device-mapper.c
|
||||
*
|
||||
* Copyright (C) 2001 Sistina Software
|
||||
*
|
||||
* This software 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 software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU CC; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Changelog
|
||||
*
|
||||
* 14/08/2001 - First Version [Joe Thornber]
|
||||
*/
|
||||
|
||||
#include "dm.h"
|
||||
#include "dmfs.h"
|
||||
|
||||
#include <linux/blkpg.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/kmod.h>
|
||||
|
||||
/* we only need this for the lv_bmap struct definition, not happy */
|
||||
#include <linux/lvm.h>
|
||||
|
||||
#define MAX_DEVICES 64
|
||||
#define DEFAULT_READ_AHEAD 64
|
||||
|
||||
static int major = 0;
|
||||
const char *_name = "device-mapper";
|
||||
int _version[3] = {0, 1, 0};
|
||||
|
||||
struct io_hook {
|
||||
struct mapped_device *md;
|
||||
struct target *target;
|
||||
int rw;
|
||||
|
||||
void (*end_io)(struct buffer_head * bh, int uptodate);
|
||||
void *context;
|
||||
};
|
||||
|
||||
kmem_cache_t *_io_hook_cache;
|
||||
|
||||
#define rl down_read(&_dev_lock)
|
||||
#define ru up_read(&_dev_lock)
|
||||
#define wl down_write(&_dev_lock)
|
||||
#define wu up_write(&_dev_lock)
|
||||
|
||||
struct rw_semaphore _dev_lock;
|
||||
static struct mapped_device *_devs[MAX_DEVICES];
|
||||
|
||||
/* block device arrays */
|
||||
static int _block_size[MAX_DEVICES];
|
||||
static int _blksize_size[MAX_DEVICES];
|
||||
static int _hardsect_size[MAX_DEVICES];
|
||||
|
||||
const char *_fs_dir = "device-mapper";
|
||||
static devfs_handle_t _dev_dir;
|
||||
|
||||
static int request(request_queue_t *q, int rw, struct buffer_head *bh);
|
||||
static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb);
|
||||
|
||||
/*
|
||||
* setup and teardown the driver
|
||||
*/
|
||||
static int __init dm_init(void)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
|
||||
init_rwsem(&_dev_lock);
|
||||
|
||||
_io_hook_cache = kmem_cache_create("dm io hooks",
|
||||
sizeof(struct io_hook),
|
||||
0, 0, NULL, NULL);
|
||||
|
||||
if (!_io_hook_cache)
|
||||
goto err;
|
||||
|
||||
ret = dmfs_init();
|
||||
if (ret < 0)
|
||||
goto err_kmem_cache_destroy;
|
||||
|
||||
ret = dm_target_init();
|
||||
if (ret)
|
||||
goto err_kmem_cache_destroy;
|
||||
|
||||
ret = devfs_register_blkdev(major, _name, &dm_blk_dops);
|
||||
if (ret < 0)
|
||||
goto err_blkdev;
|
||||
|
||||
if (major == 0)
|
||||
major = ret;
|
||||
|
||||
/* set up the arrays */
|
||||
read_ahead[major] = DEFAULT_READ_AHEAD;
|
||||
blk_size[major] = _block_size;
|
||||
blksize_size[major] = _blksize_size;
|
||||
hardsect_size[major] = _hardsect_size;
|
||||
|
||||
ret = -EIO;
|
||||
|
||||
blk_queue_make_request(BLK_DEFAULT_QUEUE(major), request);
|
||||
|
||||
_dev_dir = devfs_mk_dir(0, _fs_dir, NULL);
|
||||
|
||||
printk(KERN_INFO "%s %d.%d.%d initialised\n", _name,
|
||||
_version[0], _version[1], _version[2]);
|
||||
return 0;
|
||||
|
||||
err_blkdev:
|
||||
printk(KERN_ERR "%s -- register_blkdev failed\n", _name);
|
||||
err_kmem_cache_destroy:
|
||||
kmem_cache_destroy(_io_hook_cache);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit dm_exit(void)
|
||||
{
|
||||
dmfs_exit();
|
||||
|
||||
if (kmem_cache_destroy(_io_hook_cache))
|
||||
WARN("it looks like there are still some io_hooks allocated");
|
||||
|
||||
|
||||
if (devfs_unregister_blkdev(major, _name) < 0)
|
||||
printk(KERN_ERR "%s -- unregister_blkdev failed\n", _name);
|
||||
|
||||
read_ahead[major] = 0;
|
||||
blk_size[major] = NULL;
|
||||
blksize_size[major] = NULL;
|
||||
hardsect_size[major] = NULL;
|
||||
|
||||
printk(KERN_INFO "%s %d.%d.%d cleaned up\n", _name,
|
||||
_version[0], _version[1], _version[2]);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG
|
||||
static void dm_sbin_hotplug(struct mapped_device *md, char *action, int minor)
|
||||
{
|
||||
int i;
|
||||
char *argv[3];
|
||||
char *envp[7];
|
||||
char name[DM_NAME_LEN + 16];
|
||||
char dev_major[16], dev_minor[16];
|
||||
|
||||
if (!hotplug_path[0])
|
||||
return;
|
||||
|
||||
if (!current->fs->root)
|
||||
return;
|
||||
|
||||
sprintf(name, "DMNAME=%s\n", md->name);
|
||||
sprintf(dev_major, "MAJOR=%d", major);
|
||||
sprintf(dev_minor, "MINOR=%d", minor);
|
||||
|
||||
i = 0;
|
||||
argv[i++] = hotplug_path;
|
||||
argv[i++] = "devmap";
|
||||
argv[i] = 0;
|
||||
|
||||
i = 0;
|
||||
envp[i++] = "HOME=/";
|
||||
envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
|
||||
envp[i++] = name;
|
||||
envp[i++] = action;
|
||||
envp[i++] = dev_minor;
|
||||
envp[i++] = dev_major;
|
||||
envp[i] = 0;
|
||||
|
||||
call_usermodehelper(argv[0], argv, envp);
|
||||
}
|
||||
#else
|
||||
#define dm_sbin_hotplug(md, action, minor) do { } while(0)
|
||||
#endif /* CONFIG_HOTPLUG */
|
||||
|
||||
/*
|
||||
* block device functions
|
||||
*/
|
||||
static int dm_blk_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
int minor = MINOR(inode->i_rdev);
|
||||
struct mapped_device *md;
|
||||
|
||||
if (minor >= MAX_DEVICES)
|
||||
return -ENXIO;
|
||||
|
||||
wl;
|
||||
md = _devs[minor];
|
||||
|
||||
if (!md || !is_active(md)) {
|
||||
wu;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
md->use_count++;
|
||||
wu;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dm_blk_close(struct inode *inode, struct file *file)
|
||||
{
|
||||
int minor = MINOR(inode->i_rdev);
|
||||
struct mapped_device *md;
|
||||
|
||||
if (minor >= MAX_DEVICES)
|
||||
return -ENXIO;
|
||||
|
||||
wl;
|
||||
md = _devs[minor];
|
||||
if (!md || md->use_count < 1) {
|
||||
WARN("reference count in mapped_device incorrect");
|
||||
wu;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
md->use_count--;
|
||||
wu;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In 512-byte units */
|
||||
#define VOLUME_SIZE(minor) (_block_size[(minor)] >> 1)
|
||||
|
||||
static int dm_blk_ioctl(struct inode *inode, struct file *file,
|
||||
uint command, ulong a)
|
||||
{
|
||||
int minor = MINOR(inode->i_rdev);
|
||||
long size;
|
||||
|
||||
if (minor >= MAX_DEVICES)
|
||||
return -ENXIO;
|
||||
|
||||
switch (command) {
|
||||
case BLKSSZGET:
|
||||
case BLKBSZGET:
|
||||
case BLKROGET:
|
||||
case BLKROSET:
|
||||
case BLKRASET:
|
||||
case BLKRAGET:
|
||||
case BLKFLSBUF:
|
||||
#if 0
|
||||
case BLKELVSET:
|
||||
case BLKELVGET:
|
||||
#endif
|
||||
return blk_ioctl(inode->i_rdev, command, a);
|
||||
break;
|
||||
|
||||
case BLKGETSIZE:
|
||||
size = VOLUME_SIZE(minor);
|
||||
if (copy_to_user((void *) a, &size, sizeof (long)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
|
||||
case BLKGETSIZE64:
|
||||
size = VOLUME_SIZE(minor);
|
||||
if (put_user((u64)size, (u64 *)a))
|
||||
return -EFAULT;
|
||||
break;
|
||||
|
||||
case BLKRRPART:
|
||||
return -EINVAL;
|
||||
|
||||
case LV_BMAP:
|
||||
return dm_user_bmap(inode, (struct lv_bmap *) a);
|
||||
|
||||
default:
|
||||
WARN("unknown block ioctl %d", command);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct io_hook *alloc_io_hook(void)
|
||||
{
|
||||
return kmem_cache_alloc(_io_hook_cache, GFP_NOIO);
|
||||
}
|
||||
|
||||
static inline void free_io_hook(struct io_hook *ih)
|
||||
{
|
||||
kmem_cache_free(_io_hook_cache, ih);
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: need to decide if deferred_io's need
|
||||
* their own slab, I say no for now since they are
|
||||
* only used when the device is suspended.
|
||||
*/
|
||||
static inline struct deferred_io *alloc_deferred(void)
|
||||
{
|
||||
return kmalloc(sizeof(struct deferred_io), GFP_NOIO);
|
||||
}
|
||||
|
||||
static inline void free_deferred(struct deferred_io *di)
|
||||
{
|
||||
kfree(di);
|
||||
}
|
||||
|
||||
/*
|
||||
* call a targets optional error function if
|
||||
* an io failed.
|
||||
*/
|
||||
static inline int call_err_fn(struct io_hook *ih, struct buffer_head *bh)
|
||||
{
|
||||
dm_err_fn err = ih->target->type->err;
|
||||
if (err)
|
||||
return err(bh, ih->rw, ih->target->private);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* bh->b_end_io routine that decrements the
|
||||
* pending count and then calls the original
|
||||
* bh->b_end_io fn.
|
||||
*/
|
||||
static void dec_pending(struct buffer_head *bh, int uptodate)
|
||||
{
|
||||
struct io_hook *ih = bh->b_private;
|
||||
|
||||
if (!uptodate && call_err_fn(ih, bh))
|
||||
return;
|
||||
|
||||
if (atomic_dec_and_test(&ih->md->pending))
|
||||
/* nudge anyone waiting on suspend queue */
|
||||
wake_up(&ih->md->wait);
|
||||
|
||||
bh->b_end_io = ih->end_io;
|
||||
bh->b_private = ih->context;
|
||||
free_io_hook(ih);
|
||||
|
||||
bh->b_end_io(bh, uptodate);
|
||||
}
|
||||
|
||||
/*
|
||||
* add the bh to the list of deferred io.
|
||||
*/
|
||||
static int queue_io(struct mapped_device *md, struct buffer_head *bh, int rw)
|
||||
{
|
||||
struct deferred_io *di = alloc_deferred();
|
||||
|
||||
if (!di)
|
||||
return -ENOMEM;
|
||||
|
||||
wl;
|
||||
if (test_bit(DM_ACTIVE, &md->state)) {
|
||||
wu;
|
||||
return 0;
|
||||
}
|
||||
|
||||
di->bh = bh;
|
||||
di->rw = rw;
|
||||
di->next = md->deferred;
|
||||
md->deferred = di;
|
||||
wu;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* do the bh mapping for a given leaf
|
||||
*/
|
||||
static inline int __map_buffer(struct mapped_device *md,
|
||||
struct buffer_head *bh, int rw, int leaf)
|
||||
{
|
||||
int r;
|
||||
dm_map_fn fn;
|
||||
void *context;
|
||||
struct io_hook *ih = NULL;
|
||||
struct target *ti = md->map->targets + leaf;
|
||||
|
||||
fn = ti->type->map;
|
||||
context = ti->private;
|
||||
|
||||
ih = alloc_io_hook();
|
||||
|
||||
if (!ih)
|
||||
return 0;
|
||||
|
||||
ih->md = md;
|
||||
ih->rw = rw;
|
||||
ih->target = ti;
|
||||
ih->end_io = bh->b_end_io;
|
||||
ih->context = bh->b_private;
|
||||
|
||||
r = fn(bh, rw, context);
|
||||
|
||||
if (r > 0) {
|
||||
/* hook the end io request fn */
|
||||
atomic_inc(&md->pending);
|
||||
bh->b_end_io = dec_pending;
|
||||
bh->b_private = ih;
|
||||
|
||||
} else if (r == 0)
|
||||
/* we don't need to hook */
|
||||
free_io_hook(ih);
|
||||
|
||||
else if (r < 0) {
|
||||
free_io_hook(ih);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* search the btree for the correct target.
|
||||
*/
|
||||
static inline int __find_node(struct dm_table *t, struct buffer_head *bh)
|
||||
{
|
||||
int l, n = 0, k = 0;
|
||||
offset_t *node;
|
||||
|
||||
for (l = 0; l < t->depth; l++) {
|
||||
n = get_child(n, k);
|
||||
node = get_node(t, l, n);
|
||||
|
||||
for (k = 0; k < KEYS_PER_NODE; k++)
|
||||
if (node[k] >= bh->b_rsector)
|
||||
break;
|
||||
}
|
||||
|
||||
return (KEYS_PER_NODE * n) + k;
|
||||
}
|
||||
|
||||
static int request(request_queue_t *q, int rw, struct buffer_head *bh)
|
||||
{
|
||||
struct mapped_device *md;
|
||||
int r, minor = MINOR(bh->b_rdev);
|
||||
|
||||
if (minor >= MAX_DEVICES)
|
||||
goto bad_no_lock;
|
||||
|
||||
rl;
|
||||
md = _devs[minor];
|
||||
|
||||
if (!md || !md->map)
|
||||
goto bad;
|
||||
|
||||
/* if we're suspended we have to queue this io for later */
|
||||
if (!test_bit(DM_ACTIVE, &md->state)) {
|
||||
ru;
|
||||
r = queue_io(md, bh, rw);
|
||||
|
||||
if (r < 0)
|
||||
goto bad_no_lock;
|
||||
|
||||
else if (r > 0)
|
||||
return 0; /* deferred successfully */
|
||||
|
||||
rl; /* FIXME: there's still a race here */
|
||||
}
|
||||
|
||||
if (!__map_buffer(md, bh, rw, __find_node(md->map, bh)))
|
||||
goto bad;
|
||||
|
||||
ru;
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
ru;
|
||||
|
||||
bad_no_lock:
|
||||
buffer_IO_error(bh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_dev_size(int minor, unsigned long block)
|
||||
{
|
||||
/* FIXME: check this */
|
||||
unsigned long max_sector = (_block_size[minor] << 1) + 1;
|
||||
unsigned long sector = (block + 1) * (_blksize_size[minor] >> 9);
|
||||
|
||||
return (sector > max_sector) ? 0 : 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* creates a dummy buffer head and maps it (for lilo).
|
||||
*/
|
||||
static int do_bmap(kdev_t dev, unsigned long block,
|
||||
kdev_t *r_dev, unsigned long *r_block)
|
||||
{
|
||||
struct mapped_device *md;
|
||||
struct buffer_head bh;
|
||||
int minor = MINOR(dev), r;
|
||||
struct target *t;
|
||||
|
||||
rl;
|
||||
if ((minor >= MAX_DEVICES) || !(md = _devs[minor]) ||
|
||||
!test_bit(DM_ACTIVE, &md->state)) {
|
||||
r = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!check_dev_size(minor, block)) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* setup dummy bh */
|
||||
memset(&bh, 0, sizeof(bh));
|
||||
bh.b_blocknr = block;
|
||||
bh.b_dev = bh.b_rdev = dev;
|
||||
bh.b_size = _blksize_size[minor];
|
||||
bh.b_rsector = block * (bh.b_size >> 9);
|
||||
|
||||
/* find target */
|
||||
t = md->map->targets + __find_node(md->map, &bh);
|
||||
|
||||
/* do the mapping */
|
||||
r = t->type->map(&bh, READ, t->private);
|
||||
|
||||
*r_dev = bh.b_rdev;
|
||||
*r_block = bh.b_rsector / (bh.b_size >> 9);
|
||||
|
||||
out:
|
||||
ru;
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* marshals arguments and results between user and
|
||||
* kernel space.
|
||||
*/
|
||||
static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb)
|
||||
{
|
||||
unsigned long block, r_block;
|
||||
kdev_t r_dev;
|
||||
int r;
|
||||
|
||||
if (get_user(block, &lvb->lv_block))
|
||||
return -EFAULT;
|
||||
|
||||
if ((r = do_bmap(inode->i_rdev, block, &r_dev, &r_block)))
|
||||
return r;
|
||||
|
||||
if (put_user(kdev_t_to_nr(r_dev), &lvb->lv_dev) ||
|
||||
put_user(r_block, &lvb->lv_block))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* see if the device with a specific minor # is
|
||||
* free.
|
||||
*/
|
||||
static inline int __specific_dev(int minor)
|
||||
{
|
||||
if (minor > MAX_DEVICES) {
|
||||
WARN("request for a mapped_device > than MAX_DEVICES");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_devs[minor])
|
||||
return minor;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* find the first free device.
|
||||
*/
|
||||
static inline int __any_old_dev(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_DEVICES; i++)
|
||||
if (!_devs[i])
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate and initialise a blank device.
|
||||
*/
|
||||
static struct mapped_device *alloc_dev(int minor)
|
||||
{
|
||||
struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL);
|
||||
|
||||
if (!md)
|
||||
return 0;
|
||||
|
||||
memset(md, 0, sizeof (*md));
|
||||
|
||||
wl;
|
||||
minor = (minor < 0) ? __any_old_dev() : __specific_dev(minor);
|
||||
|
||||
if (minor < 0) {
|
||||
WARN("no free devices available");
|
||||
wu;
|
||||
kfree(md);
|
||||
return 0;
|
||||
}
|
||||
|
||||
md->dev = MKDEV(DM_BLK_MAJOR, minor);
|
||||
md->name[0] = '\0';
|
||||
md->state = 0;
|
||||
|
||||
init_waitqueue_head(&md->wait);
|
||||
|
||||
_devs[minor] = md;
|
||||
wu;
|
||||
|
||||
return md;
|
||||
}
|
||||
|
||||
/*
|
||||
* open a device so we can use it as a map
|
||||
* destination.
|
||||
*/
|
||||
static int open_dev(struct dm_dev *d)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (d->bd)
|
||||
BUG();
|
||||
|
||||
if (!(d->bd = bdget(kdev_t_to_nr(d->dev))))
|
||||
return -ENOMEM;
|
||||
|
||||
if ((err = blkdev_get(d->bd, FMODE_READ|FMODE_WRITE, 0, BDEV_FILE))) {
|
||||
bdput(d->bd);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* close a device that we've been using.
|
||||
*/
|
||||
static void close_dev(struct dm_dev *d)
|
||||
{
|
||||
if (!d->bd)
|
||||
return;
|
||||
|
||||
blkdev_put(d->bd, BDEV_FILE);
|
||||
bdput(d->bd);
|
||||
d->bd = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Close a list of devices.
|
||||
*/
|
||||
static void close_devices(struct list_head *devices)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
|
||||
for (tmp = devices->next; tmp != devices; tmp = tmp->next) {
|
||||
struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
|
||||
close_dev(dd);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a list of devices.
|
||||
*/
|
||||
static int open_devices(struct list_head *devices)
|
||||
{
|
||||
int r = 0;
|
||||
struct list_head *tmp;
|
||||
|
||||
for (tmp = devices->next; tmp != devices; tmp = tmp->next) {
|
||||
struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
|
||||
if ((r = open_dev(dd)))
|
||||
goto bad;
|
||||
}
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
close_devices(devices);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
struct mapped_device *dm_find_by_minor(int minor)
|
||||
{
|
||||
struct mapped_device *md;
|
||||
|
||||
rl;
|
||||
md = _devs[minor];
|
||||
ru;
|
||||
|
||||
return md;
|
||||
}
|
||||
|
||||
static int register_device(struct mapped_device *md)
|
||||
{
|
||||
md->devfs_entry =
|
||||
devfs_register(_dev_dir, md->name, DEVFS_FL_CURRENT_OWNER,
|
||||
MAJOR(md->dev), MINOR(md->dev),
|
||||
S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
|
||||
&dm_blk_dops, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unregister_device(struct mapped_device *md)
|
||||
{
|
||||
devfs_unregister(md->devfs_entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* constructor for a new device
|
||||
*/
|
||||
struct mapped_device *dm_create(const char *name, int minor)
|
||||
{
|
||||
int r;
|
||||
struct mapped_device *md;
|
||||
|
||||
if (minor >= MAX_DEVICES)
|
||||
return ERR_PTR(-ENXIO);
|
||||
|
||||
if (!(md = alloc_dev(minor)))
|
||||
return ERR_PTR(-ENXIO);
|
||||
|
||||
wl;
|
||||
strcpy(md->name, name);
|
||||
_devs[minor] = md;
|
||||
if ((r = register_device(md))) {
|
||||
wu;
|
||||
return ERR_PTR(r);
|
||||
}
|
||||
wu;
|
||||
|
||||
dm_sbin_hotplug(md, "ACTION=create", minor);
|
||||
|
||||
return md;
|
||||
}
|
||||
|
||||
/*
|
||||
* destructor for the device. md->map is
|
||||
* deliberately not destroyed, dm-fs should manage
|
||||
* table objects.
|
||||
*/
|
||||
int dm_remove(struct mapped_device *md)
|
||||
{
|
||||
int minor, r;
|
||||
|
||||
wl;
|
||||
if (md->use_count) {
|
||||
wu;
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if ((r = unregister_device(md))) {
|
||||
wu;
|
||||
return r;
|
||||
}
|
||||
|
||||
minor = MINOR(md->dev);
|
||||
_devs[minor] = 0;
|
||||
wu;
|
||||
|
||||
dm_sbin_hotplug(md, "ACTION=remove", minor);
|
||||
kfree(md);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* the hardsect size for a mapped device is the
|
||||
* smallest hard sect size from the devices it
|
||||
* maps onto.
|
||||
*/
|
||||
static int __find_hardsect_size(struct list_head *devices)
|
||||
{
|
||||
int result = INT_MAX, size;
|
||||
struct list_head *tmp;
|
||||
|
||||
for (tmp = devices->next; tmp != devices; tmp = tmp->next) {
|
||||
struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
|
||||
size = get_hardsect_size(dd->dev);
|
||||
if (size < result)
|
||||
result = size;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bind a table to the device.
|
||||
*/
|
||||
void __bind(struct mapped_device *md, struct dm_table *t)
|
||||
{
|
||||
int minor = MINOR(md->dev);
|
||||
|
||||
md->map = t;
|
||||
|
||||
/* in k */
|
||||
_block_size[minor] = (t->highs[t->num_targets - 1] + 1) >> 1;
|
||||
|
||||
_blksize_size[minor] = BLOCK_SIZE;
|
||||
_hardsect_size[minor] = __find_hardsect_size(&t->devices);
|
||||
register_disk(NULL, md->dev, 1, &dm_blk_dops, _block_size[minor]);
|
||||
}
|
||||
|
||||
/*
|
||||
* requeue the deferred buffer_heads by calling
|
||||
* generic_make_request.
|
||||
*/
|
||||
static void __flush_deferred_io(struct mapped_device *md)
|
||||
{
|
||||
struct deferred_io *c, *n;
|
||||
|
||||
for (c = md->deferred, md->deferred = 0; c; c = n) {
|
||||
n = c->next;
|
||||
generic_make_request(c->rw, c->bh);
|
||||
free_deferred(c);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* make the device available for use, if was
|
||||
* previously suspended rather than newly created
|
||||
* then all queued io is flushed
|
||||
*/
|
||||
int dm_activate(struct mapped_device *md, struct dm_table *table)
|
||||
{
|
||||
int r;
|
||||
|
||||
/* check that the mapping has at least been loaded. */
|
||||
if (!table->num_targets)
|
||||
return -EINVAL;
|
||||
|
||||
wl;
|
||||
|
||||
/* you must be deactivated first */
|
||||
if (is_active(md)) {
|
||||
wu;
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
__bind(md, table);
|
||||
|
||||
if ((r = open_devices(&md->map->devices))) {
|
||||
wu;
|
||||
return r;
|
||||
}
|
||||
|
||||
set_bit(DM_ACTIVE, &md->state);
|
||||
__flush_deferred_io(md);
|
||||
wu;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deactivate the device, the device must not be
|
||||
* opened by anyone.
|
||||
*/
|
||||
int dm_deactivate(struct mapped_device *md)
|
||||
{
|
||||
rl;
|
||||
if (md->use_count) {
|
||||
ru;
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
fsync_dev(md->dev);
|
||||
|
||||
ru;
|
||||
|
||||
wl;
|
||||
if (md->use_count) {
|
||||
/* drat, somebody got in quick ... */
|
||||
wu;
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (md->map)
|
||||
close_devices(&md->map->devices);
|
||||
md->map = NULL;
|
||||
clear_bit(DM_ACTIVE, &md->state);
|
||||
wu;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to be able to change a mapping table
|
||||
* under a mounted filesystem. for example we
|
||||
* might want to move some data in the background.
|
||||
* Before the table can be swapped with
|
||||
* dm_bind_table, dm_suspend must be called to
|
||||
* flush any in flight buffer_heads and ensure
|
||||
* that any further io gets deferred.
|
||||
*/
|
||||
void dm_suspend(struct mapped_device *md)
|
||||
{
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
wl;
|
||||
if (!is_active(md)) {
|
||||
wu;
|
||||
return;
|
||||
}
|
||||
|
||||
clear_bit(DM_ACTIVE, &md->state);
|
||||
wu;
|
||||
|
||||
/* wait for all the pending io to flush */
|
||||
add_wait_queue(&md->wait, &wait);
|
||||
current->state = TASK_UNINTERRUPTIBLE;
|
||||
do {
|
||||
wl;
|
||||
if (!atomic_read(&md->pending))
|
||||
break;
|
||||
|
||||
wu;
|
||||
schedule();
|
||||
|
||||
} while (1);
|
||||
|
||||
current->state = TASK_RUNNING;
|
||||
remove_wait_queue(&md->wait, &wait);
|
||||
close_devices(&md->map->devices);
|
||||
|
||||
md->map = 0;
|
||||
wu;
|
||||
}
|
||||
|
||||
struct block_device_operations dm_blk_dops = {
|
||||
open: dm_blk_open,
|
||||
release: dm_blk_close,
|
||||
ioctl: dm_blk_ioctl,
|
||||
owner: THIS_MODULE,
|
||||
};
|
||||
|
||||
/*
|
||||
* module hooks
|
||||
*/
|
||||
module_init(dm_init);
|
||||
module_exit(dm_exit);
|
||||
|
||||
MODULE_PARM(major, "i");
|
||||
MODULE_PARM_DESC(major, "The major device number of the device-mapper");
|
||||
MODULE_DESCRIPTION("device-mapper driver");
|
||||
MODULE_AUTHOR("Joe Thornber <thornber@btconnect.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
@@ -1,256 +0,0 @@
|
||||
/*
|
||||
* dm.h
|
||||
*
|
||||
* Copyright (C) 2001 Sistina Software
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Internal header file for device mapper
|
||||
*
|
||||
* Changelog
|
||||
*
|
||||
* 16/08/2001 - First version [Joe Thornber]
|
||||
*/
|
||||
|
||||
/*
|
||||
* This driver attempts to provide a generic way of specifying logical
|
||||
* devices which are mapped onto other devices.
|
||||
*
|
||||
* It does this by mapping sections of the logical device onto 'targets'.
|
||||
*
|
||||
* When the logical device is accessed the make_request function looks up
|
||||
* the correct target for the given sector, and then asks this target
|
||||
* to do the remapping.
|
||||
*
|
||||
* (dm-table.c) A btree like structure is used to hold the sector
|
||||
* range -> target mapping. Because we know all the entries in the
|
||||
* btree in advance we can make a very compact tree, omitting pointers
|
||||
* to child nodes, (child nodes locations can be calculated). Each
|
||||
* node of the btree is 1 level cache line in size, this gives a small
|
||||
* performance boost.
|
||||
*
|
||||
* A userland test program for the btree gave the following results on a
|
||||
* 1 Gigahertz Athlon machine:
|
||||
*
|
||||
* entries in btree lookups per second
|
||||
* ---------------- ------------------
|
||||
* 5 25,000,000
|
||||
* 1000 7,700,000
|
||||
* 10,000,000 3,800,000
|
||||
*
|
||||
* Of course these results should be taken with a pinch of salt; the
|
||||
* lookups were sequential and there were no other applications (other
|
||||
* than X + emacs) running to give any pressure on the level 1 cache.
|
||||
*
|
||||
* Typical LVM users would find they have very few targets for each
|
||||
* LV (probably less than 10).
|
||||
*
|
||||
* (dm-target.c) Target types are not hard coded, instead the
|
||||
* register_mapping_type function should be called. A target type is
|
||||
* specified using three functions (see the header):
|
||||
*
|
||||
* dm_ctr_fn - takes a string and contructs a target specific piece of
|
||||
* context data.
|
||||
* dm_dtr_fn - destroy contexts.
|
||||
* dm_map_fn - function that takes a buffer_head and some previously
|
||||
* constructed context and performs the remapping.
|
||||
*
|
||||
* Currently there are two two trivial mappers, which are
|
||||
* automatically registered: 'linear', and 'io_error'. Linear alone
|
||||
* is enough to implement most LVM features (omitting striped volumes
|
||||
* and snapshots).
|
||||
*
|
||||
* (dm-fs.c) The driver is controlled through a /proc interface:
|
||||
* /proc/device-mapper/control allows you to create and remove devices
|
||||
* by 'cat'ing a line of the following format:
|
||||
*
|
||||
* create <device name> [minor no]
|
||||
* remove <device name>
|
||||
*
|
||||
* /proc/device-mapper/<device name> accepts the mapping table:
|
||||
*
|
||||
* begin
|
||||
* <sector start> <length> <target name> <target args>...
|
||||
* ...
|
||||
* end
|
||||
*
|
||||
* The begin/end lines are nasty, they should be handled by open/close
|
||||
* for the file.
|
||||
*
|
||||
* At the moment the table assumes 32 bit keys (sectors), the move to
|
||||
* 64 bits will involve no interface changes, since the tables will be
|
||||
* read in as ascii data. A different table implementation can
|
||||
* therefor be provided at another time. Either just by changing offset_t
|
||||
* to 64 bits, or maybe implementing a structure which looks up the keys in
|
||||
* stages (ie, 32 bits at a time).
|
||||
*
|
||||
* More interesting targets:
|
||||
*
|
||||
* striped mapping; given a stripe size and a number of device regions
|
||||
* this would stripe data across the regions. Especially useful, since
|
||||
* we could limit each striped region to a 32 bit area and then avoid
|
||||
* nasty 64 bit %'s.
|
||||
*
|
||||
* mirror mapping (reflector ?); would set off a kernel thread slowly
|
||||
* copying data from one region to another, ensuring that any new
|
||||
* writes got copied to both destinations correctly. Great for
|
||||
* implementing pvmove. Not sure how userland would be notified that
|
||||
* the copying process had completed. Possibly by reading a /proc entry
|
||||
* for the LV. Could also use poll() for this kind of thing.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DM_INTERNAL_H
|
||||
#define DM_INTERNAL_H
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/iobuf.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/compatmac.h>
|
||||
#include <linux/cache.h>
|
||||
#include <linux/devfs_fs_kernel.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/device-mapper.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#define MAX_DEPTH 16
|
||||
#define NODE_SIZE L1_CACHE_BYTES
|
||||
#define KEYS_PER_NODE (NODE_SIZE / sizeof(offset_t))
|
||||
#define CHILDREN_PER_NODE (KEYS_PER_NODE + 1)
|
||||
#define DM_NAME_LEN 128
|
||||
#define MAX_TARGET_LINE 256
|
||||
|
||||
enum {
|
||||
DM_BOUND = 0, /* device has been bound to a table */
|
||||
DM_ACTIVE, /* device is running */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* list of devices that a metadevice uses
|
||||
* and hence should open/close.
|
||||
*/
|
||||
struct dm_dev {
|
||||
atomic_t count;
|
||||
struct list_head list;
|
||||
|
||||
kdev_t dev;
|
||||
struct block_device *bd;
|
||||
};
|
||||
|
||||
/*
|
||||
* io that had to be deferred while we were
|
||||
* suspended
|
||||
*/
|
||||
struct deferred_io {
|
||||
int rw;
|
||||
struct buffer_head *bh;
|
||||
struct deferred_io *next;
|
||||
};
|
||||
|
||||
/*
|
||||
* btree leaf, these do the actual mapping
|
||||
*/
|
||||
struct target {
|
||||
struct target_type *type;
|
||||
void *private;
|
||||
};
|
||||
|
||||
/*
|
||||
* the btree
|
||||
*/
|
||||
struct dm_table {
|
||||
/* btree table */
|
||||
int depth;
|
||||
int counts[MAX_DEPTH]; /* in nodes */
|
||||
offset_t *index[MAX_DEPTH];
|
||||
|
||||
int num_targets;
|
||||
int num_allocated;
|
||||
offset_t *highs;
|
||||
struct target *targets;
|
||||
|
||||
/* a list of devices used by this table */
|
||||
struct list_head devices;
|
||||
};
|
||||
|
||||
/*
|
||||
* the actual device struct
|
||||
*/
|
||||
struct mapped_device {
|
||||
kdev_t dev;
|
||||
char name[DM_NAME_LEN];
|
||||
|
||||
int use_count;
|
||||
int state;
|
||||
|
||||
/* a list of io's that arrived while we were suspended */
|
||||
atomic_t pending;
|
||||
wait_queue_head_t wait;
|
||||
struct deferred_io *deferred;
|
||||
|
||||
struct dm_table *map;
|
||||
|
||||
/* used by dm-fs.c */
|
||||
devfs_handle_t devfs_entry;
|
||||
};
|
||||
|
||||
extern struct block_device_operations dm_blk_dops;
|
||||
|
||||
|
||||
/* dm-target.c */
|
||||
int dm_target_init(void);
|
||||
struct target_type *dm_get_target_type(const char *name);
|
||||
void dm_put_target_type(struct target_type *t);
|
||||
|
||||
/* dm.c */
|
||||
struct mapped_device *dm_find_by_minor(int minor);
|
||||
|
||||
struct mapped_device *dm_create(const char *name, int minor);
|
||||
int dm_remove(struct mapped_device *md);
|
||||
|
||||
int dm_activate(struct mapped_device *md, struct dm_table *t);
|
||||
int dm_deactivate(struct mapped_device *md);
|
||||
|
||||
void dm_suspend(struct mapped_device *md);
|
||||
|
||||
|
||||
/* dm-table.c */
|
||||
struct dm_table *dm_table_create(void);
|
||||
void dm_table_destroy(struct dm_table *t);
|
||||
|
||||
int dm_table_add_target(struct dm_table *t, offset_t high,
|
||||
struct target_type *type, void *private);
|
||||
int dm_table_complete(struct dm_table *t);
|
||||
|
||||
#define WARN(f, x...) printk(KERN_WARNING "device-mapper: " f "\n" , ## x)
|
||||
|
||||
/*
|
||||
* calculate the index of the child node of the
|
||||
* n'th node k'th key.
|
||||
*/
|
||||
static inline int get_child(int n, int k)
|
||||
{
|
||||
return (n * CHILDREN_PER_NODE) + k;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns the n'th node of level l from table t.
|
||||
*/
|
||||
static inline offset_t *get_node(struct dm_table *t, int l, int n)
|
||||
{
|
||||
return t->index[l] + (n * KEYS_PER_NODE);
|
||||
}
|
||||
|
||||
static inline int is_active(struct mapped_device *md)
|
||||
{
|
||||
return test_bit(DM_ACTIVE, &md->state);
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
* dmfs-error.c
|
||||
*
|
||||
* Copyright (C) 2001 Sistina Software
|
||||
*
|
||||
* This software 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 software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU CC; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include "dm.h"
|
||||
#include "dmfs.h"
|
||||
|
||||
struct dmfs_error {
|
||||
struct list_head list;
|
||||
unsigned len;
|
||||
char *msg;
|
||||
};
|
||||
|
||||
static struct dmfs_error oom_error;
|
||||
|
||||
static struct list_head oom_list = {
|
||||
next: &oom_error.list,
|
||||
prev: &oom_error.list,
|
||||
};
|
||||
|
||||
static struct dmfs_error oom_error = {
|
||||
list: { next: &oom_list, prev: &oom_list },
|
||||
len: 39,
|
||||
msg: "Out of memory during creation of table\n",
|
||||
};
|
||||
|
||||
void dmfs_add_error(struct inode *inode, unsigned num, char *str)
|
||||
{
|
||||
struct dmfs_i *dmi = DMFS_I(inode);
|
||||
int len = strlen(str) + sizeof(struct dmfs_error) + 12;
|
||||
struct dmfs_error *e = kmalloc(len, GFP_KERNEL);
|
||||
if (e) {
|
||||
e->msg = (char *)(e + 1);
|
||||
e->len = sprintf(e->msg, "%8u: %s\n", num, str);
|
||||
list_add(&e->list, &dmi->errors);
|
||||
}
|
||||
}
|
||||
|
||||
void dmfs_zap_errors(struct inode *inode)
|
||||
{
|
||||
struct dmfs_i *dmi = DMFS_I(inode);
|
||||
struct dmfs_error *e;
|
||||
|
||||
while(!list_empty(&dmi->errors)) {
|
||||
e = list_entry(dmi->errors.next, struct dmfs_error, list);
|
||||
list_del(&e->list);
|
||||
kfree(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void *e_start(void *context, loff_t *pos)
|
||||
{
|
||||
struct list_head *p;
|
||||
loff_t n = *pos;
|
||||
struct dmfs_i *dmi = context;
|
||||
|
||||
down(&dmi->sem);
|
||||
if (dmi->status) {
|
||||
list_for_each(p, &oom_list)
|
||||
if (n-- == 0)
|
||||
return list_entry(p, struct dmfs_error, list);
|
||||
} else {
|
||||
list_for_each(p, &dmi->errors)
|
||||
if (n-- == 0)
|
||||
return list_entry(p, struct dmfs_error, list);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *e_next(void *context, void *v, loff_t *pos)
|
||||
{
|
||||
struct dmfs_i *dmi = context;
|
||||
struct list_head *p = ((struct dmfs_error *)v)->list.next;
|
||||
(*pos)++;
|
||||
return (p == &dmi->errors) || (p == &oom_list) ? NULL
|
||||
: list_entry(p, struct dmfs_error, list);
|
||||
}
|
||||
|
||||
static void e_stop(void *context, void *v)
|
||||
{
|
||||
struct dmfs_i *dmi = context;
|
||||
up(&dmi->sem);
|
||||
}
|
||||
|
||||
static int show_error(struct seq_file *e, void *v)
|
||||
{
|
||||
struct dmfs_error *d = v;
|
||||
seq_puts(e, d->msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct seq_operations error_op = {
|
||||
start: e_start,
|
||||
next: e_next,
|
||||
stop: e_stop,
|
||||
show: show_error,
|
||||
};
|
||||
|
||||
static int dmfs_error_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return seq_open(file, &error_op, DMFS_I(file->f_dentry->d_parent->d_inode));
|
||||
}
|
||||
|
||||
static int dmfs_error_sync(struct file *file, struct dentry *dentry, int datasync)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations dmfs_error_file_operations = {
|
||||
open: dmfs_error_open,
|
||||
read: seq_read,
|
||||
llseek: seq_lseek,
|
||||
release: seq_release,
|
||||
fsync: dmfs_error_sync,
|
||||
};
|
||||
|
||||
static struct inode_operations dmfs_error_inode_operations = {
|
||||
};
|
||||
|
||||
struct inode *dmfs_create_error(struct inode *dir, int mode)
|
||||
{
|
||||
struct inode *inode = dmfs_new_inode(dir->i_sb, mode | S_IFREG);
|
||||
|
||||
if (inode) {
|
||||
inode->i_fop = &dmfs_error_file_operations;
|
||||
inode->i_op = &dmfs_error_inode_operations;
|
||||
}
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
@@ -1,286 +0,0 @@
|
||||
/*
|
||||
* dmfs-lv.c
|
||||
*
|
||||
* Copyright (C) 2001 Sistina Software
|
||||
*
|
||||
* This software 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 software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU CC; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* Heavily based upon ramfs */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "dm.h"
|
||||
#include "dmfs.h"
|
||||
|
||||
extern struct address_space_operations dmfs_address_space_operations;
|
||||
extern struct inode *dmfs_create_tdir(struct super_block *sb, int mode);
|
||||
|
||||
struct dentry *dmfs_verify_name(struct inode *dir, const char *name)
|
||||
{
|
||||
struct nameidata nd;
|
||||
int err = -ENOENT;
|
||||
struct file file;
|
||||
struct dentry *dentry;
|
||||
|
||||
memset(&file, 0, sizeof(struct file));
|
||||
|
||||
if (!path_init(name, LOOKUP_FOLLOW, &nd))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
err = path_walk(name, &nd);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
err = -EINVAL;
|
||||
if (nd.mnt->mnt_sb != dir->i_sb)
|
||||
goto err_out;
|
||||
|
||||
if (nd.dentry->d_parent->d_inode != dir)
|
||||
goto err_out;
|
||||
|
||||
err = -ENODATA;
|
||||
if (DMFS_I(nd.dentry->d_inode) == NULL ||
|
||||
DMFS_I(nd.dentry->d_inode)->table == NULL)
|
||||
goto err_out;
|
||||
|
||||
if (!list_empty(&(DMFS_I(nd.dentry->d_inode)->errors)))
|
||||
goto err_out;
|
||||
|
||||
dentry = nd.dentry;
|
||||
file.f_dentry = nd.dentry;
|
||||
err = deny_write_access(&file);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
dget(dentry);
|
||||
path_release(&nd);
|
||||
return dentry;
|
||||
err_out:
|
||||
path_release(&nd);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
struct inode *dmfs_create_symlink(struct inode *dir, int mode)
|
||||
{
|
||||
struct inode *inode = dmfs_new_private_inode(dir->i_sb, mode | S_IFLNK);
|
||||
|
||||
if (inode) {
|
||||
inode->i_mapping->a_ops = &dmfs_address_space_operations;
|
||||
inode->i_op = &page_symlink_inode_operations;
|
||||
}
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
||||
static int dmfs_lv_unlink(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct file file = { f_dentry: DMFS_I(inode)->dentry };
|
||||
|
||||
if (!(inode->i_mode & S_IFLNK))
|
||||
return -EINVAL;
|
||||
|
||||
dm_suspend(DMFS_I(dir)->md);
|
||||
allow_write_access(&file);
|
||||
dput(DMFS_I(inode)->dentry);
|
||||
DMFS_I(inode)->dentry = NULL;
|
||||
inode->i_nlink--;
|
||||
dput(dentry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dmfs_lv_symlink(struct inode *dir, struct dentry *dentry,
|
||||
const char *symname)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct dentry *de;
|
||||
int rv;
|
||||
int l;
|
||||
|
||||
if (dentry->d_name.len != 6 ||
|
||||
memcmp(dentry->d_name.name, "ACTIVE", 6) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
de = dmfs_verify_name(dir, symname);
|
||||
if (IS_ERR(de))
|
||||
return PTR_ERR(de);
|
||||
|
||||
inode = dmfs_create_symlink(dir, S_IRWXUGO);
|
||||
if (inode == NULL) {
|
||||
rv = -ENOSPC;
|
||||
goto out_allow_write;
|
||||
}
|
||||
|
||||
DMFS_I(inode)->dentry = de;
|
||||
d_instantiate(dentry, inode);
|
||||
dget(dentry);
|
||||
|
||||
l = strlen(symname) + 1;
|
||||
rv = block_symlink(inode, symname, l);
|
||||
if (rv)
|
||||
goto out_dput;
|
||||
|
||||
rv = dm_activate(DMFS_I(dir)->md, DMFS_I(de->d_inode)->table);
|
||||
if (rv)
|
||||
goto out_dput;
|
||||
|
||||
return rv;
|
||||
|
||||
out_dput:
|
||||
dput(dentry);
|
||||
DMFS_I(inode)->dentry = NULL;
|
||||
out_allow_write:
|
||||
{
|
||||
struct file file = { f_dentry: de };
|
||||
allow_write_access(&file);
|
||||
dput(de);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int is_identifier(const char *str, int len)
|
||||
{
|
||||
while(len--) {
|
||||
if (!isalnum(*str) && *str != '_')
|
||||
return 0;
|
||||
str++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dmfs_lv_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
||||
{
|
||||
struct inode *inode;
|
||||
int rv = -ENOSPC;
|
||||
|
||||
if (dentry->d_name.len >= DM_NAME_LEN)
|
||||
return -EINVAL;
|
||||
|
||||
if (!is_identifier(dentry->d_name.name, dentry->d_name.len))
|
||||
return -EPERM;
|
||||
|
||||
if (dentry->d_name.len == 6 &&
|
||||
memcmp(dentry->d_name.name, "ACTIVE", 6) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (dentry->d_name.name[0] == '.')
|
||||
return -EINVAL;
|
||||
|
||||
inode = dmfs_create_tdir(dir->i_sb, mode);
|
||||
if (inode) {
|
||||
d_instantiate(dentry, inode);
|
||||
dget(dentry);
|
||||
rv = 0;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* if u.generic_ip is not NULL, then it indicates an inode which
|
||||
* represents a table. If it is NULL then the inode is a virtual
|
||||
* file and should be deleted along with the directory.
|
||||
*/
|
||||
static inline int positive(struct dentry *dentry)
|
||||
{
|
||||
return dentry->d_inode && !d_unhashed(dentry);
|
||||
}
|
||||
|
||||
static int empty(struct dentry *dentry)
|
||||
{
|
||||
struct list_head *list;
|
||||
|
||||
spin_lock(&dcache_lock);
|
||||
list = dentry->d_subdirs.next;
|
||||
|
||||
while(list != &dentry->d_subdirs) {
|
||||
struct dentry *de = list_entry(list, struct dentry, d_child);
|
||||
|
||||
if (positive(de)) {
|
||||
spin_unlock(&dcache_lock);
|
||||
return 0;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
spin_unlock(&dcache_lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dmfs_lv_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
int ret = -ENOTEMPTY;
|
||||
|
||||
if (empty(dentry)) {
|
||||
struct inode *inode = dentry->d_inode;
|
||||
inode->i_nlink--;
|
||||
dput(dentry);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct dentry *dmfs_lv_lookup(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
d_add(dentry, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int dmfs_lv_sync(struct file *file, struct dentry *dentry, int datasync)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations dmfs_lv_file_operations = {
|
||||
read: generic_read_dir,
|
||||
readdir: dcache_readdir,
|
||||
fsync: dmfs_lv_sync,
|
||||
};
|
||||
|
||||
static struct inode_operations dmfs_lv_inode_operations = {
|
||||
lookup: dmfs_lv_lookup,
|
||||
unlink: dmfs_lv_unlink,
|
||||
symlink: dmfs_lv_symlink,
|
||||
mkdir: dmfs_lv_mkdir,
|
||||
rmdir: dmfs_lv_rmdir,
|
||||
};
|
||||
|
||||
struct inode *dmfs_create_lv(struct super_block *sb, int mode, struct dentry *dentry)
|
||||
{
|
||||
struct inode *inode = dmfs_new_private_inode(sb, mode | S_IFDIR);
|
||||
struct mapped_device *md;
|
||||
const char *name = dentry->d_name.name;
|
||||
char tmp_name[DM_NAME_LEN + 1];
|
||||
|
||||
if (inode) {
|
||||
inode->i_fop = &dmfs_lv_file_operations;
|
||||
inode->i_op = &dmfs_lv_inode_operations;
|
||||
memcpy(tmp_name, name, dentry->d_name.len);
|
||||
tmp_name[dentry->d_name.len] = 0;
|
||||
md = dm_create(tmp_name, -1);
|
||||
if (IS_ERR(md)) {
|
||||
iput(inode);
|
||||
return ERR_PTR(PTR_ERR(md));
|
||||
}
|
||||
DMFS_I(inode)->md = md;
|
||||
}
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
||||
|
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* dmfs-root.c
|
||||
*
|
||||
* Copyright (C) 2001 Sistina Software
|
||||
*
|
||||
* This software 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 software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU CC; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* Heavily based upon ramfs */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "dm.h"
|
||||
#include "dmfs.h"
|
||||
|
||||
extern struct inode *dmfs_create_lv(struct super_block *sb, int mode, struct dentry *dentry);
|
||||
|
||||
static int is_identifier(const char *str, int len)
|
||||
{
|
||||
while(len--) {
|
||||
if (!isalnum(*str) && *str != '_')
|
||||
return 0;
|
||||
str++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dmfs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
||||
{
|
||||
struct inode *inode;
|
||||
int rv = -ENOSPC;
|
||||
|
||||
if (dentry->d_name.len >= DM_NAME_LEN)
|
||||
return -EINVAL;
|
||||
|
||||
if (!is_identifier(dentry->d_name.name, dentry->d_name.len))
|
||||
return -EPERM;
|
||||
|
||||
if (dentry->d_name.name[0] == '.')
|
||||
return -EINVAL;
|
||||
|
||||
inode = dmfs_create_lv(dir->i_sb, mode, dentry);
|
||||
if (inode) {
|
||||
d_instantiate(dentry, inode);
|
||||
dget(dentry);
|
||||
rv = 0;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* if u.generic_ip is not NULL, then it indicates an inode which
|
||||
* represents a table. If it is NULL then the inode is a virtual
|
||||
* file and should be deleted along with the directory.
|
||||
*/
|
||||
static inline int positive(struct dentry *dentry)
|
||||
{
|
||||
return dentry->d_inode && !d_unhashed(dentry);
|
||||
}
|
||||
|
||||
static int empty(struct dentry *dentry)
|
||||
{
|
||||
struct list_head *list;
|
||||
|
||||
spin_lock(&dcache_lock);
|
||||
list = dentry->d_subdirs.next;
|
||||
|
||||
while(list != &dentry->d_subdirs) {
|
||||
struct dentry *de = list_entry(list, struct dentry, d_child);
|
||||
|
||||
if (positive(de)) {
|
||||
spin_unlock(&dcache_lock);
|
||||
return 0;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
spin_unlock(&dcache_lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dmfs_root_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
int ret = -ENOTEMPTY;
|
||||
|
||||
if (empty(dentry)) {
|
||||
struct inode *inode = dentry->d_inode;
|
||||
ret = dm_deactivate(DMFS_I(inode)->md);
|
||||
if (ret == 0) {
|
||||
inode->i_nlink--;
|
||||
dput(dentry);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct dentry *dmfs_root_lookup(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
d_add(dentry, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int dmfs_root_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry)
|
||||
{
|
||||
/* Can only rename - not move between directories! */
|
||||
if (old_dir != new_dir)
|
||||
return -EPERM;
|
||||
|
||||
return -EINVAL; /* FIXME: a change of LV name here */
|
||||
}
|
||||
|
||||
static int dmfs_root_sync(struct file *file, struct dentry *dentry, int datasync)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations dmfs_root_file_operations = {
|
||||
read: generic_read_dir,
|
||||
readdir: dcache_readdir,
|
||||
fsync: dmfs_root_sync,
|
||||
};
|
||||
|
||||
static struct inode_operations dmfs_root_inode_operations = {
|
||||
lookup: dmfs_root_lookup,
|
||||
mkdir: dmfs_root_mkdir,
|
||||
rmdir: dmfs_root_rmdir,
|
||||
rename: dmfs_root_rename,
|
||||
};
|
||||
|
||||
struct inode *dmfs_create_root(struct super_block *sb, int mode)
|
||||
{
|
||||
struct inode *inode = dmfs_new_inode(sb, mode | S_IFDIR);
|
||||
|
||||
if (inode) {
|
||||
inode->i_fop = &dmfs_root_file_operations;
|
||||
inode->i_op = &dmfs_root_inode_operations;
|
||||
}
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
||||
|
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* dmfs-status.c
|
||||
*
|
||||
* Copyright (C) 2001 Sistina Software
|
||||
*
|
||||
* This software 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 software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU CC; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "dm.h"
|
||||
#include "dmfs.h"
|
||||
|
||||
static ssize_t dmfs_status_read(struct file *file, char *buf, size_t size, loff_t *pos)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dmfs_status_sync(struct file *file, struct dentry *dentry, int datasync)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations dmfs_status_file_operations = {
|
||||
read: dmfs_status_read,
|
||||
fsync: dmfs_status_sync,
|
||||
};
|
||||
|
||||
static struct inode_operations dmfs_status_inode_operations = {
|
||||
};
|
||||
|
||||
struct inode *dmfs_create_status(struct inode *dir, int mode)
|
||||
{
|
||||
struct inode *inode = dmfs_new_inode(dir->i_sb, mode | S_IFREG);
|
||||
|
||||
if (inode) {
|
||||
inode->i_fop = &dmfs_status_file_operations;
|
||||
inode->i_op = &dmfs_status_inode_operations;
|
||||
}
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* dmfs-super.c
|
||||
*
|
||||
* Copyright (C) 2001 Sistina Software
|
||||
*
|
||||
* This software 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 software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU CC; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include "dmfs.h"
|
||||
#include "dm.h"
|
||||
|
||||
#define DMFS_MAGIC 0x444D4653
|
||||
|
||||
extern struct inode *dmfs_create_root(struct super_block *sb, int);
|
||||
|
||||
static int dmfs_statfs(struct super_block *sb, struct statfs *buf)
|
||||
{
|
||||
buf->f_type = sb->s_magic;
|
||||
buf->f_bsize = sb->s_blocksize;
|
||||
buf->f_namelen = DM_NAME_LEN - 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dmfs_delete_inode(struct inode *inode)
|
||||
{
|
||||
struct dmfs_i *dmi = DMFS_I(inode);
|
||||
|
||||
if (dmi) {
|
||||
if (dmi->md)
|
||||
dm_remove(dmi->md);
|
||||
if (dmi->table)
|
||||
dm_table_destroy(dmi->table);
|
||||
if (dmi->dentry)
|
||||
dput(dmi->dentry);
|
||||
if (!list_empty(&dmi->errors))
|
||||
dmfs_zap_errors(inode);
|
||||
kfree(dmi);
|
||||
MOD_DEC_USE_COUNT; /* Don't remove */
|
||||
}
|
||||
|
||||
inode->u.generic_ip = NULL;
|
||||
clear_inode(inode);
|
||||
}
|
||||
|
||||
static struct super_operations dmfs_super_operations = {
|
||||
statfs: dmfs_statfs,
|
||||
put_inode: force_delete,
|
||||
delete_inode: dmfs_delete_inode,
|
||||
};
|
||||
|
||||
static struct super_block *dmfs_read_super(struct super_block *sb, void *data, int silent)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct dentry *root;
|
||||
|
||||
sb->s_blocksize = PAGE_CACHE_SIZE;
|
||||
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
|
||||
sb->s_magic = DMFS_MAGIC;
|
||||
sb->s_op = &dmfs_super_operations;
|
||||
sb->s_maxbytes = MAX_NON_LFS;
|
||||
|
||||
inode = dmfs_create_root(sb, 0755);
|
||||
if (IS_ERR(inode))
|
||||
return NULL;
|
||||
root = d_alloc_root(inode);
|
||||
if (!root) {
|
||||
iput(inode);
|
||||
return NULL;
|
||||
}
|
||||
sb->s_root = root;
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
struct inode *dmfs_new_inode(struct super_block *sb, int mode)
|
||||
{
|
||||
struct inode *inode = new_inode(sb);
|
||||
|
||||
if (inode) {
|
||||
inode->i_mode = mode;
|
||||
inode->i_uid = current->fsuid;
|
||||
inode->i_gid = current->fsgid;
|
||||
inode->i_blksize = PAGE_CACHE_SIZE;
|
||||
inode->i_blocks = 0;
|
||||
inode->i_rdev = NODEV;
|
||||
inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
|
||||
}
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
||||
struct inode *dmfs_new_private_inode(struct super_block *sb, int mode)
|
||||
{
|
||||
struct inode *inode = dmfs_new_inode(sb, mode);
|
||||
struct dmfs_i *dmi;
|
||||
|
||||
if (inode) {
|
||||
dmi = kmalloc(sizeof(struct dmfs_i), GFP_KERNEL);
|
||||
if (dmi == NULL) {
|
||||
iput(inode);
|
||||
return NULL;
|
||||
}
|
||||
memset(dmi, 0, sizeof(struct dmfs_i));
|
||||
init_MUTEX(&dmi->sem);
|
||||
INIT_LIST_HEAD(&dmi->errors);
|
||||
inode->u.generic_ip = dmi;
|
||||
MOD_INC_USE_COUNT; /* Don't remove */
|
||||
}
|
||||
return inode;
|
||||
}
|
||||
|
||||
static DECLARE_FSTYPE(dmfs_fstype, "dmfs", dmfs_read_super, FS_SINGLE);
|
||||
static struct vfsmount *dmfs_mnt;
|
||||
|
||||
int __init dmfs_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = register_filesystem(&dmfs_fstype);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
dmfs_mnt = kern_mount(&dmfs_fstype);
|
||||
if (IS_ERR(dmfs_mnt)) {
|
||||
ret = PTR_ERR(dmfs_mnt);
|
||||
unregister_filesystem(&dmfs_fstype);
|
||||
} else {
|
||||
MOD_DEC_USE_COUNT; /* Yes, this really is correct... */
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __exit dmfs_exit(void)
|
||||
{
|
||||
MOD_INC_USE_COUNT; /* So that it lands up being zero */
|
||||
|
||||
do_umount(dmfs_mnt, 0);
|
||||
|
||||
unregister_filesystem(&dmfs_fstype);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -1,353 +0,0 @@
|
||||
/*
|
||||
* dmfs-table.c
|
||||
*
|
||||
* Copyright (C) 2001 Sistina Software
|
||||
*
|
||||
* This software 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 software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU CC; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include "dm.h"
|
||||
#include "dmfs.h"
|
||||
|
||||
static offset_t start_of_next_range(struct dm_table *t)
|
||||
{
|
||||
offset_t n = 0;
|
||||
if (t->num_targets) {
|
||||
n = t->highs[t->num_targets - 1] + 1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static char *dmfs_parse_line(struct dm_table *t, char *str)
|
||||
{
|
||||
offset_t start, size, high;
|
||||
void *context;
|
||||
struct target_type *ttype;
|
||||
int rv = 0;
|
||||
char *msg;
|
||||
int pos = 0;
|
||||
char target[33];
|
||||
|
||||
static char *err_table[] = {
|
||||
"Missing/Invalid start argument",
|
||||
"Missing/Invalid size argument",
|
||||
"Missing target type"
|
||||
};
|
||||
printk("dmfs_parse_line: (%s)\n", str);
|
||||
|
||||
rv = sscanf(str, "%d %d %32s%n", &start, &size, target, &pos);
|
||||
if (rv < 3) {
|
||||
msg = err_table[rv];
|
||||
goto out;
|
||||
}
|
||||
str += pos;
|
||||
while(*str && isspace(*str))
|
||||
str++;
|
||||
|
||||
msg = "Gap in table";
|
||||
if (start != start_of_next_range(t))
|
||||
goto out;
|
||||
|
||||
msg = "Target type unknown";
|
||||
ttype = dm_get_target_type(target);
|
||||
if (ttype) {
|
||||
msg = "This message should never appear (constructor error)";
|
||||
rv = ttype->ctr(t, start, size, str, &context);
|
||||
msg = context;
|
||||
if (rv == 0) {
|
||||
printk("dmfs_parse: %u %u %s %s\n", start, size,
|
||||
ttype->name,
|
||||
ttype->print ? ttype->print(context) : "-");
|
||||
msg = "Error adding target to table";
|
||||
high = start + (size - 1);
|
||||
if (dm_table_add_target(t, high, ttype, context) == 0)
|
||||
return NULL;
|
||||
ttype->dtr(t, context);
|
||||
}
|
||||
dm_put_target_type(ttype);
|
||||
}
|
||||
out:
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
static int dmfs_copy(char *dst, int dstlen, char *src, int srclen, int *flag)
|
||||
{
|
||||
int len = min(dstlen, srclen);
|
||||
char *start = dst;
|
||||
|
||||
while(len) {
|
||||
*dst = *src++;
|
||||
if (*dst == '\n')
|
||||
goto end_of_line;
|
||||
dst++;
|
||||
len--;
|
||||
}
|
||||
out:
|
||||
return (dst - start);
|
||||
end_of_line:
|
||||
dst++;
|
||||
*flag = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
static int dmfs_line_is_not_comment(char *str)
|
||||
{
|
||||
while(*str) {
|
||||
if (*str == '#')
|
||||
break;
|
||||
if (!isspace(*str))
|
||||
return 1;
|
||||
str++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dmfs_desc {
|
||||
struct dm_table *table;
|
||||
struct inode *inode;
|
||||
char *tmp;
|
||||
loff_t tmpl;
|
||||
unsigned long lnum;
|
||||
};
|
||||
|
||||
static int dmfs_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset, unsigned long size)
|
||||
{
|
||||
char *buf, *msg;
|
||||
unsigned long count = desc->count, len, copied;
|
||||
struct dmfs_desc *d = (struct dmfs_desc *)desc->buf;
|
||||
|
||||
if (size > count)
|
||||
size = count;
|
||||
|
||||
len = size;
|
||||
buf = kmap(page);
|
||||
do {
|
||||
int flag = 0;
|
||||
copied = dmfs_copy(d->tmp + d->tmpl, PAGE_SIZE - d->tmpl - 1,
|
||||
buf + offset, len, &flag);
|
||||
offset += copied;
|
||||
len -= copied;
|
||||
if (d->tmpl + copied == PAGE_SIZE - 1)
|
||||
goto line_too_long;
|
||||
d->tmpl += copied;
|
||||
if (flag || (len == 0 && count == size)) {
|
||||
*(d->tmp + d->tmpl) = 0;
|
||||
if (dmfs_line_is_not_comment(d->tmp)) {
|
||||
msg = dmfs_parse_line(d->table, d->tmp);
|
||||
if (msg) {
|
||||
dmfs_add_error(d->inode, d->lnum, msg);
|
||||
}
|
||||
}
|
||||
d->lnum++;
|
||||
d->tmpl = 0;
|
||||
}
|
||||
} while(len > 0);
|
||||
kunmap(page);
|
||||
|
||||
desc->count = count - size;
|
||||
desc->written += size;
|
||||
|
||||
return size;
|
||||
|
||||
line_too_long:
|
||||
printk(KERN_INFO "dmfs_read_actor: Line %lu too long\n", d->lnum);
|
||||
kunmap(page);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dm_table *dmfs_parse(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct dm_table *t = NULL;
|
||||
unsigned long page;
|
||||
struct dmfs_desc d;
|
||||
loff_t pos = 0;
|
||||
|
||||
if (inode->i_size == 0)
|
||||
return NULL;
|
||||
|
||||
page = __get_free_page(GFP_NOFS);
|
||||
if (page) {
|
||||
t = dm_table_create();
|
||||
if (t) {
|
||||
read_descriptor_t desc;
|
||||
|
||||
desc.written = 0;
|
||||
desc.count = inode->i_size;
|
||||
desc.buf = (char *)&d;
|
||||
d.table = t;
|
||||
d.inode = inode;
|
||||
d.tmp = (char *)page;
|
||||
d.tmpl = 0;
|
||||
d.lnum = 1;
|
||||
|
||||
do_generic_file_read(filp, &pos, &desc, dmfs_read_actor);
|
||||
if (desc.written != inode->i_size) {
|
||||
dm_table_destroy(t);
|
||||
t = NULL;
|
||||
}
|
||||
}
|
||||
free_page(page);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
static int dmfs_table_release(struct inode *inode, struct file *f)
|
||||
{
|
||||
struct dentry *dentry = f->f_dentry;
|
||||
struct inode *parent = dentry->d_parent->d_inode;
|
||||
struct dmfs_i *dmi = DMFS_I(parent);
|
||||
struct dm_table *table;
|
||||
|
||||
if (f->f_mode & FMODE_WRITE) {
|
||||
|
||||
down(&dmi->sem);
|
||||
dmfs_zap_errors(dentry->d_parent->d_inode);
|
||||
table = dmfs_parse(dentry->d_parent->d_inode, f);
|
||||
|
||||
if (table) {
|
||||
if (dmi->table)
|
||||
dm_table_destroy(dmi->table);
|
||||
dmi->table = table;
|
||||
}
|
||||
up(&dmi->sem);
|
||||
|
||||
put_write_access(parent);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dmfs_readpage(struct file *file, struct page *page)
|
||||
{
|
||||
if (!Page_Uptodate(page)) {
|
||||
memset(kmap(page), 0, PAGE_CACHE_SIZE);
|
||||
kunmap(page);
|
||||
flush_dcache_page(page);
|
||||
SetPageUptodate(page);
|
||||
}
|
||||
UnlockPage(page);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dmfs_prepare_write(struct file *file, struct page *page,
|
||||
unsigned offset, unsigned to)
|
||||
{
|
||||
void *addr = kmap(page);
|
||||
if (!Page_Uptodate(page)) {
|
||||
memset(addr, 0, PAGE_CACHE_SIZE);
|
||||
flush_dcache_page(page);
|
||||
SetPageUptodate(page);
|
||||
}
|
||||
SetPageDirty(page);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dmfs_commit_write(struct file *file, struct page *page,
|
||||
unsigned offset, unsigned to)
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + to;
|
||||
|
||||
kunmap(page);
|
||||
if (pos > inode->i_size)
|
||||
inode->i_size = pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* There is a small race here in that two processes might call this at
|
||||
* the same time and both fail. So its a fail safe race :-) This should
|
||||
* move into namei.c (and thus use the spinlock and do this properly)
|
||||
* at some stage if we continue to use this set of functions for ensuring
|
||||
* exclusive write access to the file
|
||||
*/
|
||||
static int get_exclusive_write_access(struct inode *inode)
|
||||
{
|
||||
if (get_write_access(inode))
|
||||
return -1;
|
||||
if (atomic_read(&inode->i_writecount) != 1) {
|
||||
put_write_access(inode);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dmfs_table_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dentry *dentry = file->f_dentry;
|
||||
struct inode *parent = dentry->d_parent->d_inode;
|
||||
|
||||
if (file->f_mode & FMODE_WRITE) {
|
||||
if (get_exclusive_write_access(parent))
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dmfs_table_sync(struct file *file, struct dentry *dentry, int datasync)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dmfs_table_revalidate(struct dentry *dentry)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *parent = dentry->d_parent->d_inode;
|
||||
|
||||
inode->i_size = parent->i_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct address_space_operations dmfs_address_space_operations = {
|
||||
readpage: dmfs_readpage,
|
||||
writepage: fail_writepage,
|
||||
prepare_write: dmfs_prepare_write,
|
||||
commit_write: dmfs_commit_write,
|
||||
};
|
||||
|
||||
static struct file_operations dmfs_table_file_operations = {
|
||||
llseek: generic_file_llseek,
|
||||
read: generic_file_read,
|
||||
write: generic_file_write,
|
||||
open: dmfs_table_open,
|
||||
release: dmfs_table_release,
|
||||
fsync: dmfs_table_sync,
|
||||
};
|
||||
|
||||
static struct inode_operations dmfs_table_inode_operations = {
|
||||
revalidate: dmfs_table_revalidate,
|
||||
};
|
||||
|
||||
struct inode *dmfs_create_table(struct inode *dir, int mode)
|
||||
{
|
||||
struct inode *inode = dmfs_new_inode(dir->i_sb, mode | S_IFREG);
|
||||
|
||||
if (inode) {
|
||||
inode->i_mapping = dir->i_mapping;
|
||||
inode->i_mapping->a_ops = &dmfs_address_space_operations;
|
||||
inode->i_fop = &dmfs_table_file_operations;
|
||||
inode->i_op = &dmfs_table_inode_operations;
|
||||
}
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* dmfs-tdir.c
|
||||
*
|
||||
* Copyright (C) 2001 Sistina Software
|
||||
*
|
||||
* This software 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 software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GNU CC; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* Heavily based upon ramfs */
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "dm.h"
|
||||
#include "dmfs.h"
|
||||
|
||||
extern struct inode *dmfs_create_error(struct inode *, int);
|
||||
extern struct inode *dmfs_create_table(struct inode *, int);
|
||||
extern struct inode *dmfs_create_status(struct inode *, int);
|
||||
|
||||
|
||||
static int dmfs_tdir_unlink(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
|
||||
inode->i_mapping = &inode->i_data;
|
||||
inode->i_nlink--;
|
||||
dput(dentry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dentry *dmfs_tdir_lookup(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
struct inode *inode = NULL;
|
||||
const char *name = dentry->d_name.name;
|
||||
|
||||
switch(dentry->d_name.len) {
|
||||
case 5:
|
||||
if (memcmp("table", name, 5) == 0) {
|
||||
inode = dmfs_create_table(dir, 0600);
|
||||
break;
|
||||
}
|
||||
if (memcmp("error", name, 5) == 0)
|
||||
inode = dmfs_create_error(dir, 0600);
|
||||
break;
|
||||
case 6:
|
||||
if (memcmp("status", name, 6) == 0)
|
||||
inode = dmfs_create_status(dir, 0600);
|
||||
break;
|
||||
}
|
||||
|
||||
d_add(dentry, inode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int dmfs_tdir_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||
{
|
||||
int i;
|
||||
struct dentry *dentry = filp->f_dentry;
|
||||
|
||||
i = filp->f_pos;
|
||||
switch(i) {
|
||||
case 0:
|
||||
if (filldir(dirent, ".", 1, i, dentry->d_inode->i_ino, DT_DIR) < 0)
|
||||
break;
|
||||
i++;
|
||||
filp->f_pos++;
|
||||
/* fallthrough */
|
||||
case 1:
|
||||
if (filldir(dirent, "..", 2, i, dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
|
||||
break;
|
||||
i++;
|
||||
filp->f_pos++;
|
||||
/* fallthrough */
|
||||
case 2:
|
||||
if (filldir(dirent, "table", 5, i, 2, DT_REG) < 0)
|
||||
break;
|
||||
i++;
|
||||
filp->f_pos++;
|
||||
/* fallthrough */
|
||||
case 3:
|
||||
if (filldir(dirent, "error", 5, i, 3, DT_REG) < 0)
|
||||
break;
|
||||
i++;
|
||||
filp->f_pos++;
|
||||
/* fallthrough */
|
||||
case 4:
|
||||
if (filldir(dirent, "status", 6, i, 4, DT_REG) < 0)
|
||||
break;
|
||||
i++;
|
||||
filp->f_pos++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int dmfs_tdir_sync(struct file *file, struct dentry *dentry, int datasync)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations dmfs_tdir_file_operations = {
|
||||
read: generic_read_dir,
|
||||
readdir: dmfs_tdir_readdir,
|
||||
fsync: dmfs_tdir_sync,
|
||||
};
|
||||
|
||||
static struct inode_operations dmfs_tdir_inode_operations = {
|
||||
lookup: dmfs_tdir_lookup,
|
||||
unlink: dmfs_tdir_unlink,
|
||||
};
|
||||
|
||||
struct inode *dmfs_create_tdir(struct super_block *sb, int mode)
|
||||
{
|
||||
struct inode *inode = dmfs_new_private_inode(sb, mode | S_IFDIR);
|
||||
|
||||
if (inode) {
|
||||
inode->i_fop = &dmfs_tdir_file_operations;
|
||||
inode->i_op = &dmfs_tdir_inode_operations;
|
||||
}
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
||||
|
@@ -1,27 +0,0 @@
|
||||
#ifndef LINUX_DMFS_H
|
||||
#define LINUX_DMFS_H
|
||||
|
||||
struct dmfs_i {
|
||||
struct semaphore sem;
|
||||
struct dm_table *table;
|
||||
struct mapped_device *md;
|
||||
struct dentry *dentry;
|
||||
struct list_head errors;
|
||||
int status;
|
||||
};
|
||||
|
||||
#define DMFS_I(inode) ((struct dmfs_i *)(inode)->u.generic_ip)
|
||||
|
||||
|
||||
extern int dmfs_init(void) __init;
|
||||
extern int dmfs_exit(void) __exit;
|
||||
|
||||
struct inode *dmfs_new_inode(struct super_block *sb, int mode);
|
||||
struct inode *dmfs_new_private_inode(struct super_block *sb, int mode);
|
||||
|
||||
void dmfs_add_error(struct inode *inode, unsigned num, char *str);
|
||||
void dmfs_zap_errors(struct inode *inode);
|
||||
|
||||
|
||||
|
||||
#endif /* LINUX_DMFS_H */
|
@@ -1,10 +0,0 @@
|
||||
--- linux-2.4.14/drivers/md/Config.in Mon Sep 24 16:29:14 2001
|
||||
+++ linux/drivers/md/Config.in Tue Nov 6 11:25:35 2001
|
||||
@@ -14,5 +14,7 @@
|
||||
dep_tristate ' Multipath I/O support' CONFIG_MD_MULTIPATH $CONFIG_BLK_DEV_MD
|
||||
|
||||
dep_tristate ' Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM $CONFIG_MD
|
||||
+dep_tristate ' Device mapper support' CONFIG_BLK_DEV_DM $CONFIG_MD
|
||||
+dep_tristate ' Device mapper linear target' CONFIG_BLK_DEV_DM_LINEAR $CONFIG_BLK_DEV_DM
|
||||
|
||||
endmenu
|
@@ -1,13 +0,0 @@
|
||||
--- uml_build/arch/um/config.in.orig Tue Jan 2 14:33:42 2001
|
||||
+++ uml_build/arch/um/config.in Tue Jan 2 14:35:42 2001
|
||||
@@ -15,6 +15,8 @@
|
||||
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
|
||||
endmenu
|
||||
|
||||
+source drivers/md/Config.in
|
||||
+
|
||||
mainmenu_option next_comment
|
||||
comment 'Processor features'
|
||||
bool 'Symmetric multi-processing support' CONFIG_SMP
|
||||
|
||||
|
@@ -1,10 +0,0 @@
|
||||
--- linux-2.4.14/kernel/ksyms.c Tue Nov 6 11:18:14 2001
|
||||
+++ linux/kernel/ksyms.c Wed Nov 7 11:26:45 2001
|
||||
@@ -521,6 +521,7 @@
|
||||
|
||||
/* binfmt_aout */
|
||||
EXPORT_SYMBOL(get_write_access);
|
||||
+EXPORT_SYMBOL(deny_write_access);
|
||||
|
||||
/* time */
|
||||
EXPORT_SYMBOL(get_fast_time);
|
@@ -1,31 +0,0 @@
|
||||
--- linux-2.4.14/drivers/md/Makefile Mon Sep 24 16:29:14 2001
|
||||
+++ linux/drivers/md/Makefile Wed Nov 7 10:48:26 2001
|
||||
@@ -4,9 +4,12 @@
|
||||
|
||||
O_TARGET := mddev.o
|
||||
|
||||
-export-objs := md.o xor.o
|
||||
+export-objs := md.o xor.o dm-table.o dm-target.o
|
||||
list-multi := lvm-mod.o
|
||||
lvm-mod-objs := lvm.o lvm-snap.o
|
||||
+dm-mod-objs := dm.o dm-table.o dm-target.o dmfs-super.o dmfs-root.o \
|
||||
+ dmfs-tdir.o dmfs-table.o dmfs-error.o dmfs-status.o \
|
||||
+ dmfs-lv.o seq_file.o
|
||||
|
||||
# Note: link order is important. All raid personalities
|
||||
# and xor.o must come before md.o, as they each initialise
|
||||
@@ -20,8 +23,14 @@
|
||||
obj-$(CONFIG_MD_MULTIPATH) += multipath.o
|
||||
obj-$(CONFIG_BLK_DEV_MD) += md.o
|
||||
obj-$(CONFIG_BLK_DEV_LVM) += lvm-mod.o
|
||||
+obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o
|
||||
+obj-$(CONFIG_BLK_DEV_DM_LINEAR) += dm-linear.o
|
||||
|
||||
include $(TOPDIR)/Rules.make
|
||||
|
||||
lvm-mod.o: $(lvm-mod-objs)
|
||||
$(LD) -r -o $@ $(lvm-mod-objs)
|
||||
+
|
||||
+dm-mod.o: $(dm-mod-objs)
|
||||
+ $(LD) -r -o $@ $(dm-mod-objs)
|
||||
+
|
@@ -1,13 +0,0 @@
|
||||
00_latest Latest source - I only tend to update this before
|
||||
making a release. So if you got this from CVS copy
|
||||
or link the source files in by hand.
|
||||
|
||||
00_config Add device-mapper to the MD section
|
||||
|
||||
00_config_uml only apply for uml, turns on the md section
|
||||
|
||||
00_makefile Add device-mapper to the MD Makefile.
|
||||
|
||||
00_bh-async-3 AA's async bh patch so we can hook b_end_io
|
||||
to keep track of pending io.
|
||||
|
@@ -1,6 +0,0 @@
|
||||
List of projects, ideas and pending bug fixes
|
||||
===============================================
|
||||
|
||||
o Check tables are an integer multiple of the underlying block size at
|
||||
table load time.
|
||||
|
@@ -1,240 +0,0 @@
|
||||
/*
|
||||
* linux/fs/seq_file.c
|
||||
*
|
||||
* helper functions for making syntetic files from sequences of records.
|
||||
* initial implementation -- AV, Oct 2001.
|
||||
*
|
||||
* Slight modifications to the original. Will be passed on to Al Viro in
|
||||
* the next few days.
|
||||
*/
|
||||
|
||||
#include <linux/malloc.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
/**
|
||||
* seq_open - initialize sequential file
|
||||
* @file: file we initialize
|
||||
* @op: method table describing the sequence
|
||||
*
|
||||
* seq_open() sets @file, associating it with a sequence described
|
||||
* by @op. @op->start() sets the iterator up and returns the first
|
||||
* element of sequence. @op->stop() shuts it down. @op->next()
|
||||
* returns the next element of sequence. @op->show() prints element
|
||||
* into the buffer. In case of error ->start() and ->next() return
|
||||
* ERR_PTR(error). In the end of sequence they return %NULL. ->show()
|
||||
* returns 0 in case of success and negative number in case of error.
|
||||
*/
|
||||
int seq_open(struct file *file, struct seq_operations *op, void *context)
|
||||
{
|
||||
struct seq_file *p = kmalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
memset(p, 0, sizeof(*p));
|
||||
sema_init(&p->sem, 1);
|
||||
p->op = op;
|
||||
p->context = context;
|
||||
file->private_data = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* seq_read - ->read() method for sequential files.
|
||||
* @file, @buf, @size, @ppos: see file_operations method
|
||||
*
|
||||
* Ready-made ->f_op->read()
|
||||
*/
|
||||
ssize_t seq_read(struct file *file, char *buf, size_t size, loff_t *ppos)
|
||||
{
|
||||
struct seq_file *m = (struct seq_file *)file->private_data;
|
||||
size_t copied = 0;
|
||||
loff_t pos;
|
||||
size_t n;
|
||||
void *p;
|
||||
int err = 0;
|
||||
|
||||
if (ppos != &file->f_pos)
|
||||
return -EPIPE;
|
||||
|
||||
down(&m->sem);
|
||||
/* grab buffer if we didn't have one */
|
||||
if (!m->buf) {
|
||||
m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
|
||||
if (!m->buf)
|
||||
goto Enomem;
|
||||
}
|
||||
/* if not empty - flush it first */
|
||||
if (m->count) {
|
||||
n = min(m->count, size);
|
||||
err = copy_to_user(buf, m->buf + m->from, n);
|
||||
if (err)
|
||||
goto Efault;
|
||||
m->count -= n;
|
||||
m->from += n;
|
||||
size -= n;
|
||||
buf += n;
|
||||
copied += n;
|
||||
if (!m->count)
|
||||
(*ppos)++;
|
||||
if (!size)
|
||||
goto Done;
|
||||
}
|
||||
/* we need at least one record in buffer */
|
||||
while (1) {
|
||||
pos = *ppos;
|
||||
p = m->op->start(m->context, &pos);
|
||||
err = PTR_ERR(p);
|
||||
if (!p || IS_ERR(p))
|
||||
break;
|
||||
err = m->op->show(m, p);
|
||||
if (err)
|
||||
break;
|
||||
if (m->count < m->size)
|
||||
goto Fill;
|
||||
m->op->stop(m->context, p);
|
||||
kfree(m->buf);
|
||||
m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
|
||||
if (!m->buf)
|
||||
goto Enomem;
|
||||
}
|
||||
m->op->stop(m->context, p);
|
||||
goto Done;
|
||||
Fill:
|
||||
/* they want more? let's try to get some more */
|
||||
while (m->count < size) {
|
||||
size_t offs = m->count;
|
||||
loff_t next = pos;
|
||||
p = m->op->next(m->context, p, &next);
|
||||
if (!p || IS_ERR(p)) {
|
||||
err = PTR_ERR(p);
|
||||
break;
|
||||
}
|
||||
err = m->op->show(m, p);
|
||||
if (err || m->count == m->size) {
|
||||
m->count = offs;
|
||||
break;
|
||||
}
|
||||
pos = next;
|
||||
}
|
||||
m->op->stop(m->context, p);
|
||||
n = min(m->count, size);
|
||||
err = copy_to_user(buf, m->buf, n);
|
||||
if (err)
|
||||
goto Efault;
|
||||
copied += n;
|
||||
m->count -= n;
|
||||
if (m->count)
|
||||
m->from = n;
|
||||
else
|
||||
pos++;
|
||||
*ppos = pos;
|
||||
Done:
|
||||
if (!copied)
|
||||
copied = err;
|
||||
up(&m->sem);
|
||||
return copied;
|
||||
Enomem:
|
||||
err = -ENOMEM;
|
||||
goto Done;
|
||||
Efault:
|
||||
err = -EFAULT;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
/**
|
||||
* seq_lseek - ->llseek() method for sequential files.
|
||||
* @file, @offset, @origin: see file_operations method
|
||||
*
|
||||
* Ready-made ->f_op->llseek()
|
||||
*/
|
||||
loff_t seq_lseek(struct file *file, loff_t offset, int origin)
|
||||
{
|
||||
struct seq_file *m = (struct seq_file *)file->private_data;
|
||||
long long retval = -EINVAL;
|
||||
|
||||
down(&m->sem);
|
||||
switch (origin) {
|
||||
case 1:
|
||||
offset += file->f_pos;
|
||||
case 0:
|
||||
if (offset < 0)
|
||||
break;
|
||||
if (offset != file->f_pos) {
|
||||
file->f_pos = offset;
|
||||
m->count = 0;
|
||||
}
|
||||
retval = offset;
|
||||
}
|
||||
up(&m->sem);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* seq_release - free the structures associated with sequential file.
|
||||
* @file: file in question
|
||||
* @inode: file->f_dentry->d_inode
|
||||
*
|
||||
* Frees the structures associated with sequential file; can be used
|
||||
* as ->f_op->release() if you don't have private data to destroy.
|
||||
*/
|
||||
int seq_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct seq_file *m = (struct seq_file *)file->private_data;
|
||||
kfree(m->buf);
|
||||
kfree(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* seq_escape - print string into buffer, escaping some characters
|
||||
* @m: target buffer
|
||||
* @s: string
|
||||
* @esc: set of characters that need escaping
|
||||
*
|
||||
* Puts string into buffer, replacing each occurence of character from
|
||||
* @esc with usual octal escape. Returns 0 in case of success, -1 - in
|
||||
* case of overflow.
|
||||
*/
|
||||
int seq_escape(struct seq_file *m, const char *s, const char *esc)
|
||||
{
|
||||
char *end = m->buf + m->size;
|
||||
char *p;
|
||||
char c;
|
||||
|
||||
for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) {
|
||||
if (!strchr(esc, c)) {
|
||||
*p++ = c;
|
||||
continue;
|
||||
}
|
||||
if (p + 3 < end) {
|
||||
*p++ = '\\';
|
||||
*p++ = '0' + ((c & 0300) >> 6);
|
||||
*p++ = '0' + ((c & 070) >> 3);
|
||||
*p++ = '0' + (c & 07);
|
||||
continue;
|
||||
}
|
||||
m->count = m->size;
|
||||
return -1;
|
||||
}
|
||||
m->count = p - m->buf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int seq_printf(struct seq_file *m, const char *f, ...)
|
||||
{
|
||||
va_list args;
|
||||
int len;
|
||||
|
||||
if (m->count < m->size) {
|
||||
va_start(args, f);
|
||||
len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
|
||||
va_end(args);
|
||||
if (m->count + len < m->size) {
|
||||
m->count += len;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
m->count = m->size;
|
||||
return -1;
|
||||
}
|
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Original file by Al Viro. This is a slight modification which I'll
|
||||
* pass on to Al Viro shortly.
|
||||
*/
|
||||
#ifndef _LINUX_SEQ_FILE_H
|
||||
#define _LINUX_SEQ_FILE_H
|
||||
#ifdef __KERNEL__
|
||||
|
||||
struct seq_operations;
|
||||
|
||||
struct seq_file {
|
||||
char *buf;
|
||||
size_t size;
|
||||
size_t from;
|
||||
size_t count;
|
||||
loff_t index;
|
||||
struct semaphore sem;
|
||||
struct seq_operations *op;
|
||||
void *context;
|
||||
};
|
||||
|
||||
struct seq_operations {
|
||||
void * (*start) (void *context, loff_t *pos);
|
||||
void (*stop) (void *context, void *v);
|
||||
void * (*next) (void *context, void *v, loff_t *pos);
|
||||
int (*show) (struct seq_file *m, void *v);
|
||||
};
|
||||
|
||||
int seq_open(struct file *, struct seq_operations *, void *context);
|
||||
ssize_t seq_read(struct file *, char *, size_t, loff_t *);
|
||||
loff_t seq_lseek(struct file *, loff_t, int);
|
||||
int seq_release(struct inode *, struct file *);
|
||||
int seq_escape(struct seq_file *, const char *, const char *);
|
||||
|
||||
static inline int seq_putc(struct seq_file *m, char c)
|
||||
{
|
||||
if (m->count < m->size) {
|
||||
m->buf[m->count++] = c;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int seq_puts(struct seq_file *m, const char *s)
|
||||
{
|
||||
int len = strlen(s);
|
||||
if (m->count + len < m->size) {
|
||||
memcpy(m->buf + m->count, s, len);
|
||||
m->count += len;
|
||||
return 0;
|
||||
}
|
||||
m->count = m->size;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int seq_printf(struct seq_file *, const char *, ...)
|
||||
__attribute__ ((format (printf,2,3)));
|
||||
|
||||
#endif
|
||||
#endif
|
@@ -1,30 +0,0 @@
|
||||
FILES
|
||||
-----
|
||||
|
||||
setup-uml - script to build a user mode linux system, with the lvm driver
|
||||
symbolically linked back to the LVM dir so I can work from CVS.
|
||||
|
||||
uml-lvm.patch - patch to enable lvm in the uml configuration
|
||||
|
||||
uml.patch.bz2 - uml patch from
|
||||
http://sourceforge.net/project/showfiles.php?group_id=429
|
||||
|
||||
config-uml - .config which turns on LVM
|
||||
|
||||
|
||||
RUNNING
|
||||
-------
|
||||
|
||||
o checkout an LVM dir for use with uml
|
||||
make sure you've got a copy of a root filesystem kicking about
|
||||
|
||||
o edit the variables at the top of 'setup'
|
||||
|
||||
o run setup-uml
|
||||
|
||||
o move to your uml dir and run lvm-install as root
|
||||
|
||||
o then run the 'up' script to run uml
|
||||
|
||||
o if you want to rebuild uml after changing the LVM driver just change into
|
||||
the linux directory and do a 'make linux ARCH=um'. Don't forget the ARCH=um.
|
@@ -1,299 +0,0 @@
|
||||
#
|
||||
# Automatically generated by make menuconfig: don't edit
|
||||
#
|
||||
CONFIG_USERMODE=y
|
||||
# CONFIG_ISA is not set
|
||||
# CONFIG_SBUS is not set
|
||||
# CONFIG_PCI is not set
|
||||
CONFIG_UID16=y
|
||||
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
|
||||
|
||||
#
|
||||
# Code maturity level options
|
||||
#
|
||||
CONFIG_EXPERIMENTAL=y
|
||||
|
||||
#
|
||||
# Multi-device support (RAID and LVM)
|
||||
#
|
||||
CONFIG_MD=y
|
||||
# CONFIG_BLK_DEV_MD is not set
|
||||
# CONFIG_MD_LINEAR is not set
|
||||
# CONFIG_MD_RAID0 is not set
|
||||
# CONFIG_MD_RAID1 is not set
|
||||
# CONFIG_MD_RAID5 is not set
|
||||
# CONFIG_BLK_DEV_LVM is not set
|
||||
CONFIG_BLK_DEV_DM=y
|
||||
|
||||
#
|
||||
# General Setup
|
||||
#
|
||||
CONFIG_STDIO_CONSOLE=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_SYSVIPC=y
|
||||
CONFIG_BSD_PROCESS_ACCT=y
|
||||
CONFIG_SYSCTL=y
|
||||
CONFIG_BINFMT_AOUT=y
|
||||
CONFIG_BINFMT_ELF=y
|
||||
CONFIG_BINFMT_MISC=y
|
||||
CONFIG_UNIX98_PTYS=y
|
||||
CONFIG_UNIX98_PTY_COUNT=256
|
||||
CONFIG_SSL=y
|
||||
CONFIG_HOSTFS=m
|
||||
CONFIG_MCONSOLE=y
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
|
||||
#
|
||||
# Loadable module support
|
||||
#
|
||||
CONFIG_MODULES=y
|
||||
# CONFIG_KMOD is not set
|
||||
|
||||
#
|
||||
# Devices
|
||||
#
|
||||
CONFIG_BLK_DEV_UBD=y
|
||||
# CONFIG_BLK_DEV_UBD_SYNC is not set
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_NBD=y
|
||||
CONFIG_BLK_DEV_RAM=y
|
||||
CONFIG_BLK_DEV_RAM_SIZE=4096
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
# CONFIG_MMAPPER is not set
|
||||
|
||||
#
|
||||
# Networking options
|
||||
#
|
||||
# CONFIG_PACKET is not set
|
||||
CONFIG_NETLINK=y
|
||||
# CONFIG_RTNETLINK is not set
|
||||
# CONFIG_NETLINK_DEV is not set
|
||||
# CONFIG_NETFILTER is not set
|
||||
# CONFIG_FILTER is not set
|
||||
CONFIG_UNIX=y
|
||||
CONFIG_INET=y
|
||||
# CONFIG_IP_MULTICAST is not set
|
||||
# CONFIG_IP_ADVANCED_ROUTER is not set
|
||||
# CONFIG_IP_PNP is not set
|
||||
# CONFIG_NET_IPIP is not set
|
||||
# CONFIG_NET_IPGRE is not set
|
||||
# CONFIG_INET_ECN is not set
|
||||
# CONFIG_SYN_COOKIES is not set
|
||||
# CONFIG_IPV6 is not set
|
||||
# CONFIG_KHTTPD is not set
|
||||
# CONFIG_ATM is not set
|
||||
# CONFIG_IPX is not set
|
||||
# CONFIG_ATALK is not set
|
||||
# CONFIG_DECNET is not set
|
||||
# CONFIG_BRIDGE is not set
|
||||
# CONFIG_X25 is not set
|
||||
# CONFIG_LAPB is not set
|
||||
# CONFIG_LLC is not set
|
||||
# CONFIG_NET_DIVERT is not set
|
||||
# CONFIG_ECONET is not set
|
||||
# CONFIG_WAN_ROUTER is not set
|
||||
# CONFIG_NET_FASTROUTE is not set
|
||||
# CONFIG_NET_HW_FLOWCONTROL is not set
|
||||
|
||||
#
|
||||
# QoS and/or fair queueing
|
||||
#
|
||||
# CONFIG_NET_SCHED is not set
|
||||
|
||||
#
|
||||
# Network drivers
|
||||
#
|
||||
|
||||
#
|
||||
# ARCnet devices
|
||||
#
|
||||
# CONFIG_ARCNET is not set
|
||||
CONFIG_DUMMY=y
|
||||
# CONFIG_BONDING is not set
|
||||
# CONFIG_EQUALIZER is not set
|
||||
CONFIG_TUN=y
|
||||
CONFIG_ETHERTAP=y
|
||||
|
||||
#
|
||||
# Ethernet (10 or 100Mbit)
|
||||
#
|
||||
# CONFIG_NET_ETHERNET is not set
|
||||
|
||||
#
|
||||
# Ethernet (1000 Mbit)
|
||||
#
|
||||
# CONFIG_ACENIC is not set
|
||||
# CONFIG_ACENIC_OMIT_TIGON_I is not set
|
||||
# CONFIG_DL2K is not set
|
||||
# CONFIG_MYRI_SBUS is not set
|
||||
# CONFIG_HAMACHI is not set
|
||||
# CONFIG_YELLOWFIN is not set
|
||||
# CONFIG_SK98LIN is not set
|
||||
# CONFIG_FDDI is not set
|
||||
# CONFIG_HIPPI is not set
|
||||
# CONFIG_PLIP is not set
|
||||
CONFIG_PPP=y
|
||||
# CONFIG_PPP_MULTILINK is not set
|
||||
# CONFIG_PPP_FILTER is not set
|
||||
# CONFIG_PPP_ASYNC is not set
|
||||
# CONFIG_PPP_SYNC_TTY is not set
|
||||
# CONFIG_PPP_DEFLATE is not set
|
||||
# CONFIG_PPP_BSDCOMP is not set
|
||||
# CONFIG_PPPOE is not set
|
||||
CONFIG_SLIP=y
|
||||
# CONFIG_SLIP_COMPRESSED is not set
|
||||
# CONFIG_SLIP_SMART is not set
|
||||
# CONFIG_SLIP_MODE_SLIP6 is not set
|
||||
|
||||
#
|
||||
# Wireless LAN (non-hamradio)
|
||||
#
|
||||
# CONFIG_NET_RADIO is not set
|
||||
|
||||
#
|
||||
# Token Ring devices
|
||||
#
|
||||
# CONFIG_TR is not set
|
||||
# CONFIG_NET_FC is not set
|
||||
# CONFIG_RCPCI is not set
|
||||
# CONFIG_SHAPER is not set
|
||||
|
||||
#
|
||||
# Wan interfaces
|
||||
#
|
||||
# CONFIG_WAN is not set
|
||||
|
||||
#
|
||||
# Network device support
|
||||
#
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_UML_NET=y
|
||||
CONFIG_UML_NET_ETHERTAP=y
|
||||
CONFIG_UML_NET_SLIP=y
|
||||
CONFIG_UML_NET_DAEMON=y
|
||||
CONFIG_UML_NET_MCAST=y
|
||||
CONFIG_ETHERTAP=y
|
||||
CONFIG_TUN=y
|
||||
|
||||
#
|
||||
# File systems
|
||||
#
|
||||
CONFIG_QUOTA=y
|
||||
CONFIG_AUTOFS_FS=m
|
||||
CONFIG_AUTOFS4_FS=m
|
||||
CONFIG_REISERFS_FS=m
|
||||
# CONFIG_REISERFS_CHECK is not set
|
||||
# CONFIG_ADFS_FS is not set
|
||||
# CONFIG_ADFS_FS_RW is not set
|
||||
# CONFIG_AFFS_FS is not set
|
||||
# CONFIG_HFS_FS is not set
|
||||
# CONFIG_BFS_FS is not set
|
||||
CONFIG_FAT_FS=m
|
||||
CONFIG_MSDOS_FS=m
|
||||
CONFIG_UMSDOS_FS=m
|
||||
CONFIG_VFAT_FS=m
|
||||
# CONFIG_EFS_FS is not set
|
||||
# CONFIG_JFFS_FS is not set
|
||||
# CONFIG_CRAMFS is not set
|
||||
# CONFIG_TMPFS is not set
|
||||
# CONFIG_RAMFS is not set
|
||||
CONFIG_ISO9660_FS=m
|
||||
# CONFIG_JOLIET is not set
|
||||
CONFIG_MINIX_FS=m
|
||||
# CONFIG_VXFS_FS is not set
|
||||
# CONFIG_NTFS_FS is not set
|
||||
# CONFIG_NTFS_RW is not set
|
||||
# CONFIG_HPFS_FS is not set
|
||||
CONFIG_PROC_FS=y
|
||||
CONFIG_DEVFS_FS=y
|
||||
CONFIG_DEVFS_MOUNT=y
|
||||
# CONFIG_DEVFS_DEBUG is not set
|
||||
CONFIG_DEVPTS_FS=y
|
||||
# CONFIG_QNX4FS_FS is not set
|
||||
# CONFIG_QNX4FS_RW is not set
|
||||
# CONFIG_ROMFS_FS is not set
|
||||
CONFIG_EXT2_FS=y
|
||||
# CONFIG_SYSV_FS is not set
|
||||
# CONFIG_UDF_FS is not set
|
||||
# CONFIG_UDF_RW is not set
|
||||
# CONFIG_UFS_FS is not set
|
||||
# CONFIG_UFS_FS_WRITE is not set
|
||||
|
||||
#
|
||||
# Network File Systems
|
||||
#
|
||||
# CONFIG_CODA_FS is not set
|
||||
# CONFIG_NFS_FS is not set
|
||||
# CONFIG_NFS_V3 is not set
|
||||
# CONFIG_ROOT_NFS is not set
|
||||
# CONFIG_NFSD is not set
|
||||
# CONFIG_NFSD_V3 is not set
|
||||
# CONFIG_SUNRPC is not set
|
||||
# CONFIG_LOCKD is not set
|
||||
# CONFIG_SMB_FS is not set
|
||||
# CONFIG_NCP_FS is not set
|
||||
# CONFIG_NCPFS_PACKET_SIGNING is not set
|
||||
# CONFIG_NCPFS_IOCTL_LOCKING is not set
|
||||
# CONFIG_NCPFS_STRONG is not set
|
||||
# CONFIG_NCPFS_NFS_NS is not set
|
||||
# CONFIG_NCPFS_OS2_NS is not set
|
||||
# CONFIG_NCPFS_SMALLDOS is not set
|
||||
# CONFIG_NCPFS_NLS is not set
|
||||
# CONFIG_NCPFS_EXTRAS is not set
|
||||
|
||||
#
|
||||
# Partition Types
|
||||
#
|
||||
# CONFIG_PARTITION_ADVANCED is not set
|
||||
CONFIG_MSDOS_PARTITION=y
|
||||
# CONFIG_SMB_NLS is not set
|
||||
CONFIG_NLS=y
|
||||
|
||||
#
|
||||
# Native Language Support
|
||||
#
|
||||
CONFIG_NLS_DEFAULT="iso8859-1"
|
||||
# CONFIG_NLS_CODEPAGE_437 is not set
|
||||
# CONFIG_NLS_CODEPAGE_737 is not set
|
||||
# CONFIG_NLS_CODEPAGE_775 is not set
|
||||
# CONFIG_NLS_CODEPAGE_850 is not set
|
||||
# CONFIG_NLS_CODEPAGE_852 is not set
|
||||
# CONFIG_NLS_CODEPAGE_855 is not set
|
||||
# CONFIG_NLS_CODEPAGE_857 is not set
|
||||
# CONFIG_NLS_CODEPAGE_860 is not set
|
||||
# CONFIG_NLS_CODEPAGE_861 is not set
|
||||
# CONFIG_NLS_CODEPAGE_862 is not set
|
||||
# CONFIG_NLS_CODEPAGE_863 is not set
|
||||
# CONFIG_NLS_CODEPAGE_864 is not set
|
||||
# CONFIG_NLS_CODEPAGE_865 is not set
|
||||
# CONFIG_NLS_CODEPAGE_866 is not set
|
||||
# CONFIG_NLS_CODEPAGE_869 is not set
|
||||
# CONFIG_NLS_CODEPAGE_936 is not set
|
||||
# CONFIG_NLS_CODEPAGE_950 is not set
|
||||
# CONFIG_NLS_CODEPAGE_932 is not set
|
||||
# CONFIG_NLS_CODEPAGE_949 is not set
|
||||
# CONFIG_NLS_CODEPAGE_874 is not set
|
||||
# CONFIG_NLS_ISO8859_8 is not set
|
||||
# CONFIG_NLS_CODEPAGE_1251 is not set
|
||||
# CONFIG_NLS_ISO8859_1 is not set
|
||||
# CONFIG_NLS_ISO8859_2 is not set
|
||||
# CONFIG_NLS_ISO8859_3 is not set
|
||||
# CONFIG_NLS_ISO8859_4 is not set
|
||||
# CONFIG_NLS_ISO8859_5 is not set
|
||||
# CONFIG_NLS_ISO8859_6 is not set
|
||||
# CONFIG_NLS_ISO8859_7 is not set
|
||||
# CONFIG_NLS_ISO8859_9 is not set
|
||||
# CONFIG_NLS_ISO8859_13 is not set
|
||||
# CONFIG_NLS_ISO8859_14 is not set
|
||||
# CONFIG_NLS_ISO8859_15 is not set
|
||||
# CONFIG_NLS_KOI8_R is not set
|
||||
# CONFIG_NLS_KOI8_U is not set
|
||||
# CONFIG_NLS_UTF8 is not set
|
||||
|
||||
#
|
||||
# Kernel hacking
|
||||
#
|
||||
CONFIG_DEBUGSYM=y
|
||||
CONFIG_PT_PROXY=y
|
||||
# CONFIG_GPROF is not set
|
||||
# CONFIG_GCOV is not set
|
@@ -1,179 +0,0 @@
|
||||
#! /usr/bin/perl -w
|
||||
|
||||
use Cwd;
|
||||
|
||||
##############################
|
||||
# Start user configurable bit
|
||||
##############################
|
||||
|
||||
# Please use absolute paths too.
|
||||
# you can't use ~'s in your paths here.
|
||||
|
||||
# the directory where you've checked out lvm, keep a seperate copy for uml,
|
||||
# the uml kernel will have links to these files
|
||||
$lvm_src="/home/thornber/sistina/LVM2";
|
||||
|
||||
|
||||
# the debian root image, get it from here:
|
||||
# http://prdownloads.sourceforge.net/user-mode-linux/root_fs_debian2.2_small.bz2
|
||||
# unzip it once you've downloaded it
|
||||
$root_fs="/home/thornber/uml/root_fs_debian2.2_small";
|
||||
|
||||
# these are 100 Meg files created with dd
|
||||
# these become our PV's /dev/ubd/[1-4]
|
||||
# I sometimes use ubd/1 as swap though.
|
||||
@block_devices = ("/home/thornber/uml/scratch1",
|
||||
"/home/thornber/uml/scratch2",
|
||||
"/home/thornber/uml/scratch3",
|
||||
"/home/thornber/uml/scratch4");
|
||||
|
||||
# directory where uml will be built, and the up, lvm-install scripts will
|
||||
# be placed
|
||||
$dest_dir="/home/thornber/builds/uml-lvm2";
|
||||
|
||||
# It must be 2.4.8, can be .gz or .bz2
|
||||
$kernel_tarball="/home/thornber/packages/2.4/linux-2.4.9.tar";
|
||||
|
||||
###############################
|
||||
# end of user configurable bit
|
||||
###############################
|
||||
|
||||
|
||||
$wd = cwd;
|
||||
$uml_patch = $wd . "/uml.patch.bz2";
|
||||
$lvm_uml_patch = $wd . "/uml-lvm.patch";
|
||||
$driver = $lvm_src . "/driver/device-mapper";
|
||||
|
||||
|
||||
# check we've got everything we need
|
||||
&check_file($root_fs);
|
||||
&check_dir($lvm_src);
|
||||
&check_file($kernel_tarball);
|
||||
&check_dir($dest_dir);
|
||||
&check_file($uml_patch);
|
||||
&check_file($lvm_uml_patch);
|
||||
|
||||
|
||||
chdir($dest_dir);
|
||||
&extract_kernel($dest_dir, $kernel_tarball);
|
||||
chdir("linux");
|
||||
&run_command("bzip2 -dc $uml_patch | patch -p1", "patching kernel with uml");
|
||||
&run_command("patch -p1 < $lvm_uml_patch", "enabling LVM driver");
|
||||
|
||||
chdir("$dest_dir/linux");
|
||||
|
||||
&run_command("cd include/linux; ln -s $driver/device-mapper.h",
|
||||
"linking device-mapper.h");
|
||||
|
||||
&run_command("cd drivers/md; ln -s $driver/dm.h", "linking dm.h");
|
||||
&run_command("cd drivers/md; ln -s $driver/dm-fs.c", "linking dm-fs.c");
|
||||
&run_command("cd drivers/md; ln -s $driver/dm-table.c", "linking dm-table.c");
|
||||
&run_command("cd drivers/md; ln -s $driver/dm-target.c",
|
||||
"linking dm-target.c");
|
||||
&run_command("cd drivers/md; ln -s $driver/dm.c", "linking dm.c");
|
||||
|
||||
chdir("$dest_dir/linux");
|
||||
&run_command("make oldconfig ARCH=um", "making oldconfig ARCH=um");
|
||||
&run_command("make dep ARCH=um", "making dependencies");
|
||||
&run_command("make linux ARCH=um", "building linux uml");
|
||||
|
||||
chdir($dest_dir);
|
||||
&run_command("ln -s $dest_dir/linux/linux uml", "creating link for linux");
|
||||
|
||||
chdir($dest_dir);
|
||||
&run_command("ln -s $root_fs ./root_fs", "linking root filesystem");
|
||||
|
||||
chdir($dest_dir);
|
||||
&link_devices();
|
||||
&write_up();
|
||||
&run_command("mkdir root_fs_mnt");
|
||||
&write_lvm_install();
|
||||
|
||||
print "Dont forget to run $dest_dir/lvm-install as root\n";
|
||||
|
||||
|
||||
sub write_lvm_install {
|
||||
open(OUT, "> lvm-install");
|
||||
print OUT "#! /bin/sh\n\n";
|
||||
print OUT <<"end";
|
||||
mount root_fs root_fs_mnt -o loop
|
||||
cd $lvm_src; make install; cd $dest_dir
|
||||
umount root_fs_mnt
|
||||
end
|
||||
|
||||
close OUT;
|
||||
system "chmod +x lvm-install";
|
||||
}
|
||||
|
||||
|
||||
sub write_up {
|
||||
open(UP, "> up");
|
||||
print UP "#! /bin/sh\n\n./uml ";
|
||||
$count = 1;
|
||||
for $d (@block_devices) {
|
||||
print UP "ubd$count=ubd$count ";
|
||||
$count++;
|
||||
}
|
||||
print UP "\n";
|
||||
close UP;
|
||||
system("chmod +x up");
|
||||
}
|
||||
|
||||
sub link_devices {
|
||||
$count = 1;
|
||||
foreach $d (@block_devices) {
|
||||
&run_command("ln -s $d ubd$count",
|
||||
"linking block device ubd$count");
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
sub extract_kernel {
|
||||
my($dest, $tb) = @_;
|
||||
my($cmd);
|
||||
if($tb =~ m/\.bz2/) {
|
||||
$cmd = "tar Ixf $tb";
|
||||
|
||||
} elsif($tb =~ m/\.gz/) {
|
||||
$cmd = "tar zxf $tb";
|
||||
|
||||
} else {
|
||||
$cmd = "tar xf $tb";
|
||||
}
|
||||
|
||||
&run_command($cmd, "extracting kernel");
|
||||
}
|
||||
|
||||
sub run_command {
|
||||
my($cmd) = shift;
|
||||
my($desc) = shift;
|
||||
my($r);
|
||||
print STDERR $desc, " ... ";
|
||||
$r = system("$cmd > /dev/null");
|
||||
if(!$r) {
|
||||
print STDERR "done.\n";
|
||||
return;
|
||||
} else {
|
||||
print STDERR "failed.\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
sub check_file {
|
||||
$f = shift;
|
||||
if(! -e $f) {
|
||||
print STDERR "couldn't find $f\n";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
sub check_dir {
|
||||
$f = shift;
|
||||
if(! -e $f || ! -d $f) {
|
||||
print STDERR "couldn't find a directory called $f\n";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,30 +0,0 @@
|
||||
--- uml_build/arch/um/config.in.orig Tue Jan 2 14:33:42 2001
|
||||
+++ uml_build/arch/um/config.in Tue Jan 2 14:35:42 2001
|
||||
@@ -15,6 +15,8 @@
|
||||
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
|
||||
endmenu
|
||||
|
||||
+source drivers/md/Config.in
|
||||
+
|
||||
mainmenu_option next_comment
|
||||
comment 'Processor features'
|
||||
bool 'Symmetric multi-processing support' CONFIG_SMP
|
||||
--- linux/drivers/md/Config.in.orig Tue Aug 21 14:18:30 2001
|
||||
+++ linux/drivers/md/Config.in Tue Aug 21 14:19:08 2001
|
||||
@@ -14,4 +14,6 @@
|
||||
|
||||
dep_tristate ' Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM $CONFIG_MD
|
||||
|
||||
+dep_tristate ' Device mapper support' CONFIG_BLK_DEV_DM $CONFIG_MD
|
||||
+
|
||||
endmenu
|
||||
--- linux/drivers/md/Makefile.orig Tue Aug 21 14:19:14 2001
|
||||
+++ linux/drivers/md/Makefile Tue Aug 21 14:20:06 2001
|
||||
@@ -19,6 +19,7 @@
|
||||
obj-$(CONFIG_MD_RAID5) += raid5.o xor.o
|
||||
obj-$(CONFIG_BLK_DEV_MD) += md.o
|
||||
obj-$(CONFIG_BLK_DEV_LVM) += lvm-mod.o
|
||||
+obj-$(CONFIG_BLK_DEV_DM) += dm.o dm-table.o dm-target.o dm-fs.o dm-parse.o
|
||||
|
||||
include $(TOPDIR)/Rules.make
|
||||
|
Binary file not shown.
@@ -1,5 +1,9 @@
|
||||
../lib/activate/activate.h
|
||||
../lib/cache/cache.h
|
||||
../lib/commands/errors.h
|
||||
../lib/commands/toolcontext.h
|
||||
../lib/config/config.h
|
||||
../lib/config/defaults.h
|
||||
../lib/datastruct/bitset.h
|
||||
../lib/datastruct/btree.h
|
||||
../lib/datastruct/hash.h
|
||||
@@ -8,15 +12,25 @@
|
||||
../lib/device/dev-cache.h
|
||||
../lib/device/device.h
|
||||
../lib/display/display.h
|
||||
../lib/display/display_formats.h
|
||||
../lib/filters/filter-composite.h
|
||||
../lib/filters/filter-persistent.h
|
||||
../lib/filters/filter-regex.h
|
||||
../lib/filters/filter.h
|
||||
../lib/format1/format1.h
|
||||
../lib/format1/lvm1-label.h
|
||||
../lib/format_text/format-text.h
|
||||
../lib/label/label.h
|
||||
../lib/locking/locking.h
|
||||
../lib/log/log.h
|
||||
../lib/metadata/metadata.h
|
||||
../lib/mm/dbg_malloc.h
|
||||
../lib/mm/pool.h
|
||||
../lib/mm/xlate.h
|
||||
../lib/misc/crc.h
|
||||
../lib/misc/lib.h
|
||||
../lib/misc/lvm-file.h
|
||||
../lib/misc/lvm-string.h
|
||||
../lib/misc/sharedlib.h
|
||||
../lib/regex/matcher.h
|
||||
../lib/uuid/uuid.h
|
||||
|
@@ -31,11 +31,13 @@ all: .symlinks_created
|
||||
for i in `cat .symlinks`; do $(LN_S) $$i ; done
|
||||
touch $@
|
||||
|
||||
clean:
|
||||
|
||||
distclean:
|
||||
find . -maxdepth 1 -type l -exec $(RM) \{\} \;
|
||||
$(RM) Makefile .include_symlinks .symlinks_created
|
||||
|
||||
.PHONY: clean distclean all
|
||||
clean:
|
||||
|
||||
install:
|
||||
|
||||
.PHONY: clean distclean all install
|
||||
|
||||
|
@@ -8,9 +8,16 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
ifeq ("@LVM1@", "shared")
|
||||
SUBDIRS = format1
|
||||
endif
|
||||
|
||||
SOURCES=\
|
||||
activate/activate.c \
|
||||
activate/dev_manager.c \
|
||||
activate/fs.c \
|
||||
cache/cache.c \
|
||||
commands/toolcontext.c \
|
||||
config/config.c \
|
||||
datastruct/bitset.c \
|
||||
datastruct/btree.c \
|
||||
@@ -23,21 +30,44 @@ SOURCES=\
|
||||
filters/filter-persistent.c \
|
||||
filters/filter-regex.c \
|
||||
filters/filter.c \
|
||||
format1/disk-rep.c \
|
||||
format1/format1.c \
|
||||
format1/import-export.c \
|
||||
format1/layout.c \
|
||||
format1/vg_number.c \
|
||||
format_text/archive.c \
|
||||
format_text/export.c \
|
||||
format_text/flags.c \
|
||||
format_text/format-text.c \
|
||||
format_text/import.c \
|
||||
format_text/import_vsn1.c \
|
||||
format_text/text_label.c \
|
||||
label/label.c \
|
||||
locking/external_locking.c \
|
||||
locking/file_locking.c \
|
||||
locking/locking.c \
|
||||
locking/no_locking.c \
|
||||
log/log.c \
|
||||
metadata/lv_manip.c \
|
||||
metadata/merge.c \
|
||||
metadata/metadata.c \
|
||||
metadata/pv_map.c \
|
||||
metadata/snapshot_manip.c \
|
||||
misc/crc.c \
|
||||
misc/lvm-file.c \
|
||||
misc/sharedlib.c \
|
||||
mm/dbg_malloc.c \
|
||||
mm/pool.c \
|
||||
regex/matcher.c \
|
||||
regex/parse_rx.c \
|
||||
regex/ttree.c \
|
||||
uuid/uuid.c
|
||||
uuid/uuid.c
|
||||
|
||||
ifeq ("@LVM1@", "internal")
|
||||
SOURCES+=\
|
||||
format1/disk-rep.c \
|
||||
format1/format1.c \
|
||||
format1/import-export.c \
|
||||
format1/import-extents.c \
|
||||
format1/layout.c \
|
||||
format1/lvm1-label.c \
|
||||
format1/vg_number.c
|
||||
endif
|
||||
|
||||
TARGETS=liblvm.a
|
||||
|
||||
|
@@ -1 +0,0 @@
|
||||
Base library directory
|
@@ -4,273 +4,220 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "metadata.h"
|
||||
#include "activate.h"
|
||||
#include "display.h"
|
||||
#include "log.h"
|
||||
#include "fs.h"
|
||||
#include "lvm-string.h"
|
||||
#include "pool.h"
|
||||
#include "toolcontext.h"
|
||||
#include "dev_manager.h"
|
||||
|
||||
#include <devmapper/libdevmapper.h>
|
||||
#include <limits.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static void _build_lv_name(char *buffer, size_t s, struct logical_volume *lv)
|
||||
#define _skip(fmt, args...) log_very_verbose("Skipping: " fmt , ## args)
|
||||
|
||||
static int _activation = 1;
|
||||
|
||||
void set_activation(int activation)
|
||||
{
|
||||
snprintf(buffer, s, "%s_%s", lv->vg->name, lv->name);
|
||||
if (activation == _activation)
|
||||
return;
|
||||
|
||||
_activation = activation;
|
||||
if (_activation)
|
||||
log_verbose("Activation enabled. Device-mapper kernel "
|
||||
"driver will be used.");
|
||||
else
|
||||
log_verbose("Activation disabled. No device-mapper "
|
||||
"interaction will be attempted.");
|
||||
}
|
||||
|
||||
static struct dm_task *_setup_task(struct logical_volume *lv, int task)
|
||||
int activation()
|
||||
{
|
||||
char name[128];
|
||||
struct dm_task *dmt;
|
||||
|
||||
if (!(dmt = dm_task_create(task))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_build_lv_name(name, sizeof(name), lv);
|
||||
dm_task_set_name(dmt, name);
|
||||
|
||||
return dmt;
|
||||
return _activation;
|
||||
}
|
||||
|
||||
static struct dm_task *_info(struct logical_volume *lv)
|
||||
int library_version(char *version, size_t size)
|
||||
{
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
if (!dm_get_library_version(version, size))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int driver_version(char *version, size_t size)
|
||||
{
|
||||
int r = 0;
|
||||
struct dm_task *dmt;
|
||||
|
||||
if (!(dmt = _setup_task(lv, DM_DEVICE_INFO))) {
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
log_very_verbose("Getting driver version");
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_VERSION))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dm_task_run(dmt)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!dm_task_run(dmt))
|
||||
log_error("Failed to get driver version");
|
||||
|
||||
return dmt;
|
||||
|
||||
bad:
|
||||
dm_task_destroy(dmt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int lv_active(struct logical_volume *lv)
|
||||
{
|
||||
int r = -1;
|
||||
struct dm_task *dmt;
|
||||
|
||||
if (!(dmt = _info(lv))) {
|
||||
stack;
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!dm_task_exists(dmt, &r)) {
|
||||
stack;
|
||||
if (!dm_task_get_driver_version(dmt, version, size))
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
|
||||
int lv_open_count(struct logical_volume *lv)
|
||||
{
|
||||
int r = -1;
|
||||
struct dm_task *dmt;
|
||||
|
||||
if (!(dmt = _info(lv))) {
|
||||
stack;
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!dm_task_open_count(dmt, &r)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a target for the next contiguous run of
|
||||
* extents.
|
||||
* Returns 1 if info structure populated, else 0 on failure.
|
||||
*/
|
||||
static int _emit_target(struct dm_task *dmt, struct logical_volume *lv,
|
||||
unsigned int *ple)
|
||||
{
|
||||
char params[1024];
|
||||
unsigned int le = *ple;
|
||||
uint64_t esize = lv->vg->extent_size;
|
||||
int i, count = 0;
|
||||
struct pe_specifier *pes, *first = NULL;
|
||||
|
||||
for (i = le; i < lv->le_count; i++) {
|
||||
pes = lv->map + i;
|
||||
|
||||
if (!first)
|
||||
first = pes;
|
||||
|
||||
else if (first->pv != pes->pv || first->pe != pes->pe + 1)
|
||||
break; /* no longer contig. */
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
snprintf(params, sizeof(params), "%s %" PRIu64,
|
||||
dev_name(first->pv->dev),
|
||||
first->pv->pe_start + (esize * first->pe));
|
||||
|
||||
if (!dm_task_add_target(dmt, esize * le, esize * count,
|
||||
"linear", params)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*ple = i;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _load(struct logical_volume *lv, int task)
|
||||
{
|
||||
int r = 0;
|
||||
uint32_t le = 0;
|
||||
struct dm_task *dmt;
|
||||
|
||||
if (!(dmt = _setup_task(lv, task))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Merge adjacent extents.
|
||||
*/
|
||||
while (le < lv->le_count) {
|
||||
if (!_emit_target(dmt, lv, &le)) {
|
||||
log_error("Unable to activate logical volume '%s'",
|
||||
lv->name);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(r = dm_task_run(dmt)))
|
||||
stack;
|
||||
|
||||
out:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* FIXME: Always display error msg */
|
||||
int lv_activate(struct logical_volume *lv)
|
||||
{
|
||||
return _load(lv, DM_DEVICE_CREATE) && fs_add_lv(lv);
|
||||
}
|
||||
|
||||
int _suspend(struct logical_volume *lv, int sus)
|
||||
int lv_info(struct logical_volume *lv, struct dm_info *info)
|
||||
{
|
||||
int r;
|
||||
struct dm_task *dmt;
|
||||
int task = sus ? DM_DEVICE_SUSPEND : DM_DEVICE_RESUME;
|
||||
struct dev_manager *dm;
|
||||
|
||||
if (!(dmt = _setup_task(lv, task))) {
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(r = dm_task_run(dmt)))
|
||||
log_err("Couldn't %s device '%s'", sus ? "suspend" : "resume",
|
||||
lv->name);
|
||||
if (!(r = dev_manager_info(dm, lv, info)))
|
||||
stack;
|
||||
|
||||
dm_task_destroy(dmt);
|
||||
dev_manager_destroy(dm);
|
||||
return r;
|
||||
}
|
||||
|
||||
int lv_reactivate(struct logical_volume *lv)
|
||||
/*
|
||||
* Returns 1 if percent set, else 0 on failure.
|
||||
*/
|
||||
int lv_snapshot_percent(struct logical_volume *lv, float *percent)
|
||||
{
|
||||
int r;
|
||||
if (!_suspend(lv, 1)) {
|
||||
struct dev_manager *dm;
|
||||
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
if (!(dm = dev_manager_create(lv->vg->name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = _load(lv, DM_DEVICE_RELOAD);
|
||||
|
||||
if (!_suspend(lv, 0)) {
|
||||
if (!(r = dev_manager_snapshot_percent(dm, lv, percent)))
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_manager_destroy(dm);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int lv_deactivate(struct logical_volume *lv)
|
||||
static int _lv_active(struct logical_volume *lv)
|
||||
{
|
||||
struct dm_info info;
|
||||
|
||||
if (!lv_info(lv, &info)) {
|
||||
stack;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return info.exists;
|
||||
}
|
||||
|
||||
static int _lv_open_count(struct logical_volume *lv)
|
||||
{
|
||||
struct dm_info info;
|
||||
|
||||
if (!lv_info(lv, &info)) {
|
||||
stack;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return info.open_count;
|
||||
}
|
||||
|
||||
/* FIXME Need to detect and handle an lv rename */
|
||||
static int _lv_activate(struct logical_volume *lv)
|
||||
{
|
||||
int r;
|
||||
struct dm_task *dmt;
|
||||
struct dev_manager *dm;
|
||||
|
||||
if (!(dmt = _setup_task(lv, DM_DEVICE_REMOVE))) {
|
||||
if (!(dm = dev_manager_create(lv->vg->name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(r = dm_task_run(dmt)))
|
||||
if (!(r = dev_manager_activate(dm, lv)))
|
||||
stack;
|
||||
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
fs_del_lv(lv);
|
||||
|
||||
dev_manager_destroy(dm);
|
||||
return r;
|
||||
}
|
||||
|
||||
int activate_lvs_in_vg(struct volume_group *vg)
|
||||
static int _lv_deactivate(struct logical_volume *lv)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
int count = 0;
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = &(list_item(lvh, struct lv_list)->lv);
|
||||
|
||||
count += (!lv_active(lv) && lv_activate(lv));
|
||||
if (!(dm = dev_manager_create(lv->vg->name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return count;
|
||||
if (!(r = dev_manager_deactivate(dm, lv)))
|
||||
stack;
|
||||
|
||||
dev_manager_destroy(dm);
|
||||
return r;
|
||||
}
|
||||
|
||||
int lv_update_write_access(struct logical_volume *lv)
|
||||
static int _lv_suspend(struct logical_volume *lv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int r;
|
||||
struct dev_manager *dm;
|
||||
|
||||
int deactivate_lvs_in_vg(struct volume_group *vg)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
int count = 0;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = &(list_item(lvh, struct lv_list)->lv);
|
||||
|
||||
count += ((lv_active(lv) == 1) && lv_deactivate(lv));
|
||||
if (!(dm = dev_manager_create(lv->vg->name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return count;
|
||||
if (!(r = dev_manager_suspend(dm, lv)))
|
||||
stack;
|
||||
|
||||
dev_manager_destroy(dm);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* These two functions return the number of LVs in the state,
|
||||
* or -1 on error.
|
||||
*/
|
||||
int lvs_in_vg_activated(struct volume_group *vg)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
int count = 0;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = &(list_item(lvh, struct lv_list)->lv);
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
count += (lv_active(lv) == 1);
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
count += (_lv_active(lv) == 1);
|
||||
}
|
||||
|
||||
return count;
|
||||
@@ -282,12 +229,125 @@ int lvs_in_vg_opened(struct volume_group *vg)
|
||||
struct logical_volume *lv;
|
||||
int count = 0;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = &(list_item(lvh, struct lv_list)->lv);
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
count += (lv_open_count(lv) == 1);
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
count += (_lv_open_count(lv) == 1);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* These return success if the device is not active */
|
||||
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s)
|
||||
{
|
||||
struct logical_volume *lv;
|
||||
struct dm_info info;
|
||||
|
||||
if (!activation())
|
||||
return 1;
|
||||
|
||||
if (!(lv = lv_from_lvid(cmd, lvid_s)))
|
||||
return 0;
|
||||
|
||||
if (!activation())
|
||||
return 1;
|
||||
|
||||
if (test_mode()) {
|
||||
_skip("Suspending '%s'.", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 (!activation())
|
||||
return 1;
|
||||
|
||||
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 (!activation())
|
||||
return 1;
|
||||
|
||||
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 (!activation())
|
||||
return 1;
|
||||
|
||||
if (!(lv = lv_from_lvid(cmd, lvid_s)))
|
||||
return 0;
|
||||
|
||||
if (test_mode()) {
|
||||
_skip("Activating '%s'.", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_info(lv, &info)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!info.exists || info.suspended)
|
||||
return _lv_activate(lv);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@@ -1,43 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#ifndef LVM_ACTIVATE_H
|
||||
#define LVM_ACTIVATE_H
|
||||
|
||||
/* FIXME Snapshot handling? */
|
||||
#include "metadata.h"
|
||||
#include <libdevmapper.h>
|
||||
|
||||
int lv_active(struct logical_volume *lv);
|
||||
int lv_open_count(struct logical_volume *lv);
|
||||
void set_activation(int activation);
|
||||
int activation();
|
||||
|
||||
int lv_activate(struct logical_volume *lv);
|
||||
int lv_reactivate(struct logical_volume *lv);
|
||||
int lv_deactivate(struct logical_volume *lv);
|
||||
int driver_version(char *version, size_t size);
|
||||
int library_version(char *version, size_t size);
|
||||
|
||||
/*
|
||||
* Return number of LVs in the VG that are
|
||||
* active.
|
||||
* Returns 1 if info structure has been populated, else 0.
|
||||
*/
|
||||
int lv_info(struct logical_volume *lv, struct dm_info *info);
|
||||
/*
|
||||
* Returns 1 if percent has been set, else 0.
|
||||
*/
|
||||
int lv_snapshot_percent(struct logical_volume *lv, float *percent);
|
||||
|
||||
/*
|
||||
* These should eventually use config file
|
||||
* to determine whether or not to activate
|
||||
*/
|
||||
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s);
|
||||
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s);
|
||||
int lv_activate(struct cmd_context *cmd, const char *lvid_s);
|
||||
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s);
|
||||
|
||||
/*
|
||||
* FIXME:
|
||||
* I don't like the *lvs_in_vg* function names.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Return number of LVs in the VG that are active.
|
||||
*/
|
||||
int lvs_in_vg_activated(struct volume_group *vg);
|
||||
int lvs_in_vg_opened(struct volume_group *vg);
|
||||
|
||||
/*
|
||||
* Test for (lv->status & LVM_WRITE)
|
||||
*/
|
||||
int lv_update_write_access(struct logical_volume *lv);
|
||||
|
||||
/*
|
||||
* Activate all LVs in the VG. Ignore any that
|
||||
* are already active. Return number
|
||||
* activated.
|
||||
*/
|
||||
int activate_lvs_in_vg(struct volume_group *vg);
|
||||
|
||||
/*
|
||||
* Deactivate all LVs in the VG
|
||||
*/
|
||||
int deactivate_lvs_in_vg(struct volume_group *vg);
|
||||
int lv_setup_cow_store(struct logical_volume *lv);
|
||||
|
||||
#endif
|
||||
|
1640
lib/activate/dev_manager.c
Normal file
1640
lib/activate/dev_manager.c
Normal file
File diff suppressed because it is too large
Load Diff
41
lib/activate/dev_manager.h
Normal file
41
lib/activate/dev_manager.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#ifndef _LVM_DEV_MANAGER_H
|
||||
#define _LVM_DEV_MANAGER_H
|
||||
|
||||
#include "metadata.h"
|
||||
|
||||
#include <libdevmapper.h>
|
||||
|
||||
struct dev_manager;
|
||||
|
||||
/*
|
||||
* Constructor and destructor.
|
||||
*/
|
||||
struct dev_manager *dev_manager_create(const char *vg_name);
|
||||
void dev_manager_destroy(struct dev_manager *dm);
|
||||
|
||||
/*
|
||||
* The device handler is responsible for creating all the layered
|
||||
* dm devices, and ensuring that all constraints are maintained
|
||||
* (eg, an origin is created before its snapshot, but is not
|
||||
* unsuspended until the snapshot is also created.)
|
||||
*/
|
||||
int dev_manager_info(struct dev_manager *dm, struct logical_volume *lv,
|
||||
struct dm_info *info);
|
||||
int dev_manager_snapshot_percent(struct dev_manager *dm,
|
||||
struct logical_volume *lv, float *percent);
|
||||
int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv);
|
||||
int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv);
|
||||
int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv);
|
||||
|
||||
/*
|
||||
* Put the desired changes into effect.
|
||||
*/
|
||||
int dev_manager_execute(struct dev_manager *dm);
|
||||
|
||||
#endif
|
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
|
||||
#ifndef DMFS_INTERFACE_H
|
||||
#define DMFS_INTERFACE_H
|
||||
|
||||
struct dmfs;
|
||||
|
||||
struct dmfs *dmfs_create(void);
|
||||
void dmfs_destroy(struct dmfs *dm);
|
||||
|
||||
int dmfs_dev_is_present(struct dmfs *dm, const char *dev);
|
||||
int dmfs_dev_is_active(struct dmfs *dm, const char *dev);
|
||||
|
||||
int dmfs_table_is_present(struct dmfs *dm, const char *dev, const char *table);
|
||||
int dmfs_table_is_active(struct dmfs *dm, const char *dev, const char *table);
|
||||
|
||||
int dmfs_dev_create(struct dmfs *dm, const char *name);
|
||||
int dmfs_dev_load_table(struct dmfs *dm, const char *dev,
|
||||
const char *table, const char *file);
|
||||
int dmfs_dev_drop_table(struct dmfs *dm, const char *dev, const char *table);
|
||||
|
||||
int dmfs_dev_activate_table(struct dmfs *dm, const char *dev,
|
||||
const char *table);
|
||||
|
||||
int dmfs_dev_deactivate(struct dmfs *dm, const char *dev);
|
||||
|
||||
#endif
|
@@ -4,108 +4,117 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "lib.h"
|
||||
#include "fs.h"
|
||||
#include "toolcontext.h"
|
||||
#include "lvm-string.h"
|
||||
#include "lvm-file.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <libdevmapper.h>
|
||||
|
||||
#include "fs.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <devmapper/libdevmapper.h>
|
||||
|
||||
/*
|
||||
* FIXME: copied straight from LVM1.
|
||||
*
|
||||
* This should run through /proc/mounts once only,
|
||||
* storing devfs mount points in a hash table.
|
||||
*/
|
||||
static int _check_devfs(const char *dev_dir)
|
||||
static int _mk_dir(struct volume_group *vg)
|
||||
{
|
||||
int r = 0, len;
|
||||
char dir[PATH_MAX], line[512];
|
||||
char type[32];
|
||||
FILE *mounts = NULL;
|
||||
char vg_path[PATH_MAX];
|
||||
|
||||
if (!(mounts = fopen("/proc/mounts", "r")))
|
||||
goto out;
|
||||
|
||||
/* trim the trailing slash off dev_dir, yuck */
|
||||
len = strlen(dev_dir) - 1;
|
||||
while(len && dev_dir[len] == '/')
|
||||
len--;
|
||||
|
||||
while (!feof(mounts)) {
|
||||
fgets(line, sizeof(line) - 1, mounts);
|
||||
if (sscanf(line, "%*s %s %s %*s", dir, type) != 2)
|
||||
continue;
|
||||
|
||||
if (!strcmp(type, "devfs") && !strncmp(dir, dev_dir, len)) {
|
||||
r = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(mounts);
|
||||
|
||||
out:
|
||||
return r;
|
||||
}
|
||||
|
||||
void _build_lv_path(char *buffer, size_t len, struct logical_volume *lv)
|
||||
{
|
||||
snprintf(buffer, len, "%s%s/%s_%s",
|
||||
lv->vg->cmd->dev_dir, dm_dir(), lv->vg->name, lv->name);
|
||||
}
|
||||
|
||||
void _build_vg_path(char *buffer, size_t len, struct volume_group *vg)
|
||||
{
|
||||
snprintf(buffer, len, "%s/%s", vg->cmd->dev_dir, vg->name);
|
||||
}
|
||||
|
||||
void _build_link_path(char *buffer, size_t len, struct logical_volume *lv)
|
||||
{
|
||||
snprintf(buffer, len, "%s/%s/%s", lv->vg->cmd->dev_dir,
|
||||
lv->vg->name, lv->name);
|
||||
}
|
||||
|
||||
static int _mk_node(struct logical_volume *lv)
|
||||
{
|
||||
char lv_path[PATH_MAX];
|
||||
char dm_path[PATH_MAX];
|
||||
dev_t dev;
|
||||
const char *dev_dir = lv->vg->cmd->dev_dir;
|
||||
|
||||
if (_check_devfs(dev_dir))
|
||||
return 1;
|
||||
|
||||
snprintf(dm_path, PATH_MAX, "%s%s", dev_dir, dm_dir());
|
||||
if (mkdir(dm_path, 0555) && errno != EEXIST) {
|
||||
log_sys_error("mkdir", dm_path);
|
||||
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
|
||||
vg->cmd->dev_dir, vg->name) == -1) {
|
||||
log_error("Couldn't construct name of volume "
|
||||
"group directory.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
_build_lv_path(lv_path, sizeof(lv_path), lv);
|
||||
if (dir_exists(vg_path))
|
||||
return 1;
|
||||
|
||||
if (mknod(lv_path, S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, dev) < 0) {
|
||||
log_sys_error("mknod", lv_path);
|
||||
log_very_verbose("Creating directory %s", vg_path);
|
||||
if (mkdir(vg_path, 0555)) {
|
||||
log_sys_error("mkdir", vg_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _rm_node(struct logical_volume *lv)
|
||||
static int _rm_dir(struct volume_group *vg)
|
||||
{
|
||||
char vg_path[PATH_MAX];
|
||||
|
||||
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
|
||||
vg->cmd->dev_dir, vg->name) == -1) {
|
||||
log_error("Couldn't construct name of volume "
|
||||
"group directory.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_very_verbose("Removing directory %s", vg_path);
|
||||
|
||||
if (is_empty_dir(vg_path))
|
||||
rmdir(vg_path);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _mk_link(struct logical_volume *lv, const char *dev)
|
||||
{
|
||||
char lv_path[PATH_MAX], link_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) {
|
||||
log_error("Couldn't create source pathname for "
|
||||
"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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lstat(lv_path, &buf)) {
|
||||
if (!S_ISLNK(buf.st_mode)) {
|
||||
log_error("Symbolic link %s not created: file exists",
|
||||
link_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (unlink(lv_path) < 0) {
|
||||
log_sys_error("unlink", lv_path);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
log_very_verbose("Linking %s -> %s", lv_path, link_path);
|
||||
if (symlink(link_path, lv_path) < 0) {
|
||||
log_sys_error("symlink", lv_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _rm_link(struct logical_volume *lv, const char *lv_name)
|
||||
{
|
||||
struct stat buf;
|
||||
char lv_path[PATH_MAX];
|
||||
const char *dev_dir = lv->vg->cmd->dev_dir;
|
||||
|
||||
if (_check_devfs(dev_dir))
|
||||
return 1;
|
||||
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
|
||||
lv->vg->cmd->dev_dir, lv->vg->name, lv_name) == -1) {
|
||||
log_error("Couldn't determine link pathname.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
_build_lv_path(lv_path, sizeof(lv_path), lv);
|
||||
log_very_verbose("Removing link %s", lv_path);
|
||||
if (lstat(lv_path, &buf) || !S_ISLNK(buf.st_mode)) {
|
||||
log_error("%s not symbolic link - not removing", lv_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (unlink(lv_path) < 0) {
|
||||
log_sys_error("unlink", lv_path);
|
||||
@@ -115,71 +124,9 @@ static int _rm_node(struct logical_volume *lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lazy programmer: I'm just going to always try
|
||||
* and create/remove the vg directory, and not say
|
||||
* anything if it fails.
|
||||
*/
|
||||
static int _mk_dir(struct volume_group *vg)
|
||||
int fs_add_lv(struct logical_volume *lv, const char *dev)
|
||||
{
|
||||
char vg_path[PATH_MAX];
|
||||
|
||||
_build_vg_path(vg_path, sizeof(vg_path), vg);
|
||||
mkdir(vg_path, 0555);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _rm_dir(struct volume_group *vg)
|
||||
{
|
||||
char vg_path[PATH_MAX];
|
||||
|
||||
_build_vg_path(vg_path, sizeof(vg_path), vg);
|
||||
rmdir(vg_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _mk_link(struct logical_volume *lv)
|
||||
{
|
||||
char lv_path[PATH_MAX], link_path[PATH_MAX];
|
||||
|
||||
_build_lv_path(lv_path, sizeof(lv_path), lv);
|
||||
_build_link_path(link_path, sizeof(link_path), lv);
|
||||
|
||||
if (symlink(lv_path, link_path) < 0) {
|
||||
log_sys_error("symlink", link_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _rm_link(struct logical_volume *lv)
|
||||
{
|
||||
char link_path[PATH_MAX];
|
||||
|
||||
_build_link_path(link_path, sizeof(link_path), lv);
|
||||
|
||||
if (unlink(link_path) < 0) {
|
||||
log_sys_error("unlink", link_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fs_add_lv(struct logical_volume *lv)
|
||||
{
|
||||
if (!_mk_node(lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_mk_dir(lv->vg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_mk_link(lv)) {
|
||||
if (!_mk_dir(lv->vg) || !_mk_link(lv, dev)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -189,17 +136,7 @@ int fs_add_lv(struct logical_volume *lv)
|
||||
|
||||
int fs_del_lv(struct logical_volume *lv)
|
||||
{
|
||||
if (!_rm_link(lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_rm_dir(lv->vg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_rm_node(lv)) {
|
||||
if (!_rm_link(lv, lv->name) || !_rm_dir(lv->vg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -207,3 +144,15 @@ int fs_del_lv(struct logical_volume *lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME Use rename() */
|
||||
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;
|
||||
}
|
||||
|
@@ -9,7 +9,15 @@
|
||||
|
||||
#include "metadata.h"
|
||||
|
||||
int fs_add_lv(struct logical_volume *lv);
|
||||
/*
|
||||
* These calls, private to the activate unit, set
|
||||
* 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_rename_lv(struct logical_volume *lv,
|
||||
const char *dev, const char *old_name);
|
||||
|
||||
|
||||
#endif
|
||||
|
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "table-build.c"
|
||||
|
||||
static void _print_run(FILE *fp, struct logical_volume *lv)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
int build_table(struct volume_group *vg, struct logical_volume *lv,
|
||||
const char *file)
|
||||
{
|
||||
int i;
|
||||
uint64_t sector = 0;
|
||||
uint64_t pe_size = vg->extent_size;
|
||||
uint64_t dest;
|
||||
struct pe_specifier *pes;
|
||||
FILE *fp = fopen(file, "w");
|
||||
|
||||
if (!fp) {
|
||||
log_err("couldn't open '%s' to write table", file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < lv->le_count; i++) {
|
||||
pes = lv->map + i;
|
||||
dest = pes->pv->pe_start + (pe_size * pes->pe);
|
||||
fprintf(fp, "%ull %ull linear %s %ull\n",
|
||||
sector, pe_size, pes->pv->dev->name, dest);
|
||||
sector += pe_size;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
return 1;
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
|
||||
#ifndef TABLE_BUILD_H
|
||||
#define TABLE_BUILD_H
|
||||
|
||||
int build_table(struct volume_group *vg, struct logical_volume *lv,
|
||||
const char *file);
|
||||
|
||||
#endif
|
491
lib/cache/cache.c
vendored
Normal file
491
lib/cache/cache.c
vendored
Normal file
@@ -0,0 +1,491 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "cache.h"
|
||||
#include "hash.h"
|
||||
#include "toolcontext.h"
|
||||
#include "dev-cache.h"
|
||||
#include "metadata.h"
|
||||
|
||||
static struct hash_table *_pvid_hash = NULL;
|
||||
static struct hash_table *_vgid_hash = NULL;
|
||||
static struct hash_table *_vgname_hash = NULL;
|
||||
static struct list _vginfos;
|
||||
int _has_scanned = 0;
|
||||
|
||||
int cache_init()
|
||||
{
|
||||
list_init(&_vginfos);
|
||||
|
||||
if (!(_vgname_hash = hash_create(128)))
|
||||
return 0;
|
||||
|
||||
if (!(_vgid_hash = hash_create(128)))
|
||||
return 0;
|
||||
|
||||
if (!(_pvid_hash = hash_create(128)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct cache_vginfo *vginfo_from_vgname(const char *vgname)
|
||||
{
|
||||
struct cache_vginfo *vginfo;
|
||||
|
||||
if (!_vgname_hash)
|
||||
return NULL;
|
||||
|
||||
if (!(vginfo = hash_lookup(_vgname_hash, vgname)))
|
||||
return NULL;
|
||||
|
||||
return vginfo;
|
||||
}
|
||||
|
||||
struct format_type *fmt_from_vgname(const char *vgname)
|
||||
{
|
||||
struct cache_vginfo *vginfo;
|
||||
|
||||
if (!(vginfo = vginfo_from_vgname(vgname)))
|
||||
return NULL;
|
||||
|
||||
return vginfo->fmt;
|
||||
}
|
||||
|
||||
struct cache_vginfo *vginfo_from_vgid(const char *vgid)
|
||||
{
|
||||
struct cache_vginfo *vginfo;
|
||||
|
||||
if (!_vgid_hash || !vgid)
|
||||
return NULL;
|
||||
|
||||
if (!(vginfo = hash_lookup_fixed(_vgid_hash, vgid, ID_LEN)))
|
||||
return NULL;
|
||||
|
||||
return vginfo;
|
||||
}
|
||||
|
||||
struct cache_info *info_from_pvid(const char *pvid)
|
||||
{
|
||||
struct cache_info *info;
|
||||
|
||||
if (!_pvid_hash || !pvid)
|
||||
return NULL;
|
||||
|
||||
if (!(info = hash_lookup_fixed(_pvid_hash, pvid, ID_LEN)))
|
||||
return NULL;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static void _rescan_entry(struct cache_info *info)
|
||||
{
|
||||
struct label *label;
|
||||
|
||||
if (info->status & CACHE_INVALID)
|
||||
label_read(info->dev, &label);
|
||||
}
|
||||
|
||||
static int _scan_invalid(struct cmd_context *cmd)
|
||||
{
|
||||
hash_iter(_pvid_hash, (iterate_fn) _rescan_entry);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cache_label_scan(struct cmd_context *cmd, int full_scan)
|
||||
{
|
||||
struct label *label;
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
struct list *fmth;
|
||||
struct format_type *fmt;
|
||||
|
||||
static int _scanning_in_progress = 0;
|
||||
int r = 0;
|
||||
|
||||
/* Avoid recursion when a PVID can't be found! */
|
||||
if (_scanning_in_progress)
|
||||
return 0;
|
||||
|
||||
_scanning_in_progress = 1;
|
||||
|
||||
if (!_vgname_hash && !cache_init()) {
|
||||
log_error("Internal cache initialisation failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (_has_scanned && !full_scan) {
|
||||
r = _scan_invalid(cmd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(iter = dev_iter_create(cmd->filter))) {
|
||||
log_error("dev_iter creation failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
while ((dev = dev_iter_get(iter)))
|
||||
label_read(dev, &label);
|
||||
|
||||
dev_iter_destroy(iter);
|
||||
|
||||
_has_scanned = 1;
|
||||
|
||||
/* Perform any format-specific scanning e.g. text files */
|
||||
list_iterate(fmth, &cmd->formats) {
|
||||
fmt = list_item(fmth, struct format_type);
|
||||
if (fmt->ops->scan && !fmt->ops->scan(fmt))
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
_scanning_in_progress = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
struct list *cache_get_vgnames(struct cmd_context *cmd, int full_scan)
|
||||
{
|
||||
struct list *vgih, *vgnames;
|
||||
struct str_list *sl;
|
||||
|
||||
cache_label_scan(cmd, full_scan);
|
||||
|
||||
if (!(vgnames = pool_alloc(cmd->mem, sizeof(struct list)))) {
|
||||
log_error("vgnames list allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_init(vgnames);
|
||||
|
||||
list_iterate(vgih, &_vginfos) {
|
||||
if (!(sl = pool_alloc(cmd->mem, sizeof(*sl)))) {
|
||||
log_error("strlist allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
if (!(sl->str = pool_strdup(cmd->mem,
|
||||
list_item(vgih,
|
||||
struct cache_vginfo)->
|
||||
vgname))) {
|
||||
log_error("vgname allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
list_add(vgnames, &sl->list);
|
||||
}
|
||||
|
||||
return vgnames;
|
||||
}
|
||||
|
||||
struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
|
||||
{
|
||||
struct label *label;
|
||||
struct cache_info *info;
|
||||
|
||||
/* Already cached ? */
|
||||
if ((info = info_from_pvid((char *) pvid))) {
|
||||
if (label_read(info->dev, &label)) {
|
||||
info = (struct cache_info *) label->info;
|
||||
if (id_equal(pvid, (struct id *) &info->dev->pvid))
|
||||
return info->dev;
|
||||
}
|
||||
}
|
||||
|
||||
cache_label_scan(cmd, 0);
|
||||
|
||||
/* Try again */
|
||||
if ((info = info_from_pvid((char *) pvid))) {
|
||||
if (label_read(info->dev, &label)) {
|
||||
info = (struct cache_info *) label->info;
|
||||
if (id_equal(pvid, (struct id *) &info->dev->pvid))
|
||||
return info->dev;
|
||||
}
|
||||
}
|
||||
|
||||
cache_label_scan(cmd, 1);
|
||||
|
||||
/* Try again */
|
||||
if ((info = info_from_pvid((char *) pvid))) {
|
||||
if (label_read(info->dev, &label)) {
|
||||
info = (struct cache_info *) label->info;
|
||||
if (id_equal(pvid, (struct id *) &info->dev->pvid))
|
||||
return info->dev;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void _drop_vginfo(struct cache_info *info)
|
||||
{
|
||||
if (!list_empty(&info->list)) {
|
||||
list_del(&info->list);
|
||||
list_init(&info->list);
|
||||
}
|
||||
|
||||
if (info->vginfo && list_empty(&info->vginfo->infos)) {
|
||||
hash_remove(_vgname_hash, info->vginfo->vgname);
|
||||
if (info->vginfo->vgname)
|
||||
dbg_free(info->vginfo->vgname);
|
||||
if (*info->vginfo->vgid)
|
||||
hash_remove(_vgid_hash, info->vginfo->vgid);
|
||||
list_del(&info->vginfo->list);
|
||||
dbg_free(info->vginfo);
|
||||
}
|
||||
|
||||
info->vginfo = NULL;
|
||||
}
|
||||
|
||||
/* Unused
|
||||
void cache_del(struct cache_info *info)
|
||||
{
|
||||
if (info->dev->pvid[0] && _pvid_hash)
|
||||
hash_remove(_pvid_hash, info->dev->pvid);
|
||||
|
||||
_drop_vginfo(info);
|
||||
|
||||
info->label->labeller->ops->destroy_label(info->label->labeller,
|
||||
info->label);
|
||||
dbg_free(info);
|
||||
|
||||
return;
|
||||
} */
|
||||
|
||||
static int _cache_update_pvid(struct cache_info *info, const char *pvid)
|
||||
{
|
||||
if (!strcmp(info->dev->pvid, pvid))
|
||||
return 1;
|
||||
if (*info->dev->pvid) {
|
||||
hash_remove(_pvid_hash, info->dev->pvid);
|
||||
}
|
||||
strncpy(info->dev->pvid, pvid, sizeof(info->dev->pvid));
|
||||
if (!hash_insert(_pvid_hash, pvid, info)) {
|
||||
log_error("_cache_update: pvid insertion failed: %s", pvid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _cache_update_vgid(struct cache_info *info, const char *vgid)
|
||||
{
|
||||
if (!vgid || !info->vginfo || !strncmp(info->vginfo->vgid, vgid,
|
||||
sizeof(info->vginfo->vgid)))
|
||||
return 1;
|
||||
|
||||
if (info->vginfo && *info->vginfo->vgid)
|
||||
hash_remove(_vgid_hash, info->vginfo->vgid);
|
||||
if (!vgid)
|
||||
return 1;
|
||||
|
||||
strncpy(info->vginfo->vgid, vgid, sizeof(info->vginfo->vgid));
|
||||
info->vginfo->vgid[sizeof(info->vginfo->vgid) - 1] = '\0';
|
||||
if (!hash_insert(_vgid_hash, vgid, info->vginfo)) {
|
||||
log_error("_cache_update: vgid hash insertion failed: %s",
|
||||
vgid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cache_update_vgname(struct cache_info *info, const char *vgname)
|
||||
{
|
||||
struct cache_vginfo *vginfo;
|
||||
|
||||
/* If vgname is NULL and we don't already have a vgname,
|
||||
* assume ORPHAN - we want every entry to have a vginfo
|
||||
* attached for scanning reasons.
|
||||
*/
|
||||
if (!vgname && !info->vginfo)
|
||||
vgname = ORPHAN;
|
||||
|
||||
if (!vgname || (info->vginfo && !strcmp(info->vginfo->vgname, vgname)))
|
||||
return 1;
|
||||
|
||||
/* Remove existing vginfo entry */
|
||||
_drop_vginfo(info);
|
||||
|
||||
/* Get existing vginfo or create new one */
|
||||
if (!(vginfo = vginfo_from_vgname(vgname))) {
|
||||
if (!(vginfo = dbg_malloc(sizeof(*vginfo)))) {
|
||||
log_error("cache_update_vgname: list alloc failed");
|
||||
return 0;
|
||||
}
|
||||
memset(vginfo, 0, sizeof(*vginfo));
|
||||
if (!(vginfo->vgname = dbg_strdup(vgname))) {
|
||||
dbg_free(vginfo);
|
||||
log_error("cache vgname alloc failed for %s", vgname);
|
||||
return 0;
|
||||
}
|
||||
list_init(&vginfo->infos);
|
||||
if (!hash_insert(_vgname_hash, vginfo->vgname, vginfo)) {
|
||||
log_error("cache_update: vg hash insertion failed: %s",
|
||||
vginfo->vgname);
|
||||
dbg_free(vginfo->vgname);
|
||||
dbg_free(vginfo);
|
||||
return 0;
|
||||
}
|
||||
/* Ensure orphans appear last on list_iterate */
|
||||
if (!*vgname)
|
||||
list_add(&_vginfos, &vginfo->list);
|
||||
else
|
||||
list_add_h(&_vginfos, &vginfo->list);
|
||||
}
|
||||
|
||||
info->vginfo = vginfo;
|
||||
list_add(&vginfo->infos, &info->list);
|
||||
|
||||
/* FIXME Check consistency of list! */
|
||||
vginfo->fmt = info->fmt;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cache_update_vg(struct volume_group *vg)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct physical_volume *pv;
|
||||
struct cache_info *info;
|
||||
char pvid_s[ID_LEN + 1];
|
||||
int vgid_updated = 0;
|
||||
|
||||
pvid_s[sizeof(pvid_s) - 1] = '\0';
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
strncpy(pvid_s, (char *) &pv->id, sizeof(pvid_s) - 1);
|
||||
/* FIXME Could pv->dev->pvid ever be different? */
|
||||
if ((info = info_from_pvid(pvid_s))) {
|
||||
cache_update_vgname(info, vg->name);
|
||||
if (!vgid_updated) {
|
||||
_cache_update_vgid(info, (char *) &vg->id);
|
||||
vgid_updated = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct cache_info *cache_add(struct labeller *labeller, const char *pvid,
|
||||
struct device *dev,
|
||||
const char *vgname, const char *vgid)
|
||||
{
|
||||
struct label *label;
|
||||
struct cache_info *existing, *info;
|
||||
char pvid_s[ID_LEN + 1];
|
||||
|
||||
if (!_vgname_hash && !cache_init()) {
|
||||
log_error("Internal cache initialisation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strncpy(pvid_s, pvid, sizeof(pvid_s));
|
||||
pvid_s[sizeof(pvid_s) - 1] = '\0';
|
||||
|
||||
if (!(existing = info_from_pvid(pvid_s)) &&
|
||||
!(existing = info_from_pvid(dev->pvid))) {
|
||||
if (!(label = label_create(labeller))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
if (!(info = dbg_malloc(sizeof(*info)))) {
|
||||
log_error("cache_info allocation failed");
|
||||
label_destroy(label);
|
||||
return NULL;
|
||||
}
|
||||
memset(info, 0, sizeof(*info));
|
||||
|
||||
label->info = info;
|
||||
info->label = label;
|
||||
list_init(&info->list);
|
||||
info->dev = dev;
|
||||
} else {
|
||||
info = existing;
|
||||
/* Has labeller changed? */
|
||||
if (info->label->labeller != labeller) {
|
||||
label_destroy(info->label);
|
||||
if (!(info->label = label_create(labeller))) {
|
||||
/* FIXME leaves info without label! */
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
info->label->info = info;
|
||||
}
|
||||
label = info->label;
|
||||
}
|
||||
|
||||
info->fmt = (struct format_type *) labeller->private;
|
||||
info->status |= CACHE_INVALID;
|
||||
|
||||
if (!_cache_update_pvid(info, pvid_s)) {
|
||||
if (!existing) {
|
||||
dbg_free(info);
|
||||
label_destroy(label);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!cache_update_vgname(info, vgname)) {
|
||||
if (!existing) {
|
||||
hash_remove(_pvid_hash, pvid_s);
|
||||
strcpy(info->dev->pvid, "");
|
||||
dbg_free(info);
|
||||
label_destroy(label);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_cache_update_vgid(info, vgid))
|
||||
/* Non-critical */
|
||||
stack;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static void _cache_destroy_entry(struct cache_info *info)
|
||||
{
|
||||
if (!list_empty(&info->list))
|
||||
list_del(&info->list);
|
||||
strcpy(info->dev->pvid, "");
|
||||
label_destroy(info->label);
|
||||
dbg_free(info);
|
||||
}
|
||||
|
||||
static void _cache_destroy_vgnamelist(struct cache_vginfo *vginfo)
|
||||
{
|
||||
if (vginfo->vgname)
|
||||
dbg_free(vginfo->vgname);
|
||||
dbg_free(vginfo);
|
||||
}
|
||||
|
||||
void cache_destroy()
|
||||
{
|
||||
_has_scanned = 0;
|
||||
|
||||
if (_vgid_hash) {
|
||||
hash_destroy(_vgid_hash);
|
||||
_vgid_hash = NULL;
|
||||
}
|
||||
|
||||
if (_pvid_hash) {
|
||||
hash_iter(_pvid_hash, (iterate_fn) _cache_destroy_entry);
|
||||
hash_destroy(_pvid_hash);
|
||||
_pvid_hash = NULL;
|
||||
}
|
||||
|
||||
if (_vgname_hash) {
|
||||
hash_iter(_vgname_hash, (iterate_fn) _cache_destroy_vgnamelist);
|
||||
hash_destroy(_vgname_hash);
|
||||
_vgname_hash = NULL;
|
||||
}
|
||||
list_init(&_vginfos);
|
||||
}
|
73
lib/cache/cache.h
vendored
Normal file
73
lib/cache/cache.h
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LVM_CACHE_H
|
||||
#define _LVM_CACHE_H
|
||||
|
||||
#include "dev-cache.h"
|
||||
#include "list.h"
|
||||
#include "uuid.h"
|
||||
#include "label.h"
|
||||
#include "metadata.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#define ORPHAN ""
|
||||
|
||||
#define CACHE_INVALID 0x00000001
|
||||
|
||||
/* LVM specific per-volume info */
|
||||
/* Eventual replacement for struct physical_volume perhaps? */
|
||||
|
||||
struct cache_vginfo {
|
||||
struct list list; /* Join these vginfos together */
|
||||
struct list infos; /* List head for cache_infos */
|
||||
char *vgname; /* "" == orphan */
|
||||
char vgid[ID_LEN + 1];
|
||||
struct format_type *fmt;
|
||||
};
|
||||
|
||||
struct cache_info {
|
||||
struct list list; /* Join VG members together */
|
||||
struct list mdas; /* list head for metadata areas */
|
||||
struct list das; /* list head for data areas */
|
||||
struct cache_vginfo *vginfo; /* NULL == unknown */
|
||||
struct label *label;
|
||||
struct format_type *fmt;
|
||||
struct device *dev;
|
||||
uint64_t device_size; /* Bytes */
|
||||
uint32_t status;
|
||||
};
|
||||
|
||||
int cache_init();
|
||||
void cache_destroy();
|
||||
|
||||
/* Set full_scan to 1 to reread every filtered device label */
|
||||
int cache_label_scan(struct cmd_context *cmd, int full_scan);
|
||||
|
||||
/* Add/delete a device */
|
||||
struct cache_info *cache_add(struct labeller *labeller, const char *pvid,
|
||||
struct device *dev,
|
||||
const char *vgname, const char *vgid);
|
||||
void cache_del(struct cache_info *info);
|
||||
|
||||
/* Update things */
|
||||
int cache_update_vgname(struct cache_info *info, const char *vgname);
|
||||
int cache_update_vg(struct volume_group *vg);
|
||||
|
||||
/* Queries */
|
||||
struct format_type *fmt_from_vgname(const char *vgname);
|
||||
struct cache_vginfo *vginfo_from_vgname(const char *vgname);
|
||||
struct cache_vginfo *vginfo_from_vgid(const char *vgid);
|
||||
struct cache_info *info_from_pvid(const char *pvid);
|
||||
struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid);
|
||||
|
||||
/* Returns list of struct str_lists containing pool-allocated copy of vgnames */
|
||||
/* Set full_scan to 1 to reread every filtered device label */
|
||||
struct list *cache_get_vgnames(struct cmd_context *cmd, int full_scan);
|
||||
|
||||
#endif
|
16
lib/commands/errors.h
Normal file
16
lib/commands/errors.h
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#ifndef _LVM_ERRORS_H
|
||||
#define _LVM_ERRORS_H
|
||||
|
||||
#define EINVALID_CMD_LINE 1
|
||||
#define ENO_SUCH_CMD 3
|
||||
#define ECMD_PROCESSED 4
|
||||
#define ECMD_FAILED 5
|
||||
|
||||
#endif
|
||||
|
475
lib/commands/toolcontext.c
Normal file
475
lib/commands/toolcontext.c
Normal file
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "toolcontext.h"
|
||||
#include "pool.h"
|
||||
#include "metadata.h"
|
||||
#include "defaults.h"
|
||||
#include "lvm-string.h"
|
||||
#include "activate.h"
|
||||
#include "filter.h"
|
||||
#include "filter-composite.h"
|
||||
#include "filter-persistent.h"
|
||||
#include "filter-regex.h"
|
||||
#include "label.h"
|
||||
#include "lvm-file.h"
|
||||
#include "format-text.h"
|
||||
#include "sharedlib.h"
|
||||
|
||||
#ifdef LVM1_INTERNAL
|
||||
#include "format1.h"
|
||||
#endif
|
||||
|
||||
#include <locale.h>
|
||||
#include <sys/stat.h>
|
||||
#include <syslog.h>
|
||||
#include <dlfcn.h>
|
||||
#include <time.h>
|
||||
|
||||
static FILE *_log;
|
||||
|
||||
static int _get_env_vars(struct cmd_context *cmd)
|
||||
{
|
||||
const char *e;
|
||||
|
||||
/* Set to "" to avoid using any system directory */
|
||||
if ((e = getenv("LVM_SYSTEM_DIR"))) {
|
||||
if (lvm_snprintf(cmd->sys_dir, sizeof(cmd->sys_dir),
|
||||
"%s", e) < 0) {
|
||||
log_error("LVM_SYSTEM_DIR environment variable "
|
||||
"is too long.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _init_logging(struct cmd_context *cmd)
|
||||
{
|
||||
char *open_mode = "a";
|
||||
time_t t;
|
||||
|
||||
const char *log_file;
|
||||
|
||||
/* Syslog */
|
||||
cmd->default_settings.syslog =
|
||||
find_config_int(cmd->cf->root, "log/syslog", '/', DEFAULT_SYSLOG);
|
||||
if (cmd->default_settings.syslog != 1)
|
||||
fin_syslog();
|
||||
|
||||
if (cmd->default_settings.syslog > 1)
|
||||
init_syslog(cmd->default_settings.syslog);
|
||||
|
||||
/* Debug level for log file output */
|
||||
cmd->default_settings.debug =
|
||||
find_config_int(cmd->cf->root, "log/level", '/', DEFAULT_LOGLEVEL);
|
||||
init_debug(cmd->default_settings.debug);
|
||||
|
||||
/* Verbose level for tty output */
|
||||
cmd->default_settings.verbose =
|
||||
find_config_int(cmd->cf->root, "log/verbose", '/', DEFAULT_VERBOSE);
|
||||
init_verbose(cmd->default_settings.verbose);
|
||||
|
||||
/* Log message formatting */
|
||||
init_indent(find_config_int(cmd->cf->root, "log/indent", '/',
|
||||
DEFAULT_INDENT));
|
||||
|
||||
cmd->default_settings.msg_prefix = find_config_str(cmd->cf->root,
|
||||
"log/prefix", '/',
|
||||
DEFAULT_MSG_PREFIX);
|
||||
init_msg_prefix(cmd->default_settings.msg_prefix);
|
||||
|
||||
cmd->default_settings.cmd_name = find_config_int(cmd->cf->root,
|
||||
"log/command_names",
|
||||
'/', DEFAULT_CMD_NAME);
|
||||
init_cmd_name(cmd->default_settings.cmd_name);
|
||||
|
||||
/* Test mode */
|
||||
cmd->default_settings.test =
|
||||
find_config_int(cmd->cf->root, "global/test", '/', 0);
|
||||
|
||||
/* Settings for logging to file */
|
||||
if (find_config_int(cmd->cf->root, "log/overwrite", '/',
|
||||
DEFAULT_OVERWRITE))
|
||||
open_mode = "w";
|
||||
|
||||
log_file = find_config_str(cmd->cf->root, "log/file", '/', 0);
|
||||
if (log_file) {
|
||||
/* set up the logging */
|
||||
if (!(_log = fopen(log_file, open_mode)))
|
||||
log_error("Couldn't open log file %s", log_file);
|
||||
else
|
||||
init_log(_log);
|
||||
}
|
||||
|
||||
t = time(NULL);
|
||||
log_verbose("Logging initialised at %s", ctime(&t));
|
||||
|
||||
/* Tell device-mapper about our logging */
|
||||
dm_log_init(print_log);
|
||||
}
|
||||
|
||||
static int _process_config(struct cmd_context *cmd)
|
||||
{
|
||||
mode_t old_umask;
|
||||
|
||||
/* umask */
|
||||
cmd->default_settings.umask = find_config_int(cmd->cf->root,
|
||||
"global/umask", '/',
|
||||
DEFAULT_UMASK);
|
||||
|
||||
if ((old_umask = umask((mode_t) cmd->default_settings.umask)) !=
|
||||
(mode_t) cmd->default_settings.umask)
|
||||
log_verbose("Set umask to %04o", cmd->default_settings.umask);
|
||||
|
||||
/* dev dir */
|
||||
if (lvm_snprintf(cmd->dev_dir, sizeof(cmd->dev_dir), "%s/",
|
||||
find_config_str(cmd->cf->root, "devices/dir",
|
||||
'/', DEFAULT_DEV_DIR)) < 0) {
|
||||
log_error("Device directory given in config file too long");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dm_set_dev_dir(cmd->dev_dir);
|
||||
|
||||
/* proc dir */
|
||||
if (lvm_snprintf(cmd->proc_dir, sizeof(cmd->proc_dir), "%s",
|
||||
find_config_str(cmd->cf->root, "global/proc",
|
||||
'/', DEFAULT_PROC_DIR)) < 0) {
|
||||
log_error("Device directory given in config file too long");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* activation? */
|
||||
cmd->default_settings.activation = find_config_int(cmd->cf->root,
|
||||
"global/activation",
|
||||
'/',
|
||||
DEFAULT_ACTIVATION);
|
||||
set_activation(cmd->default_settings.activation);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Find and read config file */
|
||||
static int _init_config(struct cmd_context *cmd)
|
||||
{
|
||||
struct stat info;
|
||||
char config_file[PATH_MAX] = "";
|
||||
|
||||
if (!(cmd->cf = create_config_tree())) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No config file if LVM_SYSTEM_DIR is empty */
|
||||
if (!*cmd->sys_dir)
|
||||
return 1;
|
||||
|
||||
if (lvm_snprintf(config_file, sizeof(config_file),
|
||||
"%s/lvm.conf", cmd->sys_dir) < 0) {
|
||||
log_error("LVM_SYSTEM_DIR was too long");
|
||||
destroy_config_tree(cmd->cf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Is there a config file? */
|
||||
if (stat(config_file, &info) == -1) {
|
||||
if (errno == ENOENT)
|
||||
return 1;
|
||||
log_sys_error("stat", config_file);
|
||||
destroy_config_tree(cmd->cf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!read_config_file(cmd->cf, config_file)) {
|
||||
log_error("Failed to load config file %s", config_file);
|
||||
destroy_config_tree(cmd->cf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _init_dev_cache(struct cmd_context *cmd)
|
||||
{
|
||||
struct config_node *cn;
|
||||
struct config_value *cv;
|
||||
|
||||
if (!dev_cache_init()) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cn = find_config_node(cmd->cf->root, "devices/scan", '/'))) {
|
||||
if (!dev_cache_add_dir("/dev")) {
|
||||
log_error("Failed to add /dev to internal "
|
||||
"device cache");
|
||||
return 0;
|
||||
}
|
||||
log_verbose("device/scan not in config file: "
|
||||
"Defaulting to /dev");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != CFG_STRING) {
|
||||
log_error("Invalid string in config file: "
|
||||
"devices/scan");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dev_cache_add_dir(cv->v.str)) {
|
||||
log_error("Failed to add %s to internal device cache",
|
||||
cv->v.str);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
|
||||
{
|
||||
struct config_node *cn;
|
||||
struct dev_filter *f1, *f2, *f3;
|
||||
|
||||
if (!(f2 = lvm_type_filter_create(cmd->proc_dir)))
|
||||
return NULL;
|
||||
|
||||
if (!(cn = find_config_node(cmd->cf->root, "devices/filter", '/'))) {
|
||||
log_debug("devices/filter not found in config file: no regex "
|
||||
"filter installed");
|
||||
return f2;
|
||||
}
|
||||
|
||||
if (!(f1 = regex_filter_create(cn->v))) {
|
||||
log_error("Failed to create regex device filter");
|
||||
return f2;
|
||||
}
|
||||
|
||||
if (!(f3 = composite_filter_create(2, f1, f2))) {
|
||||
log_error("Failed to create composite device filter");
|
||||
return f2;
|
||||
}
|
||||
|
||||
return f3;
|
||||
}
|
||||
|
||||
static int _init_filters(struct cmd_context *cmd)
|
||||
{
|
||||
const char *lvm_cache;
|
||||
struct dev_filter *f3, *f4;
|
||||
struct stat st;
|
||||
char cache_file[PATH_MAX];
|
||||
|
||||
cmd->dump_filter = 0;
|
||||
|
||||
if (!(f3 = _init_filter_components(cmd)))
|
||||
return 0;
|
||||
|
||||
if (lvm_snprintf(cache_file, sizeof(cache_file),
|
||||
"%s/.cache", cmd->sys_dir) < 0) {
|
||||
log_error("Persistent cache filename too long ('%s/.cache').",
|
||||
cmd->sys_dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lvm_cache =
|
||||
find_config_str(cmd->cf->root, "devices/cache", '/', cache_file);
|
||||
if (!(f4 = persistent_filter_create(f3, lvm_cache))) {
|
||||
log_error("Failed to create persistent device filter");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Should we ever dump persistent filter state? */
|
||||
if (find_config_int(cmd->cf->root, "devices/write_cache_state", '/', 1))
|
||||
cmd->dump_filter = 1;
|
||||
|
||||
if (!*cmd->sys_dir)
|
||||
cmd->dump_filter = 0;
|
||||
|
||||
if (!stat(lvm_cache, &st) && !persistent_filter_load(f4))
|
||||
log_verbose("Failed to load existing device cache from %s",
|
||||
lvm_cache);
|
||||
|
||||
cmd->filter = f4;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _init_formats(struct cmd_context *cmd)
|
||||
{
|
||||
const char *format;
|
||||
|
||||
struct format_type *fmt;
|
||||
struct list *fmth;
|
||||
struct config_node *cn;
|
||||
struct config_value *cv;
|
||||
|
||||
struct format_type *(*init_format_fn) (struct cmd_context * cmd);
|
||||
|
||||
void *lib;
|
||||
|
||||
label_init();
|
||||
|
||||
#ifdef LVM1_INTERNAL
|
||||
if (!(fmt = init_lvm1_format(cmd)))
|
||||
return 0;
|
||||
fmt->library = NULL;
|
||||
list_add(&cmd->formats, &fmt->list);
|
||||
#endif
|
||||
|
||||
/* Load any formats in shared libs */
|
||||
if ((cn = find_config_node(cmd->cf->root, "global/format_libraries",
|
||||
'/'))) {
|
||||
for (cv = cn->v; cv; cv = cv->next) {
|
||||
if (cv->type != CFG_STRING) {
|
||||
log_error("Invalid string in config file: "
|
||||
"global/format_libraries");
|
||||
return 0;
|
||||
}
|
||||
if (!(lib = load_shared_library(cmd->cf, cv->v.str,
|
||||
"format"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(init_format_fn = dlsym(lib, "init_format"))) {
|
||||
log_error("Shared library %s does not contain "
|
||||
"format functions", cv->v.str);
|
||||
dlclose(lib);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(fmt = init_format_fn(cmd)))
|
||||
return 0;
|
||||
fmt->library = lib;
|
||||
list_add(&cmd->formats, &fmt->list);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(fmt = create_text_format(cmd)))
|
||||
return 0;
|
||||
fmt->library = NULL;
|
||||
list_add(&cmd->formats, &fmt->list);
|
||||
|
||||
cmd->fmt_backup = fmt;
|
||||
|
||||
format = find_config_str(cmd->cf->root, "global/format", '/',
|
||||
DEFAULT_FORMAT);
|
||||
|
||||
list_iterate(fmth, &cmd->formats) {
|
||||
fmt = list_item(fmth, struct format_type);
|
||||
if (!strcasecmp(fmt->name, format) ||
|
||||
(fmt->alias && !strcasecmp(fmt->alias, format))) {
|
||||
cmd->default_settings.fmt = fmt;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
log_error("_init_formats: Default format (%s) not found", format);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Entry point */
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args)
|
||||
{
|
||||
struct cmd_context *cmd;
|
||||
|
||||
if (!setlocale(LC_ALL, ""))
|
||||
log_error("setlocale failed");
|
||||
|
||||
init_syslog(DEFAULT_LOG_FACILITY);
|
||||
|
||||
if (!(cmd = dbg_malloc(sizeof(*cmd)))) {
|
||||
log_error("Failed to allocate command context");
|
||||
return NULL;
|
||||
}
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
cmd->args = the_args;
|
||||
list_init(&cmd->formats);
|
||||
|
||||
strcpy(cmd->sys_dir, DEFAULT_SYS_DIR);
|
||||
|
||||
if (!_get_env_vars(cmd))
|
||||
goto error;
|
||||
|
||||
/* Create system directory if it doesn't already exist */
|
||||
if (*cmd->sys_dir && !create_dir(cmd->sys_dir))
|
||||
goto error;
|
||||
|
||||
if (!_init_config(cmd))
|
||||
goto error;
|
||||
|
||||
_init_logging(cmd);
|
||||
|
||||
if (!_process_config(cmd))
|
||||
goto error;
|
||||
|
||||
if (!_init_dev_cache(cmd))
|
||||
goto error;
|
||||
|
||||
if (!_init_filters(cmd))
|
||||
goto error;
|
||||
|
||||
if (!(cmd->mem = pool_create(4 * 1024))) {
|
||||
log_error("Command memory pool creation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_init_formats(cmd))
|
||||
goto error;
|
||||
|
||||
cmd->current_settings = cmd->default_settings;
|
||||
|
||||
return cmd;
|
||||
|
||||
error:
|
||||
dbg_free(cmd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void destroy_formats(struct list *formats)
|
||||
{
|
||||
struct list *fmtl, *tmp;
|
||||
struct format_type *fmt;
|
||||
void *lib;
|
||||
|
||||
list_iterate_safe(fmtl, tmp, formats) {
|
||||
fmt = list_item(fmtl, struct format_type);
|
||||
list_del(&fmt->list);
|
||||
lib = fmt->library;
|
||||
fmt->ops->destroy(fmt);
|
||||
if (lib)
|
||||
dlclose(lib);
|
||||
}
|
||||
}
|
||||
|
||||
void destroy_toolcontext(struct cmd_context *cmd)
|
||||
{
|
||||
if (cmd->dump_filter)
|
||||
persistent_filter_dump(cmd->filter);
|
||||
|
||||
cache_destroy();
|
||||
label_exit();
|
||||
destroy_formats(&cmd->formats);
|
||||
cmd->filter->destroy(cmd->filter);
|
||||
pool_destroy(cmd->mem);
|
||||
dev_cache_exit();
|
||||
destroy_config_tree(cmd->cf);
|
||||
dbg_free(cmd);
|
||||
|
||||
dump_memory();
|
||||
fin_log();
|
||||
fin_syslog();
|
||||
|
||||
if (_log)
|
||||
fclose(_log);
|
||||
|
||||
}
|
69
lib/commands/toolcontext.h
Normal file
69
lib/commands/toolcontext.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the LGPL.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LVM_TOOLCONTEXT_H
|
||||
#define _LVM_TOOLCONTEXT_H
|
||||
|
||||
#include "dev-cache.h"
|
||||
#include "config.h"
|
||||
#include "pool.h"
|
||||
#include "metadata.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
/*
|
||||
* Config options that can be changed while commands are processed
|
||||
*/
|
||||
struct config_info {
|
||||
int debug;
|
||||
int verbose;
|
||||
int test;
|
||||
int syslog;
|
||||
int activation;
|
||||
const char *msg_prefix;
|
||||
int cmd_name; /* Show command name? */
|
||||
|
||||
int archive; /* should we archive ? */
|
||||
int backup; /* should we backup ? */
|
||||
|
||||
struct format_type *fmt;
|
||||
|
||||
mode_t umask;
|
||||
};
|
||||
|
||||
/* FIXME Split into tool & library contexts */
|
||||
/* command-instance-related variables needed by library */
|
||||
struct cmd_context {
|
||||
/* format handler allocates all objects from here */
|
||||
struct pool *mem;
|
||||
|
||||
struct format_type *fmt; /* Current format to use by default */
|
||||
struct format_type *fmt_backup; /* Format to use for backups */
|
||||
|
||||
struct list formats; /* Available formats */
|
||||
|
||||
char *cmd_line;
|
||||
struct command *command;
|
||||
struct arg *args;
|
||||
|
||||
struct dev_filter *filter;
|
||||
int dump_filter; /* Dump filter when exiting? */
|
||||
|
||||
struct config_tree *cf;
|
||||
struct config_info default_settings;
|
||||
struct config_info current_settings;
|
||||
|
||||
char sys_dir[PATH_MAX];
|
||||
char dev_dir[PATH_MAX];
|
||||
char proc_dir[PATH_MAX];
|
||||
};
|
||||
|
||||
struct cmd_context *create_toolcontext(struct arg *the_args);
|
||||
void destroy_toolcontext(struct cmd_context *cmd);
|
||||
|
||||
#endif
|
@@ -4,48 +4,50 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "lib.h"
|
||||
#include "config.h"
|
||||
#include "crc.h"
|
||||
#include "pool.h"
|
||||
#include "device.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "pool.h"
|
||||
#include "log.h"
|
||||
#include <asm/page.h>
|
||||
|
||||
enum {
|
||||
TOK_INT,
|
||||
TOK_FLOAT,
|
||||
TOK_STRING,
|
||||
TOK_EQ,
|
||||
TOK_SECTION_B,
|
||||
TOK_SECTION_E,
|
||||
TOK_ARRAY_B,
|
||||
TOK_ARRAY_E,
|
||||
TOK_IDENTIFIER,
|
||||
TOK_INT,
|
||||
TOK_FLOAT,
|
||||
TOK_STRING,
|
||||
TOK_EQ,
|
||||
TOK_SECTION_B,
|
||||
TOK_SECTION_E,
|
||||
TOK_ARRAY_B,
|
||||
TOK_ARRAY_E,
|
||||
TOK_IDENTIFIER,
|
||||
TOK_COMMA,
|
||||
TOK_EOF
|
||||
};
|
||||
|
||||
struct parser {
|
||||
const char *fb, *fe; /* file limits */
|
||||
char *fb, *fe; /* file limits */
|
||||
|
||||
int t; /* token limits and type */
|
||||
const char *tb, *te;
|
||||
int t; /* token limits and type */
|
||||
char *tb, *te;
|
||||
|
||||
int fd; /* descriptor for file being parsed */
|
||||
int fd; /* descriptor for file being parsed */
|
||||
int line; /* line number we are on */
|
||||
|
||||
struct pool *mem;
|
||||
struct pool *mem;
|
||||
};
|
||||
|
||||
struct cs {
|
||||
struct config_file cf;
|
||||
struct pool *mem;
|
||||
struct config_tree cf;
|
||||
struct pool *mem;
|
||||
time_t timestamp;
|
||||
char *filename;
|
||||
};
|
||||
|
||||
static void _get_token(struct parser *p);
|
||||
@@ -58,7 +60,6 @@ static int _match_aux(struct parser *p, int t);
|
||||
static struct config_value *_create_value(struct parser *p);
|
||||
static struct config_node *_create_node(struct parser *p);
|
||||
static char *_dup_tok(struct parser *p);
|
||||
static int _tok_match(const char *str, const char *b, const char *e);
|
||||
|
||||
#define MAX_INDENT 32
|
||||
|
||||
@@ -69,84 +70,229 @@ static int _tok_match(const char *str, const char *b, const char *e);
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
static int _tok_match(const char *str, const char *b, const char *e)
|
||||
{
|
||||
while (*str && (b != e)) {
|
||||
if (*str++ != *b++)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return !(*str || (b != e));
|
||||
}
|
||||
|
||||
/*
|
||||
* public interface
|
||||
*/
|
||||
struct config_file *create_config_file(void)
|
||||
struct config_tree *create_config_tree(void)
|
||||
{
|
||||
struct cs *c;
|
||||
struct pool *mem = pool_create(10 * 1024);
|
||||
struct cs *c;
|
||||
struct pool *mem = pool_create(10 * 1024);
|
||||
|
||||
if (!mem) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!mem) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(c = pool_alloc(mem, sizeof(*c)))) {
|
||||
stack;
|
||||
pool_destroy(mem);
|
||||
return 0;
|
||||
}
|
||||
if (!(c = pool_alloc(mem, sizeof(*c)))) {
|
||||
stack;
|
||||
pool_destroy(mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
c->mem = mem;
|
||||
c->cf.root = (struct config_node *)NULL;
|
||||
return &c->cf;
|
||||
c->mem = mem;
|
||||
c->cf.root = (struct config_node *) NULL;
|
||||
c->timestamp = 0;
|
||||
c->filename = NULL;
|
||||
return &c->cf;
|
||||
}
|
||||
|
||||
void destroy_config_file(struct config_file *cf)
|
||||
void destroy_config_tree(struct config_tree *cf)
|
||||
{
|
||||
pool_destroy(((struct cs *) cf)->mem);
|
||||
pool_destroy(((struct cs *) cf)->mem);
|
||||
}
|
||||
|
||||
int read_config(struct config_file *cf, const char *file)
|
||||
int read_config_fd(struct config_tree *cf, int fd, const char *file,
|
||||
off_t offset, uint32_t size, off_t offset2, uint32_t size2,
|
||||
checksum_fn_t checksum_fn, uint32_t checksum)
|
||||
{
|
||||
struct cs *c = (struct cs *) cf;
|
||||
struct parser *p;
|
||||
struct stat info;
|
||||
int r = 1, fd;
|
||||
struct parser *p;
|
||||
off_t mmap_offset;
|
||||
int r = 0;
|
||||
|
||||
if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
p->mem = c->mem;
|
||||
|
||||
/* memory map the file */
|
||||
if (stat(file, &info) || S_ISDIR(info.st_mode)) {
|
||||
log_sys_error("stat", file);
|
||||
return 0;
|
||||
}
|
||||
if (size2) {
|
||||
/* FIXME Attempt adjacent mmaps MAP_FIXED into malloced space
|
||||
* one PAGE_SIZE larger than required...
|
||||
*/
|
||||
if (!(p->fb = dbg_malloc(size + size2))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (lseek(fd, offset, SEEK_SET) < 0) {
|
||||
log_sys_error("lseek", file);
|
||||
goto out;
|
||||
}
|
||||
if (raw_read(fd, p->fb, size) != size) {
|
||||
log_error("Circular read from %s failed", file);
|
||||
goto out;
|
||||
}
|
||||
if (lseek(fd, offset2, SEEK_SET) < 0) {
|
||||
log_sys_error("lseek", file);
|
||||
goto out;
|
||||
}
|
||||
if (raw_read(fd, p->fb + size, size2) != size2) {
|
||||
log_error("Circular read from %s failed", file);
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
mmap_offset = offset % PAGE_SIZE;
|
||||
/* memory map the file */
|
||||
p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ,
|
||||
MAP_PRIVATE, fd, offset - mmap_offset);
|
||||
if (p->fb == (caddr_t) (-1)) {
|
||||
log_sys_error("mmap", file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((fd = open(file, O_RDONLY)) < 0) {
|
||||
log_sys_error("open", file);
|
||||
return 0;
|
||||
}
|
||||
p->fb = p->fb + mmap_offset;
|
||||
}
|
||||
|
||||
p->fb = mmap((caddr_t) 0, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (p->fb == MAP_FAILED) {
|
||||
log_sys_error("mmap", file);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
p->fe = p->fb + info.st_size;
|
||||
if (checksum_fn && checksum !=
|
||||
(checksum_fn(checksum_fn(INITIAL_CRC, p->fb, size),
|
||||
p->fb + size, size2))) {
|
||||
log_error("%s: Checksum error", file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* parse */
|
||||
p->tb = p->te = p->fb;
|
||||
p->fe = p->fb + size + size2;
|
||||
|
||||
/* parse */
|
||||
p->tb = p->te = p->fb;
|
||||
p->line = 1;
|
||||
_get_token(p);
|
||||
if (!(cf->root = _file(p))) {
|
||||
stack;
|
||||
r = 0;
|
||||
}
|
||||
if (!(cf->root = _file(p))) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* unmap the file */
|
||||
if (munmap((char *) p->fb, info.st_size)) {
|
||||
log_sys_error("munmap", file);
|
||||
r = 0;
|
||||
}
|
||||
r = 1;
|
||||
|
||||
close(fd);
|
||||
return r;
|
||||
out:
|
||||
if (size2)
|
||||
dbg_free(p->fb);
|
||||
else {
|
||||
/* unmap the file */
|
||||
if (munmap((char *) (p->fb - mmap_offset), size)) {
|
||||
log_sys_error("munmap", file);
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int read_config_file(struct config_tree *cf, const char *file)
|
||||
{
|
||||
struct cs *c = (struct cs *) cf;
|
||||
struct stat info;
|
||||
int r = 1, fd;
|
||||
|
||||
if (stat(file, &info)) {
|
||||
log_sys_error("stat", file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!S_ISREG(info.st_mode)) {
|
||||
log_error("%s is not a regular file", file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info.st_size == 0) {
|
||||
log_verbose("%s is empty", file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((fd = open(file, O_RDONLY)) < 0) {
|
||||
log_sys_error("open", file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = read_config_fd(cf, fd, file, 0, info.st_size, 0, 0,
|
||||
(checksum_fn_t) NULL, 0);
|
||||
|
||||
close(fd);
|
||||
|
||||
c->timestamp = info.st_mtime;
|
||||
c->filename = pool_strdup(c->mem, file);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if config file reloaded
|
||||
*/
|
||||
int reload_config_file(struct config_tree **cf)
|
||||
{
|
||||
struct config_tree *new_cf;
|
||||
struct cs *c = (struct cs *) *cf;
|
||||
struct cs *new_cs;
|
||||
struct stat info;
|
||||
int r, fd;
|
||||
|
||||
if (stat(c->filename, &info) == -1) {
|
||||
if (errno == ENOENT)
|
||||
return 1;
|
||||
log_sys_error("stat", c->filename);
|
||||
log_error("Failed to reload configuration file");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!S_ISREG(info.st_mode)) {
|
||||
log_error("Configuration file %s is not a regular file",
|
||||
c->filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Unchanged? */
|
||||
if (c->timestamp == info.st_mtime)
|
||||
return 0;
|
||||
|
||||
log_verbose("Detected config file change: Reloading %s", c->filename);
|
||||
|
||||
if (info.st_size == 0) {
|
||||
log_verbose("Config file reload: %s is empty", c->filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((fd = open(c->filename, O_RDONLY)) < 0) {
|
||||
log_sys_error("open", c->filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(new_cf = create_config_tree())) {
|
||||
log_error("Allocation of new config_tree failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = read_config_fd(new_cf, fd, c->filename, 0, info.st_size, 0, 0,
|
||||
(checksum_fn_t) NULL, 0);
|
||||
close(fd);
|
||||
|
||||
if (r) {
|
||||
new_cs = (struct cs *) new_cf;
|
||||
new_cs->filename = pool_strdup(new_cs->mem, c->filename);
|
||||
new_cs->timestamp = info.st_mtime;
|
||||
destroy_config_tree(*cf);
|
||||
*cf = new_cf;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void _write_value(FILE *fp, struct config_value *v)
|
||||
@@ -163,24 +309,32 @@ static void _write_value(FILE *fp, struct config_value *v)
|
||||
case CFG_INT:
|
||||
fprintf(fp, "%d", v->v.i);
|
||||
break;
|
||||
|
||||
case CFG_EMPTY_ARRAY:
|
||||
fprintf(fp, "[]");
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("_write_value: Unknown value type: %d", v->type);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static int _write_config(struct config_node *n, FILE *fp, int level)
|
||||
{
|
||||
char space[MAX_INDENT + 1];
|
||||
int l = (level < MAX_INDENT) ? level : MAX_INDENT;
|
||||
int i;
|
||||
char space[MAX_INDENT + 1];
|
||||
int l = (level < MAX_INDENT) ? level : MAX_INDENT;
|
||||
int i;
|
||||
|
||||
if (!n)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < l; i++)
|
||||
space[i] = ' ';
|
||||
space[i] = '\0';
|
||||
for (i = 0; i < l; i++)
|
||||
space[i] = '\t';
|
||||
space[i] = '\0';
|
||||
|
||||
while (n) {
|
||||
fprintf(fp, "%s%s", space, n->key);
|
||||
while (n) {
|
||||
fprintf(fp, "%s%s", space, n->key);
|
||||
if (!n->v) {
|
||||
/* it's a sub section */
|
||||
fprintf(fp, " {\n");
|
||||
@@ -203,26 +357,26 @@ static int _write_config(struct config_node *n, FILE *fp, int level)
|
||||
_write_value(fp, v);
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
n = n->sib;
|
||||
}
|
||||
n = n->sib;
|
||||
}
|
||||
/* FIXME: add error checking */
|
||||
return 1;
|
||||
}
|
||||
|
||||
int write_config(struct config_file *cf, const char *file)
|
||||
int write_config_file(struct config_tree *cf, const char *file)
|
||||
{
|
||||
int r = 1;
|
||||
FILE *fp = fopen(file, "w");
|
||||
if (!fp) {
|
||||
log_sys_error("open", file);
|
||||
return 0;
|
||||
}
|
||||
FILE *fp = fopen(file, "w");
|
||||
if (!fp) {
|
||||
log_sys_error("open", file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_write_config(cf->root, fp, 0)) {
|
||||
if (!_write_config(cf->root, fp, 0)) {
|
||||
stack;
|
||||
r = 0;
|
||||
}
|
||||
fclose(fp);
|
||||
fclose(fp);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -249,7 +403,7 @@ static struct config_node *_file(struct parser *p)
|
||||
|
||||
static struct config_node *_section(struct parser *p)
|
||||
{
|
||||
/* IDENTIFIER '{' VALUE* '}' */
|
||||
/* IDENTIFIER '{' VALUE* '}' */
|
||||
struct config_node *root, *n, *l = NULL;
|
||||
if (!(root = _create_node(p))) {
|
||||
stack;
|
||||
@@ -261,7 +415,7 @@ static struct config_node *_section(struct parser *p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
match (TOK_IDENTIFIER);
|
||||
match(TOK_IDENTIFIER);
|
||||
|
||||
if (p->t == TOK_SECTION_B) {
|
||||
match(TOK_SECTION_B);
|
||||
@@ -286,17 +440,17 @@ static struct config_node *_section(struct parser *p)
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
return root;
|
||||
}
|
||||
|
||||
static struct config_value *_value(struct parser *p)
|
||||
{
|
||||
/* '[' TYPE* ']' | TYPE */
|
||||
struct config_value *h = 0, *l, *ll = 0;
|
||||
if (p->t == TOK_ARRAY_B) {
|
||||
match (TOK_ARRAY_B);
|
||||
while (p->t != TOK_ARRAY_E) {
|
||||
if (!(l = _type(p))) {
|
||||
/* '[' TYPE* ']' | TYPE */
|
||||
struct config_value *h = NULL, *l, *ll = NULL;
|
||||
if (p->t == TOK_ARRAY_B) {
|
||||
match(TOK_ARRAY_B);
|
||||
while (p->t != TOK_ARRAY_E) {
|
||||
if (!(l = _type(p))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -310,48 +464,61 @@ static struct config_value *_value(struct parser *p)
|
||||
if (p->t == TOK_COMMA)
|
||||
match(TOK_COMMA);
|
||||
}
|
||||
match(TOK_ARRAY_E);
|
||||
} else
|
||||
match(TOK_ARRAY_E);
|
||||
/*
|
||||
* Special case for an empty array.
|
||||
*/
|
||||
if (!h) {
|
||||
if (!(h = _create_value(p)))
|
||||
return NULL;
|
||||
|
||||
h->type = CFG_EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
} else
|
||||
h = _type(p);
|
||||
|
||||
return h;
|
||||
return h;
|
||||
}
|
||||
|
||||
static struct config_value *_type(struct parser *p)
|
||||
{
|
||||
/* [0-9]+ | [0-9]*\.[0-9]* | ".*" */
|
||||
/* [0-9]+ | [0-9]*\.[0-9]* | ".*" */
|
||||
struct config_value *v = _create_value(p);
|
||||
|
||||
switch (p->t) {
|
||||
case TOK_INT:
|
||||
if (!v)
|
||||
return NULL;
|
||||
|
||||
switch (p->t) {
|
||||
case TOK_INT:
|
||||
v->type = CFG_INT;
|
||||
v->v.i = strtol(p->tb, 0, 10); /* FIXME: check error */
|
||||
match(TOK_INT);
|
||||
break;
|
||||
v->v.i = strtol(p->tb, NULL, 0); /* FIXME: check error */
|
||||
match(TOK_INT);
|
||||
break;
|
||||
|
||||
case TOK_FLOAT:
|
||||
case TOK_FLOAT:
|
||||
v->type = CFG_FLOAT;
|
||||
v->v.r = strtod(p->tb, 0); /* FIXME: check error */
|
||||
match(TOK_FLOAT);
|
||||
break;
|
||||
v->v.r = strtod(p->tb, NULL); /* FIXME: check error */
|
||||
match(TOK_FLOAT);
|
||||
break;
|
||||
|
||||
case TOK_STRING:
|
||||
case TOK_STRING:
|
||||
v->type = CFG_STRING;
|
||||
|
||||
p->tb++, p->te--; /* strip "'s */
|
||||
p->tb++, p->te--; /* strip "'s */
|
||||
if (!(v->v.str = _dup_tok(p))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
p->te++;
|
||||
match(TOK_STRING);
|
||||
break;
|
||||
match(TOK_STRING);
|
||||
break;
|
||||
|
||||
default:
|
||||
default:
|
||||
log_error("Parse error at line %d: expected a value", p->line);
|
||||
return 0;
|
||||
}
|
||||
return v;
|
||||
return 0;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static int _match_aux(struct parser *p, int t)
|
||||
@@ -368,106 +535,115 @@ static int _match_aux(struct parser *p, int t)
|
||||
*/
|
||||
static void _get_token(struct parser *p)
|
||||
{
|
||||
p->tb = p->te;
|
||||
_eat_space(p);
|
||||
if (p->tb == p->fe) {
|
||||
p->tb = p->te;
|
||||
_eat_space(p);
|
||||
if (p->tb == p->fe || !*p->tb) {
|
||||
p->t = TOK_EOF;
|
||||
return;
|
||||
}
|
||||
|
||||
p->t = TOK_INT; /* fudge so the fall through for
|
||||
floats works */
|
||||
switch (*p->te) {
|
||||
case '{':
|
||||
p->t = TOK_SECTION_B;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '}':
|
||||
p->t = TOK_SECTION_E;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
p->t = TOK_ARRAY_B;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case ']':
|
||||
p->t = TOK_ARRAY_E;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case ',':
|
||||
p->t = TOK_COMMA;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '=':
|
||||
p->t = TOK_EQ;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '"':
|
||||
p->t = TOK_STRING;
|
||||
p->t = TOK_INT; /* fudge so the fall through for
|
||||
floats works */
|
||||
switch (*p->te) {
|
||||
case '{':
|
||||
p->t = TOK_SECTION_B;
|
||||
p->te++;
|
||||
while ((p->te != p->fe) && (*p->te != '"')) {
|
||||
if ((*p->te == '\\') && (p->te + 1 != p->fe))
|
||||
p->te++;
|
||||
p->te++;
|
||||
}
|
||||
break;
|
||||
|
||||
if (p->te != p->fe)
|
||||
p->te++;
|
||||
break;
|
||||
case '}':
|
||||
p->t = TOK_SECTION_E;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '.':
|
||||
p->t = TOK_FLOAT;
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
p->te++;
|
||||
while (p->te != p->fe) {
|
||||
if (*p->te == '.') {
|
||||
if (p->t == TOK_FLOAT)
|
||||
break;
|
||||
p->t = TOK_FLOAT;
|
||||
} else if (!isdigit((int) *p->te))
|
||||
break;
|
||||
p->te++;
|
||||
}
|
||||
break;
|
||||
case '[':
|
||||
p->t = TOK_ARRAY_B;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
default:
|
||||
p->t = TOK_IDENTIFIER;
|
||||
while ((p->te != p->fe) && !isspace(*p->te) &&
|
||||
(*p->te != '#') && (*p->te != '='))
|
||||
p->te++;
|
||||
break;
|
||||
}
|
||||
case ']':
|
||||
p->t = TOK_ARRAY_E;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case ',':
|
||||
p->t = TOK_COMMA;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '=':
|
||||
p->t = TOK_EQ;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '"':
|
||||
p->t = TOK_STRING;
|
||||
p->te++;
|
||||
while ((p->te != p->fe) && (*p->te) && (*p->te != '"')) {
|
||||
if ((*p->te == '\\') && (p->te + 1 != p->fe) &&
|
||||
*(p->te + 1))
|
||||
p->te++;
|
||||
p->te++;
|
||||
}
|
||||
|
||||
if ((p->te != p->fe) && (*p->te))
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '.':
|
||||
p->t = TOK_FLOAT;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
p->te++;
|
||||
while ((p->te != p->fe) && (*p->te)) {
|
||||
if (*p->te == '.') {
|
||||
if (p->t == TOK_FLOAT)
|
||||
break;
|
||||
p->t = TOK_FLOAT;
|
||||
} else if (!isdigit((int) *p->te))
|
||||
break;
|
||||
p->te++;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
p->t = TOK_IDENTIFIER;
|
||||
while ((p->te != p->fe) && (*p->te) && !isspace(*p->te) &&
|
||||
(*p->te != '#') && (*p->te != '='))
|
||||
p->te++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void _eat_space(struct parser *p)
|
||||
{
|
||||
while (p->tb != p->fe) {
|
||||
if (*p->te == '#') {
|
||||
while ((p->te != p->fe) && (*p->te != '\n'))
|
||||
p->te++;
|
||||
while ((p->tb != p->fe) && (*p->tb)) {
|
||||
if (*p->te == '#') {
|
||||
while ((p->te != p->fe) && (*p->te) && (*p->te != '\n'))
|
||||
p->te++;
|
||||
p->line++;
|
||||
}
|
||||
|
||||
else if (isspace(*p->te)) {
|
||||
while ((p->te != p->fe) && isspace(*p->te)) {
|
||||
while ((p->te != p->fe) && (*p->te) && isspace(*p->te)) {
|
||||
if (*p->te == '\n')
|
||||
p->line++;
|
||||
p->te++;
|
||||
p->te++;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
return;
|
||||
else
|
||||
return;
|
||||
|
||||
p->tb = p->te;
|
||||
}
|
||||
p->tb = p->te;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -514,8 +690,7 @@ struct config_node *find_config_node(struct config_node *cn,
|
||||
path++;
|
||||
|
||||
/* find the end of this segment */
|
||||
for (e = path; *e && (*e != sep); e++)
|
||||
;
|
||||
for (e = path; *e && (*e != sep); e++) ;
|
||||
|
||||
/* hunt for the node */
|
||||
while (cn) {
|
||||
@@ -536,18 +711,20 @@ struct config_node *find_config_node(struct config_node *cn,
|
||||
return cn;
|
||||
}
|
||||
|
||||
const char *
|
||||
find_config_str(struct config_node *cn,
|
||||
const char *path, char sep, const char *fail)
|
||||
const char *find_config_str(struct config_node *cn,
|
||||
const char *path, char sep, const char *fail)
|
||||
{
|
||||
struct config_node *n = find_config_node(cn, path, sep);
|
||||
|
||||
if (n && n->v->type == CFG_STRING)
|
||||
if (n && n->v->type == CFG_STRING) {
|
||||
if (*n->v->v.str)
|
||||
log_very_verbose("Setting %s to %s", path, n->v->v.str);
|
||||
return n->v->v.str;
|
||||
}
|
||||
|
||||
if (fail)
|
||||
log_debug("%s not found in config: defaulting to %s",
|
||||
path, fail);
|
||||
log_very_verbose("%s not found in config: defaulting to %s",
|
||||
path, fail);
|
||||
return fail;
|
||||
}
|
||||
|
||||
@@ -556,9 +733,13 @@ int find_config_int(struct config_node *cn, const char *path,
|
||||
{
|
||||
struct config_node *n = find_config_node(cn, path, sep);
|
||||
|
||||
if (n && n->v->type == CFG_INT)
|
||||
if (n && n->v->type == CFG_INT) {
|
||||
log_very_verbose("Setting %s to %d", path, n->v->v.i);
|
||||
return n->v->v.i;
|
||||
}
|
||||
|
||||
log_very_verbose("%s not found in config: defaulting to %d",
|
||||
path, fail);
|
||||
return fail;
|
||||
}
|
||||
|
||||
@@ -567,25 +748,105 @@ float find_config_float(struct config_node *cn, const char *path,
|
||||
{
|
||||
struct config_node *n = find_config_node(cn, path, sep);
|
||||
|
||||
if (n && n->v->type == CFG_FLOAT)
|
||||
if (n && n->v->type == CFG_FLOAT) {
|
||||
log_very_verbose("Setting %s to %f", path, n->v->v.r);
|
||||
return n->v->v.r;
|
||||
}
|
||||
|
||||
log_very_verbose("%s not found in config: defaulting to %f",
|
||||
path, fail);
|
||||
|
||||
return fail;
|
||||
|
||||
}
|
||||
|
||||
static int _tok_match(const char *str, const char *b, const char *e)
|
||||
static int _str_in_array(const char *str, const char *values[])
|
||||
{
|
||||
while (*str && (b != e)) {
|
||||
if (*str++ != *b++)
|
||||
return 0;
|
||||
}
|
||||
int i;
|
||||
|
||||
return !(*str || (b != e));
|
||||
for (i = 0; values[i]; i++)
|
||||
if (!strcasecmp(str, values[i]))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
static int _str_to_bool(const char *str, int fail)
|
||||
{
|
||||
static const char *_true_values[] = { "y", "yes", "on", "true", NULL };
|
||||
static const char *_false_values[] =
|
||||
{ "n", "no", "off", "false", NULL };
|
||||
|
||||
if (_str_in_array(str, _true_values))
|
||||
return 1;
|
||||
|
||||
if (_str_in_array(str, _false_values))
|
||||
return 0;
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
int find_config_bool(struct config_node *cn, const char *path,
|
||||
char sep, int fail)
|
||||
{
|
||||
struct config_node *n = find_config_node(cn, path, sep);
|
||||
struct config_value *v;
|
||||
|
||||
if (!n)
|
||||
return fail;
|
||||
|
||||
v = n->v;
|
||||
|
||||
switch (v->type) {
|
||||
case CFG_INT:
|
||||
return v->v.i ? 1 : 0;
|
||||
|
||||
case CFG_STRING:
|
||||
return _str_to_bool(v->v.str, fail);
|
||||
}
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
int get_config_uint32(struct config_node *cn, const char *path,
|
||||
char sep, uint32_t *result)
|
||||
{
|
||||
struct config_node *n;
|
||||
|
||||
n = find_config_node(cn, path, sep);
|
||||
|
||||
if (!n || !n->v || n->v->type != CFG_INT)
|
||||
return 0;
|
||||
|
||||
*result = n->v->v.i;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_config_uint64(struct config_node *cn, const char *path,
|
||||
char sep, uint64_t *result)
|
||||
{
|
||||
struct config_node *n;
|
||||
|
||||
n = find_config_node(cn, path, sep);
|
||||
|
||||
if (!n || !n->v || n->v->type != CFG_INT)
|
||||
return 0;
|
||||
|
||||
/* FIXME Support 64-bit value! */
|
||||
*result = (uint64_t) n->v->v.i;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_config_str(struct config_node *cn, const char *path,
|
||||
char sep, char **result)
|
||||
{
|
||||
struct config_node *n;
|
||||
|
||||
n = find_config_node(cn, path, sep);
|
||||
|
||||
if (!n || !n->v || n->v->type != CFG_STRING)
|
||||
return 0;
|
||||
|
||||
*result = n->v->v.str;
|
||||
return 1;
|
||||
}
|
||||
|
@@ -1,44 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#ifndef _LVM_CONFIG_H
|
||||
#define _LVM_CONFIG_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
enum {
|
||||
CFG_STRING,
|
||||
CFG_FLOAT,
|
||||
CFG_INT,
|
||||
CFG_STRING,
|
||||
CFG_FLOAT,
|
||||
CFG_INT,
|
||||
CFG_EMPTY_ARRAY
|
||||
};
|
||||
|
||||
struct config_value {
|
||||
int type;
|
||||
union {
|
||||
int i;
|
||||
float r;
|
||||
char *str;
|
||||
} v;
|
||||
struct config_value *next; /* for arrays */
|
||||
int type;
|
||||
union {
|
||||
int i;
|
||||
float r;
|
||||
char *str;
|
||||
} v;
|
||||
struct config_value *next; /* for arrays */
|
||||
};
|
||||
|
||||
struct config_node {
|
||||
char *key;
|
||||
struct config_node *sib, *child;
|
||||
struct config_value *v;
|
||||
char *key;
|
||||
struct config_node *sib, *child;
|
||||
struct config_value *v;
|
||||
};
|
||||
|
||||
struct config_file {
|
||||
struct config_node *root;
|
||||
struct config_tree {
|
||||
struct config_node *root;
|
||||
};
|
||||
|
||||
struct config_file *create_config_file(void);
|
||||
void destroy_config_file(struct config_file *cf);
|
||||
struct config_tree *create_config_tree(void);
|
||||
void destroy_config_tree(struct config_tree *cf);
|
||||
|
||||
int read_config(struct config_file *cf, const char *file);
|
||||
int write_config(struct config_file *cf, const char *file);
|
||||
typedef uint32_t (*checksum_fn_t) (uint32_t initial, void *buf, uint32_t size);
|
||||
|
||||
int read_config_fd(struct config_tree *cf, int fd, const char *file,
|
||||
off_t offset, uint32_t size, off_t offset2, uint32_t size2,
|
||||
checksum_fn_t checksum_fn, uint32_t checksum);
|
||||
|
||||
int read_config_file(struct config_tree *cf, const char *file);
|
||||
int write_config_file(struct config_tree *cf, const char *file);
|
||||
int reload_config_file(struct config_tree **cf);
|
||||
|
||||
struct config_node *find_config_node(struct config_node *cn,
|
||||
const char *path, char seperator);
|
||||
@@ -52,10 +62,20 @@ int find_config_int(struct config_node *cn, const char *path,
|
||||
float find_config_float(struct config_node *cn, const char *path,
|
||||
char sep, float fail);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
* 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 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(struct config_node *cn, const char *path,
|
||||
char sep, char **result);
|
||||
|
||||
#endif
|
||||
|
57
lib/config/defaults.h
Normal file
57
lib/config/defaults.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Sistina Software (UK) Limited.
|
||||
*
|
||||
* This file is released under the GPL.
|
||||
*/
|
||||
|
||||
#ifndef _LVM_DEFAULTS_H
|
||||
#define _LVM_DEFAULTS_H
|
||||
|
||||
#define DEFAULT_ARCHIVE_ENABLED 1
|
||||
#define DEFAULT_BACKUP_ENABLED 1
|
||||
|
||||
#define DEFAULT_ARCHIVE_SUBDIR "archive"
|
||||
#define DEFAULT_BACKUP_SUBDIR "backup"
|
||||
|
||||
#define DEFAULT_ARCHIVE_DAYS 30
|
||||
#define DEFAULT_ARCHIVE_NUMBER 10
|
||||
|
||||
#define DEFAULT_SYS_DIR "/etc/lvm"
|
||||
#define DEFAULT_DEV_DIR "/dev"
|
||||
#define DEFAULT_PROC_DIR "/proc"
|
||||
|
||||
#define DEFAULT_LOCK_DIR "/var/lock/lvm"
|
||||
#define DEFAULT_LOCKING_LIB "lvm2_locking.so"
|
||||
|
||||
#define DEFAULT_UMASK 0077
|
||||
|
||||
#ifdef LVM1_SUPPORT
|
||||
#define DEFAULT_FORMAT "lvm1"
|
||||
#else
|
||||
#define DEFAULT_FORMAT "lvm2"
|
||||
#endif
|
||||
|
||||
#define DEFAULT_PVMETADATASIZE 255
|
||||
#define DEFAULT_PVMETADATACOPIES 1
|
||||
#define DEFAULT_LABELSECTOR 1
|
||||
|
||||
#define DEFAULT_MSG_PREFIX " "
|
||||
#define DEFAULT_CMD_NAME 0
|
||||
#define DEFAULT_OVERWRITE 0
|
||||
|
||||
#ifndef DEFAULT_LOG_FACILITY
|
||||
#define DEFAULT_LOG_FACILITY LOG_USER
|
||||
#endif
|
||||
|
||||
#define DEFAULT_SYSLOG 1
|
||||
#define DEFAULT_VERBOSE 0
|
||||
#define DEFAULT_LOGLEVEL 0
|
||||
#define DEFAULT_INDENT 1
|
||||
|
||||
#define DEFAULT_ACTIVATION 1
|
||||
|
||||
#ifdef READLINE_SUPPORT
|
||||
#define DEFAULT_MAX_HISTORY 100
|
||||
#endif
|
||||
|
||||
#endif /* _LVM_DEFAULTS_H */
|
@@ -4,10 +4,8 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "bitset.h"
|
||||
#include "dbg_malloc.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* FIXME: calculate this. */
|
||||
#define INT_SHIFT 5
|
||||
@@ -33,7 +31,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 +56,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 +64,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;
|
||||
|
@@ -11,8 +11,6 @@
|
||||
#include "pool.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
typedef uint32_t *bitset_t;
|
||||
|
||||
|
@@ -4,8 +4,8 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "btree.h"
|
||||
#include "log.h"
|
||||
|
||||
struct node {
|
||||
uint32_t key;
|
||||
@@ -40,8 +40,7 @@ static uint32_t _shuffle(uint32_t k)
|
||||
#if 1
|
||||
return ((k & 0xff) << 24 |
|
||||
(k & 0xff00) << 8 |
|
||||
(k & 0xff0000) >> 8 |
|
||||
(k & 0xff000000) >> 24);
|
||||
(k & 0xff0000) >> 8 | (k & 0xff000000) >> 24);
|
||||
#else
|
||||
return k;
|
||||
#endif
|
||||
|
@@ -4,10 +4,8 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
|
||||
#include "dbg_malloc.h"
|
||||
#include "lib.h"
|
||||
#include "hash.h"
|
||||
#include "log.h"
|
||||
|
||||
struct hash_node {
|
||||
struct hash_node *next;
|
||||
@@ -23,22 +21,30 @@ struct hash_table {
|
||||
|
||||
/* Permutation of the Integers 0 through 255 */
|
||||
static unsigned char _nums[] = {
|
||||
1, 14,110, 25, 97,174,132,119,138,170,125,118, 27,233,140, 51,
|
||||
87,197,177,107,234,169, 56, 68, 30, 7,173, 73,188, 40, 36, 65,
|
||||
49,213,104,190, 57,211,148,223, 48,115, 15, 2, 67,186,210, 28,
|
||||
12,181,103, 70, 22, 58, 75, 78,183,167,238,157,124,147,172,144,
|
||||
176,161,141, 86, 60, 66,128, 83,156,241, 79, 46,168,198, 41,254,
|
||||
178, 85,253,237,250,154,133, 88, 35,206, 95,116,252,192, 54,221,
|
||||
102,218,255,240, 82,106,158,201, 61, 3, 89, 9, 42,155,159, 93,
|
||||
166, 80, 50, 34,175,195,100, 99, 26,150, 16,145, 4, 33, 8,189,
|
||||
121, 64, 77, 72,208,245,130,122,143, 55,105,134, 29,164,185,194,
|
||||
193,239,101,242, 5,171,126, 11, 74, 59,137,228,108,191,232,139,
|
||||
6, 24, 81, 20,127, 17, 91, 92,251,151,225,207, 21, 98,113,112,
|
||||
84,226, 18,214,199,187, 13, 32, 94,220,224,212,247,204,196, 43,
|
||||
249,236, 45,244,111,182,153,136,129, 90,217,202, 19,165,231, 71,
|
||||
230,142, 96,227, 62,179,246,114,162, 53,160,215,205,180, 47,109,
|
||||
44, 38, 31,149,135, 0,216, 52, 63, 23, 37, 69, 39,117,146,184,
|
||||
163,200,222,235,248,243,219, 10,152,131,123,229,203, 76,120,209
|
||||
1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51,
|
||||
87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65,
|
||||
49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28,
|
||||
12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172,
|
||||
144,
|
||||
176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79, 46, 168, 198, 41, 254,
|
||||
178, 85, 253, 237, 250, 154, 133, 88, 35, 206, 95, 116, 252, 192, 54,
|
||||
221,
|
||||
102, 218, 255, 240, 82, 106, 158, 201, 61, 3, 89, 9, 42, 155, 159, 93,
|
||||
166, 80, 50, 34, 175, 195, 100, 99, 26, 150, 16, 145, 4, 33, 8, 189,
|
||||
121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185,
|
||||
194,
|
||||
193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232,
|
||||
139,
|
||||
6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112,
|
||||
84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196,
|
||||
43,
|
||||
249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231,
|
||||
71,
|
||||
230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47,
|
||||
109,
|
||||
44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184,
|
||||
163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120,
|
||||
209
|
||||
};
|
||||
|
||||
static struct hash_node *_create_node(const char *str)
|
||||
@@ -53,10 +59,10 @@ static struct hash_node *_create_node(const char *str)
|
||||
return n;
|
||||
}
|
||||
|
||||
static unsigned _hash(const char *str)
|
||||
static unsigned _hash(const char *str, int len)
|
||||
{
|
||||
unsigned long int h = 0, g;
|
||||
while (*str) {
|
||||
while (*str && len--) {
|
||||
h <<= 4;
|
||||
h += _nums[(int) *str++];
|
||||
g = h & ((unsigned long) 0xf << 16u);
|
||||
@@ -83,7 +89,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 +100,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,18 +125,30 @@ void hash_destroy(struct hash_table *t)
|
||||
dbg_free(t);
|
||||
}
|
||||
|
||||
static inline struct hash_node **_find(struct hash_table *t, const char *key)
|
||||
static inline struct hash_node **_find_fixed(struct hash_table *t,
|
||||
const char *key, uint32_t len)
|
||||
{
|
||||
unsigned h = _hash(key) & (t->num_slots - 1);
|
||||
unsigned h = _hash(key, len) & (t->num_slots - 1);
|
||||
struct hash_node **c;
|
||||
|
||||
for(c = &t->slots[h]; *c; c = &((*c)->next))
|
||||
if(!strcmp(key, (*c)->key))
|
||||
for (c = &t->slots[h]; *c; c = &((*c)->next))
|
||||
if (!strncmp(key, (*c)->key, len))
|
||||
break;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline struct hash_node **_find(struct hash_table *t, const char *key)
|
||||
{
|
||||
return _find_fixed(t, key, strlen(key));
|
||||
}
|
||||
|
||||
void *hash_lookup_fixed(struct hash_table *t, const char *key, uint32_t len)
|
||||
{
|
||||
struct hash_node **c = _find_fixed(t, key, len);
|
||||
return *c ? (*c)->data : 0;
|
||||
}
|
||||
|
||||
void *hash_lookup(struct hash_table *t, const char *key)
|
||||
{
|
||||
struct hash_node **c = _find(t, key);
|
||||
@@ -141,7 +159,7 @@ int hash_insert(struct hash_table *t, const char *key, void *data)
|
||||
{
|
||||
struct hash_node **c = _find(t, key);
|
||||
|
||||
if(*c)
|
||||
if (*c)
|
||||
(*c)->data = data;
|
||||
else {
|
||||
struct hash_node *n = _create_node(key);
|
||||
@@ -175,7 +193,7 @@ unsigned hash_get_num_entries(struct hash_table *t)
|
||||
return t->num_nodes;
|
||||
}
|
||||
|
||||
void hash_iterate(struct hash_table *t, iterate_fn f)
|
||||
void hash_iter(struct hash_table *t, iterate_fn f)
|
||||
{
|
||||
struct hash_node *c;
|
||||
int i;
|
||||
@@ -220,7 +238,6 @@ struct hash_node *hash_get_first(struct hash_table *t)
|
||||
|
||||
struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n)
|
||||
{
|
||||
unsigned int h = _hash(n->key) & (t->num_slots - 1);
|
||||
unsigned int h = _hash(n->key, strlen(n->key)) & (t->num_slots - 1);
|
||||
return n->next ? n->next : _next_slot(t, h + 1);
|
||||
}
|
||||
|
||||
|
@@ -7,6 +7,8 @@
|
||||
#ifndef _LVM_HASH_H
|
||||
#define _LVM_HASH_H
|
||||
|
||||
#include "lvm-types.h"
|
||||
|
||||
struct hash_table;
|
||||
struct hash_node;
|
||||
|
||||
@@ -17,16 +19,21 @@ void hash_destroy(struct hash_table *t);
|
||||
void hash_wipe(struct hash_table *t);
|
||||
|
||||
void *hash_lookup(struct hash_table *t, const char *key);
|
||||
void *hash_lookup_fixed(struct hash_table *t, const char *key, uint32_t len);
|
||||
int hash_insert(struct hash_table *t, const char *key, void *data);
|
||||
void hash_remove(struct hash_table *t, const char *key);
|
||||
|
||||
unsigned hash_get_num_entries(struct hash_table *t);
|
||||
void hash_iterate(struct hash_table *t, iterate_fn f);
|
||||
void hash_iter(struct hash_table *t, iterate_fn f);
|
||||
|
||||
char *hash_get_key(struct hash_table *t, struct hash_node *n);
|
||||
void *hash_get_data(struct hash_table *t, struct hash_node *n);
|
||||
struct hash_node *hash_get_first(struct hash_table *t);
|
||||
struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n);
|
||||
|
||||
#define hash_iterate(v, h) \
|
||||
for (v = hash_get_first(h); v; \
|
||||
v = hash_get_next(h, v))
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -47,7 +47,20 @@ static inline int list_empty(struct list *head) {
|
||||
}
|
||||
|
||||
#define list_iterate(v, head) \
|
||||
for (v = (head)->n; v != head; v = v->n)
|
||||
for (v = (head)->n; v != head; v = v->n)
|
||||
|
||||
#define list_iterate_safe(v, t, head) \
|
||||
for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
|
||||
|
||||
static inline int list_size(struct list *head) {
|
||||
int s = 0;
|
||||
struct list *v;
|
||||
|
||||
list_iterate(v, head)
|
||||
s++;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
#define list_item(v, t) \
|
||||
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list))
|
||||
|
@@ -4,21 +4,19 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "dev-cache.h"
|
||||
#include "log.h"
|
||||
#include "pool.h"
|
||||
#include "hash.h"
|
||||
#include "list.h"
|
||||
#include "lvm-types.h"
|
||||
#include "btree.h"
|
||||
#include "dbg_malloc.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include <dirent.h>
|
||||
#include <linux/kdev_t.h>
|
||||
|
||||
/*
|
||||
* FIXME: really need to seperate names from the devices since
|
||||
@@ -45,7 +43,6 @@ static struct {
|
||||
|
||||
} _cache;
|
||||
|
||||
|
||||
#define _alloc(x) pool_alloc(_cache.mem, (x))
|
||||
#define _free(x) pool_free(_cache.mem, (x))
|
||||
|
||||
@@ -63,6 +60,8 @@ static struct device *_create_dev(dev_t d)
|
||||
list_init(&dev->aliases);
|
||||
dev->dev = d;
|
||||
dev->fd = -1;
|
||||
dev->flags = 0;
|
||||
memset(dev->pvid, 0, sizeof(dev->pvid));
|
||||
return dev;
|
||||
}
|
||||
|
||||
@@ -108,40 +107,18 @@ static int _insert_dev(const char *path, dev_t d)
|
||||
}
|
||||
|
||||
if (!_add_alias(dev, path)) {
|
||||
log_err("Couldn't add alias to dir cache.");
|
||||
log_err("Couldn't add alias to dev cache.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!hash_insert(_cache.names, path, dev)) {
|
||||
log_err("Couldn't add name to hash in dir cache.");
|
||||
log_err("Couldn't add name to hash in dev cache.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* return a new path for the destination of the link.
|
||||
*/
|
||||
static char *_follow_link(const char *path, struct stat *info)
|
||||
{
|
||||
char buffer[PATH_MAX + 1];
|
||||
int n;
|
||||
n = readlink(path, buffer, sizeof(buffer) - 1);
|
||||
|
||||
if (n <= 0)
|
||||
return NULL;
|
||||
|
||||
buffer[n] = '\0';
|
||||
|
||||
if (stat(buffer, info) < 0) {
|
||||
log_sys_very_verbose("stat", buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pool_strdup(_cache.mem, buffer);
|
||||
}
|
||||
|
||||
static char *_join(const char *dir, const char *name)
|
||||
{
|
||||
int len = strlen(dir) + strlen(name) + 2;
|
||||
@@ -208,7 +185,6 @@ static int _insert_dir(const char *dir)
|
||||
static int _insert(const char *path, int rec)
|
||||
{
|
||||
struct stat info;
|
||||
char *actual_path;
|
||||
int r = 0;
|
||||
|
||||
if (stat(path, &info) < 0) {
|
||||
@@ -216,23 +192,7 @@ static int _insert(const char *path, int rec)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* follow symlinks if neccessary. */
|
||||
if (S_ISLNK(info.st_mode)) {
|
||||
log_debug("%s: Following symbolic link", path);
|
||||
if (!(actual_path = _follow_link(path, &info))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stat(actual_path, &info) < 0) {
|
||||
log_sys_very_verbose("stat", actual_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dbg_free(actual_path);
|
||||
}
|
||||
|
||||
if (S_ISDIR(info.st_mode)) { /* add a directory */
|
||||
if (S_ISDIR(info.st_mode)) { /* add a directory */
|
||||
if (rec)
|
||||
r = _insert_dir(path);
|
||||
|
||||
@@ -268,6 +228,21 @@ static void _full_scan(void)
|
||||
_cache.has_scanned = 1;
|
||||
}
|
||||
|
||||
int dev_cache_has_scanned(void)
|
||||
{
|
||||
return _cache.has_scanned;
|
||||
}
|
||||
|
||||
void dev_cache_scan(int do_scan)
|
||||
{
|
||||
if (!do_scan)
|
||||
_cache.has_scanned = 1;
|
||||
else {
|
||||
_cache.has_scanned = 0;
|
||||
_full_scan();
|
||||
}
|
||||
}
|
||||
|
||||
int dev_cache_init(void)
|
||||
{
|
||||
_cache.names = NULL;
|
||||
@@ -293,30 +268,20 @@ int dev_cache_init(void)
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
dev_cache_exit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _check_closed(struct device *dev)
|
||||
{
|
||||
if (dev->fd >= 0)
|
||||
log_err("Device '%s' has been left open.", dev_name(dev));
|
||||
}
|
||||
|
||||
static inline void _check_for_open_devices(void)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
struct dev_iter *i = dev_iter_create(NULL);
|
||||
struct device *dev;
|
||||
|
||||
if (!i) {
|
||||
stack;
|
||||
return;
|
||||
}
|
||||
|
||||
while ((dev = dev_iter_get(i))) {
|
||||
if (dev->fd >= 0)
|
||||
log_err("Device '%s' has been left open.",
|
||||
dev_name(dev));
|
||||
}
|
||||
|
||||
dev_iter_destroy(i);
|
||||
#endif
|
||||
hash_iter(_cache.names, (iterate_fn) _check_closed);
|
||||
}
|
||||
|
||||
void dev_cache_exit(void)
|
||||
@@ -352,10 +317,55 @@ int dev_cache_add_dir(const char *path)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check cached device name is still valid before returning it */
|
||||
/* This should be a rare occurrence */
|
||||
/* FIXME Make rest of code pass/cache struct device instead of dev_name */
|
||||
const char *dev_name_confirmed(struct device *dev)
|
||||
{
|
||||
struct stat buf;
|
||||
char *name;
|
||||
int r;
|
||||
|
||||
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));
|
||||
|
||||
/* Remove the incorrect hash entry */
|
||||
hash_remove(_cache.names, name);
|
||||
|
||||
/* Leave list alone if there isn't an alternative name */
|
||||
/* so dev_name will always find something to return. */
|
||||
/* Otherwise add the name to the correct device. */
|
||||
if (list_size(&dev->aliases) > 1) {
|
||||
list_del(dev->aliases.n);
|
||||
if (!r)
|
||||
_insert(name, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
log_error("Aborting - please provide new pathname for what "
|
||||
"used to be %s", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dev_name(dev);
|
||||
}
|
||||
|
||||
struct device *dev_cache_get(const char *name, struct dev_filter *f)
|
||||
{
|
||||
struct stat buf;
|
||||
struct device *d = (struct device *) hash_lookup(_cache.names, name);
|
||||
|
||||
/* If the entry's wrong, remove it */
|
||||
if (d && (stat(name, &buf) || (buf.st_rdev != d->dev))) {
|
||||
hash_remove(_cache.names, name);
|
||||
d = NULL;
|
||||
}
|
||||
|
||||
if (!d) {
|
||||
_insert(name, 0);
|
||||
d = (struct device *) hash_lookup(_cache.names, name);
|
||||
@@ -401,6 +411,3 @@ struct device *dev_iter_get(struct dev_iter *iter)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@@ -27,6 +27,10 @@ struct dev_filter {
|
||||
int dev_cache_init(void);
|
||||
void dev_cache_exit(void);
|
||||
|
||||
/* Trigger(1) or avoid(0) a scan */
|
||||
void dev_cache_scan(int do_scan);
|
||||
int dev_cache_has_scanned(void);
|
||||
|
||||
int dev_cache_add_dir(const char *path);
|
||||
struct device *dev_cache_get(const char *name, struct dev_filter *f);
|
||||
|
||||
|
@@ -4,17 +4,16 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "device.h"
|
||||
#include "lvm-types.h"
|
||||
#include "log.h"
|
||||
#include "metadata.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <linux/fs.h> // UGH!!! for BLKSSZGET
|
||||
|
||||
int dev_get_size(struct device *dev, uint64_t *size)
|
||||
{
|
||||
@@ -40,21 +39,68 @@ int dev_get_size(struct device *dev, uint64_t *size)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dev_open(struct device *dev, int flags)
|
||||
int dev_get_sectsize(struct device *dev, uint32_t *size)
|
||||
{
|
||||
int fd;
|
||||
int s;
|
||||
const char *name = dev_name(dev);
|
||||
|
||||
/* FIXME Check flags (eg is write now reqd?) */
|
||||
log_very_verbose("Getting size of %s", name);
|
||||
if ((fd = open(name, O_RDONLY)) < 0) {
|
||||
log_sys_error("open", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ioctl(fd, BLKSSZGET, &s) < 0) {
|
||||
log_sys_error("ioctl BLKSSZGET", name);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
*size = (uint32_t) s;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _flush(int fd)
|
||||
{
|
||||
ioctl(fd, BLKFLSBUF, 0);
|
||||
}
|
||||
|
||||
int dev_open(struct device *dev, int flags)
|
||||
{
|
||||
struct stat buf;
|
||||
const char *name = dev_name_confirmed(dev);
|
||||
|
||||
if (!name) {
|
||||
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)) {
|
||||
log_error("%s: stat failed: Has device name changed?", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((dev->fd = open(name, flags)) < 0) {
|
||||
log_sys_error("open", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((fstat(dev->fd, &buf) < 0) || (buf.st_rdev != dev->dev)) {
|
||||
log_error("%s: fstat failed: Has device name changed?", name);
|
||||
dev_close(dev);
|
||||
dev->fd = -1;
|
||||
return 0;
|
||||
}
|
||||
_flush(dev->fd);
|
||||
dev->flags = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -66,6 +112,9 @@ int dev_close(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dev->flags & DEV_ACCESSED_W)
|
||||
_flush(dev->fd);
|
||||
|
||||
if (close(dev->fd))
|
||||
log_sys_error("close", dev_name(dev));
|
||||
|
||||
@@ -77,7 +126,7 @@ int dev_close(struct device *dev)
|
||||
/*
|
||||
* FIXME: factor common code out.
|
||||
*/
|
||||
int _read(int fd, void *buf, size_t count)
|
||||
int raw_read(int fd, void *buf, size_t count)
|
||||
{
|
||||
size_t n = 0;
|
||||
int tot = 0;
|
||||
@@ -97,7 +146,7 @@ int _read(int fd, void *buf, size_t count)
|
||||
return tot;
|
||||
}
|
||||
|
||||
int64_t dev_read(struct device *dev, uint64_t offset,
|
||||
int64_t dev_read(struct device * dev, uint64_t offset,
|
||||
int64_t len, void *buffer)
|
||||
{
|
||||
const char *name = dev_name(dev);
|
||||
@@ -113,14 +162,18 @@ int64_t dev_read(struct device *dev, uint64_t offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _read(fd, buffer, len);
|
||||
return raw_read(fd, buffer, len);
|
||||
}
|
||||
|
||||
int _write(int fd, const void *buf, size_t count)
|
||||
{
|
||||
size_t n = 0;
|
||||
ssize_t n = 0;
|
||||
int tot = 0;
|
||||
|
||||
/* Skip all writes */
|
||||
if (test_mode())
|
||||
return count;
|
||||
|
||||
while (tot < count) {
|
||||
do
|
||||
n = write(fd, buf, count - tot);
|
||||
@@ -136,7 +189,7 @@ int _write(int fd, const void *buf, size_t count)
|
||||
return tot;
|
||||
}
|
||||
|
||||
int64_t dev_write(struct device *dev, uint64_t offset,
|
||||
int64_t dev_write(struct device * dev, uint64_t offset,
|
||||
int64_t len, void *buffer)
|
||||
{
|
||||
const char *name = dev_name(dev);
|
||||
@@ -152,6 +205,8 @@ int64_t dev_write(struct device *dev, uint64_t offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev->flags |= DEV_ACCESSED_W;
|
||||
|
||||
return _write(fd, buffer, len);
|
||||
}
|
||||
|
||||
@@ -159,24 +214,34 @@ int dev_zero(struct device *dev, uint64_t offset, int64_t len)
|
||||
{
|
||||
int64_t r, s;
|
||||
char buffer[4096];
|
||||
const char *name = dev_name(dev);
|
||||
int fd = dev->fd;
|
||||
int already_open;
|
||||
|
||||
if (fd < 0) {
|
||||
log_error("Attempt to zero part of an unopened device %s",
|
||||
name);
|
||||
already_open = dev_is_open(dev);
|
||||
|
||||
if (!already_open && !dev_open(dev, O_RDWR)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lseek(fd, offset, SEEK_SET) < 0) {
|
||||
log_sys_error("lseek", name);
|
||||
if (lseek(dev->fd, offset, SEEK_SET) < 0) {
|
||||
log_sys_error("lseek", dev_name(dev));
|
||||
if (!already_open && !dev_close(dev))
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((offset % SECTOR_SIZE) || (len % SECTOR_SIZE))
|
||||
log_debug("Wiping %s at %" PRIu64 " length %" PRId64,
|
||||
dev_name(dev), offset, len);
|
||||
else
|
||||
log_debug("Wiping %s at sector %" PRIu64 " length %" PRId64
|
||||
" sectors", dev_name(dev), offset >> SECTOR_SHIFT,
|
||||
len >> SECTOR_SHIFT);
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
while (1) {
|
||||
s = len > sizeof(buffer) ? sizeof(buffer) : len;
|
||||
r = _write(fd, buffer, s);
|
||||
r = _write(dev->fd, buffer, s);
|
||||
|
||||
if (r <= 0)
|
||||
break;
|
||||
@@ -188,5 +253,11 @@ int dev_zero(struct device *dev, uint64_t offset, int64_t len)
|
||||
}
|
||||
}
|
||||
|
||||
dev->flags |= DEV_ACCESSED_W;
|
||||
|
||||
if (!already_open && !dev_close(dev))
|
||||
stack;
|
||||
|
||||
/* FIXME: Always display error */
|
||||
return (len == 0);
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@
|
||||
* MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -24,9 +25,12 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/genhd.h>
|
||||
|
||||
#include "dbg_malloc.h"
|
||||
#include "log.h"
|
||||
@@ -34,13 +38,6 @@
|
||||
#include "metadata.h"
|
||||
#include "device.h"
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/genhd.h>
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
int _get_partition_type(struct dev_filter *filter, struct device *d);
|
||||
|
||||
#define MINOR_PART(dm, d) (MINOR((d)->dev) % dev_max_partitions(dm, (d)->dev))
|
||||
|
@@ -9,42 +9,75 @@
|
||||
|
||||
#include "lvm-types.h"
|
||||
#include "list.h"
|
||||
#include "uuid.h"
|
||||
|
||||
#define DEV_ACCESSED_W 0x00000001 /* Device written to? */
|
||||
|
||||
/*
|
||||
* 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;
|
||||
uint32_t flags;
|
||||
|
||||
char pvid[ID_LEN + 1];
|
||||
};
|
||||
|
||||
struct device_list {
|
||||
struct list 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_sectsize(struct device *dev, uint32_t *size);
|
||||
|
||||
int dev_open(struct device *dev, int flags);
|
||||
int dev_close(struct device *dev);
|
||||
|
||||
static inline int dev_fd(struct device *dev)
|
||||
{
|
||||
return dev->fd;
|
||||
}
|
||||
|
||||
int raw_read(int fd, void *buf, size_t count);
|
||||
|
||||
int64_t dev_read(struct device *dev,
|
||||
uint64_t offset, int64_t len, void *buffer);
|
||||
int64_t dev_write(struct device *dev,
|
||||
uint64_t offset, int64_t len, void *buffer);
|
||||
int dev_zero(struct device *dev, uint64_t offset, int64_t len);
|
||||
|
||||
|
||||
static inline const char *dev_name(struct device *dev) {
|
||||
return list_item(dev->aliases.n, struct str_list)->str;
|
||||
static inline const char *dev_name(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);
|
||||
|
||||
static inline int is_lvm_partition(const char *name) {
|
||||
static inline int is_lvm_partition(const char *name)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
static inline int dev_is_open(struct device *dev)
|
||||
{
|
||||
return dev->fd >= 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -18,17 +18,84 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include "lib.h"
|
||||
#include "metadata.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "log.h"
|
||||
#include "display.h"
|
||||
#include "activate.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
#define SIZE_BUF 128
|
||||
|
||||
char *display_size(unsigned long long size, size_len_t sl)
|
||||
static struct {
|
||||
alloc_policy_t alloc;
|
||||
const char *str;
|
||||
} _policies[] = {
|
||||
{
|
||||
ALLOC_NEXT_FREE, "next free"}, {
|
||||
ALLOC_CONTIGUOUS, "contiguous"}, {
|
||||
ALLOC_DEFAULT, "next free (default)"}
|
||||
};
|
||||
|
||||
static struct {
|
||||
segment_type_t segtype;
|
||||
const char *str;
|
||||
} _segtypes[] = {
|
||||
{
|
||||
SEG_STRIPED, "striped"}, {
|
||||
SEG_MIRROR, "mirror"}, {
|
||||
SEG_SNAPSHOT, "snapshot"}
|
||||
};
|
||||
|
||||
static int _num_policies = sizeof(_policies) / sizeof(*_policies);
|
||||
static int _num_segtypes = sizeof(_segtypes) / sizeof(*_segtypes);
|
||||
|
||||
const char *get_alloc_string(alloc_policy_t alloc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < _num_policies; i++)
|
||||
if (_policies[i].alloc == alloc)
|
||||
return _policies[i].str;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *get_segtype_string(segment_type_t segtype)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < _num_segtypes; i++)
|
||||
if (_segtypes[i].segtype == segtype)
|
||||
return _segtypes[i].str;
|
||||
|
||||
return 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;
|
||||
|
||||
log_error("Unrecognised allocation policy - using default");
|
||||
return ALLOC_DEFAULT;
|
||||
}
|
||||
|
||||
segment_type_t get_segtype_from_string(const char *str)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < _num_segtypes; i++)
|
||||
if (!strcmp(_segtypes[i].str, str))
|
||||
return _segtypes[i].segtype;
|
||||
|
||||
log_error("Unrecognised segment type - using default (striped)");
|
||||
return SEG_STRIPED;
|
||||
}
|
||||
|
||||
char *display_size(uint64_t size, size_len_t sl)
|
||||
{
|
||||
int s;
|
||||
ulong byte = 1024 * 1024 * 1024;
|
||||
@@ -60,68 +127,36 @@ char *display_size(unsigned long long size, size_len_t sl)
|
||||
return size_buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: this function is badly named, it doesn't display the data it
|
||||
* creates a new uuid string with -'s in it. It would be better if
|
||||
* the destination was passed in as well. EJT
|
||||
*/
|
||||
char *display_uuid(char *uuidstr)
|
||||
{
|
||||
int i, j;
|
||||
char *uuid;
|
||||
|
||||
if ((!uuidstr) || !(uuid = dbg_malloc(NAME_LEN))) {
|
||||
log_error("no memory for uuid display buffer");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(uuid, 0, NAME_LEN);
|
||||
|
||||
i = 6;
|
||||
memcpy(uuid, uuidstr, i);
|
||||
uuidstr += i;
|
||||
|
||||
for (j = 0; j < 6; j++) {
|
||||
uuid[i++] = '-';
|
||||
memcpy(&uuid[i], uuidstr, 4);
|
||||
uuidstr += 4;
|
||||
i += 4;
|
||||
}
|
||||
|
||||
memcpy(&uuid[i], uuidstr, 2);
|
||||
|
||||
/* Caller must free */
|
||||
return uuid;
|
||||
}
|
||||
|
||||
void pvdisplay_colons(struct physical_volume *pv)
|
||||
{
|
||||
char *uuid;
|
||||
char uuid[64];
|
||||
|
||||
if (!pv)
|
||||
return;
|
||||
|
||||
uuid = display_uuid(pv->id.uuid);
|
||||
if (!id_write_format(&pv->id, uuid, sizeof(uuid))) {
|
||||
stack;
|
||||
return;
|
||||
}
|
||||
|
||||
log_print("%s:%s:%" PRIu64 ":-1:%u:%u:-1:%" PRIu64 ":%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 & ALLOCATED_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");
|
||||
|
||||
dbg_free(uuid);
|
||||
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 physical_volume *pv, void *handle)
|
||||
{
|
||||
char *uuid;
|
||||
char uuid[64];
|
||||
char *size, *size1; /*, *size2; */
|
||||
|
||||
uint64_t pe_free;
|
||||
@@ -129,18 +164,22 @@ void pvdisplay_full(struct physical_volume *pv)
|
||||
if (!pv)
|
||||
return;
|
||||
|
||||
uuid = display_uuid(pv->id.uuid);
|
||||
if (!id_write_format(&pv->id, uuid, sizeof(uuid))) {
|
||||
stack;
|
||||
return;
|
||||
}
|
||||
|
||||
log_print("--- %sPhysical volume ---", pv->pe_size ? "" : "NEW ");
|
||||
log_print("PV Name %s", dev_name(pv->dev));
|
||||
log_print("VG Name %s", pv->vg_name);
|
||||
log_print("VG Name %s%s", pv->vg_name,
|
||||
pv->status & EXPORTED_VG ? " (exported)" : "");
|
||||
|
||||
size = display_size(pv->size / 2, SIZE_SHORT);
|
||||
size = display_size((uint64_t) pv->size / 2, SIZE_SHORT);
|
||||
if (pv->pe_size && pv->pe_count) {
|
||||
size1 = display_size((pv->size - pv->pe_count * pv->pe_size)
|
||||
/ 2, SIZE_SHORT);
|
||||
|
||||
/******** FIXME display LVM on-disk data size
|
||||
/******** FIXME display LVM on-disk data size
|
||||
size2 = display_size(pv->size / 2, SIZE_SHORT);
|
||||
********/
|
||||
|
||||
@@ -153,282 +192,348 @@ void pvdisplay_full(struct physical_volume *pv)
|
||||
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);
|
||||
*/
|
||||
|
||||
log_print("PV Status %savailable",
|
||||
(pv->status & ACTIVE) ? "" : "NOT ");
|
||||
|
||||
pe_free = pv->pe_count - pv->pe_allocated;
|
||||
if (pv->pe_count && (pv->status & ALLOCATED_PV))
|
||||
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);
|
||||
*********/
|
||||
/* LV count is no longer available when displaying PV
|
||||
log_print("Cur LV %u", vg->lv_count);
|
||||
*/
|
||||
log_print("PE Size (KByte) %" PRIu64, pv->pe_size / 2);
|
||||
log_print("Total PE %u", pv->pe_count);
|
||||
log_print("Free PE %" PRIu64, pe_free);
|
||||
log_print("Allocated PE %u", pv->pe_allocated);
|
||||
|
||||
#ifdef LVM_FUTURE
|
||||
printf("Stale PE %u", pv->pe_stale);
|
||||
#endif
|
||||
|
||||
log_print("Allocated PE %u", pv->pe_alloc_count);
|
||||
log_print("PV UUID %s", *uuid ? uuid : "none");
|
||||
log_print(" ");
|
||||
|
||||
dbg_free(uuid);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void pv_display_short(struct physical_volume *pv)
|
||||
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct physical_volume *pv, void *handle)
|
||||
{
|
||||
if (!pv)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
log_print("PV Name %s ", dev_name(pv->dev));
|
||||
/* FIXME pv->pv_number); */
|
||||
log_print("PV Status %savailable / %sallocatable",
|
||||
(pv->status & ACTIVE) ? "" : "NOT ",
|
||||
(pv->status & ALLOCATED_PV) ? "" : "NOT ");
|
||||
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);
|
||||
|
||||
return;
|
||||
log_print(" ");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lvdisplay_colons(struct logical_volume *lv)
|
||||
{
|
||||
log_print("%s/%s:%s:%d:%d:-1:%d:%" PRIu64 ":%d:-1:%d:%d:-1:-1",
|
||||
/* FIXME Prefix - attach to struct volume_group? */
|
||||
int inkernel;
|
||||
struct dm_info 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",
|
||||
lv->vg->cmd->dev_dir,
|
||||
lv->vg->name,
|
||||
lv->name,
|
||||
lv->vg->name,
|
||||
(lv->status & (LVM_READ | LVM_WRITE)) >> 8,
|
||||
lv->status & ACTIVE,
|
||||
(lv->status & (LVM_READ | LVM_WRITE)) >> 8, inkernel ? 1 : 0,
|
||||
/* FIXME lv->lv_number, */
|
||||
lvs_in_vg_opened(lv->vg), lv->size, lv->le_count,
|
||||
inkernel ? info.open_count : 0, lv->size, lv->le_count,
|
||||
/* FIXME Add num allocated to struct! lv->lv_allocated_le, */
|
||||
((lv->status & ALLOC_STRICT) +
|
||||
(lv->status & ALLOC_CONTIGUOUS) * 2), lv->read_ahead
|
||||
/* FIXME device num MAJOR(lv->lv_dev), MINOR(lv->lv_dev) */
|
||||
);
|
||||
(lv->alloc == ALLOC_CONTIGUOUS ? 2 : 0), lv->read_ahead,
|
||||
inkernel ? info.major : -1, inkernel ? info.minor : -1);
|
||||
return;
|
||||
}
|
||||
|
||||
void lvdisplay_full(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, snap_active;
|
||||
char uuid[64];
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
inkernel = lv_info(lv, &info) && info.exists;
|
||||
|
||||
log_print("--- Logical volume ---");
|
||||
|
||||
/* FIXME Add dev_dir */
|
||||
log_print("LV Name %s/%s", lv->vg->name, lv->name);
|
||||
log_print("LV Name %s%s/%s", lv->vg->cmd->dev_dir,
|
||||
lv->vg->name, lv->name);
|
||||
log_print("VG Name %s", lv->vg->name);
|
||||
|
||||
log_print("LV UUID %s", uuid);
|
||||
|
||||
log_print("LV Write Access %s",
|
||||
(lv->status & LVM_WRITE) ? "read/write" : "read only");
|
||||
|
||||
/******* 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 ");
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
***********/
|
||||
if (lv_is_origin(lv)) {
|
||||
log_print("LV snapshot status source of");
|
||||
|
||||
log_print("LV Status %savailable",
|
||||
(lv->status & ACTIVE) ? "" : "NOT ");
|
||||
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);
|
||||
log_print(" %s%s/%s [%s]",
|
||||
lv->vg->cmd->dev_dir, lv->vg->name,
|
||||
snap->cow->name,
|
||||
(snap_active > 0) ? "active" : "INACTIVE");
|
||||
}
|
||||
} else if ((snap = find_cow(lv))) {
|
||||
snap_active = lv_snapshot_percent(lv, &snap_percent);
|
||||
log_print("LV snapshot status %s destination for %s%s/%s",
|
||||
(snap_active > 0) ? "active" : "INACTIVE",
|
||||
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 ");
|
||||
|
||||
/********* FIXME lv_number
|
||||
log_print("LV # %u", lv->lv_number + 1);
|
||||
************/
|
||||
|
||||
/********* FIXME lv_open
|
||||
log_print("# open %u\n", lv->lv_open);
|
||||
**********/
|
||||
/********
|
||||
#ifdef LVM_FUTURE
|
||||
printf("Mirror copies %u\n", lv->lv_mirror_copies);
|
||||
printf("Consistency recovery ");
|
||||
if (lv->lv_recovery | LV_BADBLOCK_ON)
|
||||
printf("bad blocks\n");
|
||||
else
|
||||
printf("none\n");
|
||||
printf("Schedule %u\n", lv->lv_schedule);
|
||||
#endif
|
||||
********/
|
||||
if (inkernel)
|
||||
log_print("# open %u", info.open_count);
|
||||
|
||||
size = display_size(lv->size / 2, SIZE_SHORT);
|
||||
size = display_size(snap ? snap->origin->size / 2 : 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);
|
||||
**********/
|
||||
|
||||
log_print("Segments %u", list_size(&lv->segments));
|
||||
|
||||
/********* FIXME Stripes & stripesize for each segment
|
||||
log_print("Stripe size (KByte) %u", lv->stripesize / 2);
|
||||
***********/
|
||||
|
||||
if (snap) {
|
||||
if (snap_percent == -1)
|
||||
snap_percent = 100;
|
||||
|
||||
size = display_size(snap->chunk_size / 2, SIZE_SHORT);
|
||||
log_print("Snapshot chunk size %s", size);
|
||||
dbg_free(size);
|
||||
|
||||
/*
|
||||
size = display_size(lv->size / 2, SIZE_SHORT);
|
||||
sscanf(size, "%f", &fsize);
|
||||
fused = fsize * snap_percent / 100;
|
||||
*/
|
||||
log_print("Allocated to snapshot %.2f%% ", /* [%.2f/%s]", */
|
||||
snap_percent); /*, fused, size); */
|
||||
/* dbg_free(size); */
|
||||
}
|
||||
|
||||
/********** 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);
|
||||
}
|
||||
size = ???
|
||||
log_print("Allocated to COW-table %s", size);
|
||||
dbg_free(size);
|
||||
}
|
||||
******************/
|
||||
|
||||
if (lv->stripes > 1) {
|
||||
log_print("Stripes %u", lv->stripes);
|
||||
/*********** FIXME stripesize
|
||||
log_print("Stripe size (KByte) %u", lv->stripesize / 2);
|
||||
***********/
|
||||
}
|
||||
log_print("Allocation %s", get_alloc_string(lv->alloc));
|
||||
log_print("Read ahead sectors %u", lv->read_ahead);
|
||||
|
||||
/**************
|
||||
#ifdef LVM_FUTURE
|
||||
printf("Bad block ");
|
||||
if (lv->lv_badblock == LV_BADBLOCK_ON)
|
||||
printf("on\n");
|
||||
else
|
||||
printf("off\n");
|
||||
#endif
|
||||
***************/
|
||||
if (lv->status & FIXED_MINOR)
|
||||
log_print("Persistent minor %d", lv->minor);
|
||||
|
||||
/* 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" :
|
||||
"");
|
||||
if (inkernel)
|
||||
log_print("Block device %d:%d", info.major,
|
||||
info.minor);
|
||||
|
||||
log_print("Read ahead sectors %u\n", lv->read_ahead);
|
||||
log_print(" ");
|
||||
|
||||
/****************
|
||||
#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
|
||||
*************/
|
||||
|
||||
/********* FIXME blockdev
|
||||
printf("Block device %d:%d\n",
|
||||
MAJOR(lv->lv_dev), MINOR(lv->lv_dev));
|
||||
*************/
|
||||
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void lvdisplay_extents(struct logical_volume *lv)
|
||||
void _display_stripe(struct lv_segment *seg, int s, const char *pre)
|
||||
{
|
||||
int le;
|
||||
struct list *pvh;
|
||||
struct physical_volume *pv;
|
||||
uint32_t len = seg->len / seg->stripes;
|
||||
|
||||
log_verbose("--- Distribution of logical volume on physical "
|
||||
"volumes ---");
|
||||
log_verbose("PV Name PE on PV ");
|
||||
log_print("%sPhysical volume\t%s", pre,
|
||||
seg->area[s].pv ? dev_name(seg->area[s].pv->dev) : "Missing");
|
||||
|
||||
list_iterate(pvh, &lv->vg->pvs) {
|
||||
int count = 0;
|
||||
pv = &list_item(pvh, struct pv_list)->pv;
|
||||
for (le = 0; le < lv->le_count; le++)
|
||||
if (lv->map[le].pv->dev == pv->dev)
|
||||
count++;
|
||||
if (count)
|
||||
log_verbose("%-25s %d", dev_name(pv->dev), count);
|
||||
if (seg->area[s].pv)
|
||||
log_print("%sPhysical extents\t%d to %d", pre,
|
||||
seg->area[s].pe, seg->area[s].pe + len - 1);
|
||||
}
|
||||
|
||||
int lvdisplay_segments(struct logical_volume *lv)
|
||||
{
|
||||
int s;
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
|
||||
log_print("--- Segments ---");
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
|
||||
log_print("Logical extent %d to %d:",
|
||||
seg->le, seg->le + seg->len - 1);
|
||||
|
||||
log_print(" Type\t\t%s", get_segtype_string(seg->type));
|
||||
|
||||
switch (seg->type) {
|
||||
case SEG_STRIPED:
|
||||
if (seg->stripes == 1)
|
||||
_display_stripe(seg, 0, " ");
|
||||
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(" ");
|
||||
break;
|
||||
case SEG_SNAPSHOT:
|
||||
case SEG_MIRROR:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
/********* FIXME "reads writes"
|
||||
log_print(" ");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
printf("\n --- logical volume i/o statistic ---\n"
|
||||
" %d reads %d writes\n", sum_reads, sum_writes);
|
||||
void vgdisplay_extents(struct volume_group *vg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
******* */
|
||||
void vgdisplay_full(struct volume_group *vg)
|
||||
{
|
||||
uint32_t access;
|
||||
uint32_t active_pvs;
|
||||
char *s1;
|
||||
char uuid[64];
|
||||
|
||||
log_verbose(" ");
|
||||
log_verbose("--- Logical extents ---");
|
||||
log_verbose("LE PV PE");
|
||||
if (vg->status & PARTIAL_VG)
|
||||
active_pvs = list_size(&vg->pvs);
|
||||
else
|
||||
active_pvs = vg->pv_count;
|
||||
|
||||
for (le = 0; le < lv->le_count; le++) {
|
||||
log_verbose("%05d %-25s %05u ", le,
|
||||
dev_name(lv->map[le].pv->dev), lv->map[le].pe);
|
||||
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" : "",
|
||||
access == LVM_READ ? "read" : "",
|
||||
access == LVM_WRITE ? "write" : "",
|
||||
access == 0 ? "error" : "");
|
||||
log_print("VG Status %s%sresizable",
|
||||
vg->status & EXPORTED_VG ? "exported/" : "",
|
||||
vg->status & RESIZEABLE_VG ? "" : "NOT ");
|
||||
/* vg number not part of LVM2 design
|
||||
log_print ("VG # %u\n", vg->vg_number);
|
||||
*/
|
||||
if (vg->status & CLUSTERED) {
|
||||
log_print("Clustered yes");
|
||||
log_print("Shared %s",
|
||||
vg->status & SHARED ? "yes" : "no");
|
||||
}
|
||||
log_print("MAX LV %u", vg->max_lv);
|
||||
log_print("Cur LV %u", vg->lv_count);
|
||||
log_print("Open LV %u", lvs_in_vg_opened(vg));
|
||||
/****** FIXME Max LV Size
|
||||
log_print ( "MAX LV Size %s",
|
||||
( s1 = display_size ( LVM_LV_SIZE_MAX(vg) / 2, SIZE_SHORT)));
|
||||
free ( s1);
|
||||
*********/
|
||||
log_print("Max PV %u", vg->max_pv);
|
||||
log_print("Cur PV %u", vg->pv_count);
|
||||
log_print("Act PV %u", active_pvs);
|
||||
|
||||
s1 = display_size((uint64_t) vg->extent_count * (vg->extent_size / 2),
|
||||
SIZE_SHORT);
|
||||
log_print("VG Size %s", s1);
|
||||
dbg_free(s1);
|
||||
|
||||
s1 = display_size(vg->extent_size / 2, SIZE_SHORT);
|
||||
log_print("PE Size %s", s1);
|
||||
dbg_free(s1);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
if (!id_write_format(&vg->id, uuid, sizeof(uuid))) {
|
||||
stack;
|
||||
return;
|
||||
}
|
||||
|
||||
log_print("VG UUID %s", uuid);
|
||||
log_print(" ");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void vgdisplay_colons(struct volume_group *vg)
|
||||
{
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
@@ -25,29 +25,37 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {SIZE_LONG=0, SIZE_SHORT=1} size_len_t;
|
||||
typedef enum { SIZE_LONG = 0, SIZE_SHORT = 1 } size_len_t;
|
||||
|
||||
/* Specify size in KB */
|
||||
char *display_size(unsigned long long size, size_len_t sl);
|
||||
char *display_size(uint64_t size, size_len_t sl);
|
||||
char *display_uuid(char *uuidstr);
|
||||
|
||||
void pvdisplay_colons(struct physical_volume *pv);
|
||||
void pvdisplay_full(struct physical_volume *pv);
|
||||
void pvdisplay_full(struct physical_volume *pv, void *handle);
|
||||
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct physical_volume *pv, void *handle);
|
||||
|
||||
void lvdisplay_colons(struct logical_volume *lv);
|
||||
void lvdisplay_extents(struct logical_volume *lv);
|
||||
void lvdisplay_full(struct logical_volume *lv);
|
||||
int lvdisplay_segments(struct logical_volume *lv);
|
||||
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
void *handle);
|
||||
|
||||
#if 0
|
||||
void pv_show_short(pv_t * pv);
|
||||
void pv_display_pe(pv_t * pv, pe_disk_t * pe);
|
||||
void pv_display_pe_free(int pe_free, int p);
|
||||
void pv_display_pe_text(pv_t * pv, pe_disk_t * pe, lv_disk_t * lvs);
|
||||
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);
|
||||
|
||||
static inline unsigned long get_pe_offset(ulong p, pv_t *pv)
|
||||
{
|
||||
return pv->pe_start + (p * pv->pe_size);
|
||||
}
|
||||
/*
|
||||
* Allocation policy display conversion routines.
|
||||
*/
|
||||
const char *get_alloc_string(alloc_policy_t alloc);
|
||||
alloc_policy_t get_alloc_from_string(const char *str);
|
||||
|
||||
/*
|
||||
* Segment type display conversion routines.
|
||||
*/
|
||||
segment_type_t get_segtype_from_string(const char *str);
|
||||
const char *get_segtype_string(segment_type_t segtype);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@@ -4,9 +4,8 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "filter-composite.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
@@ -36,7 +35,6 @@ static void _destroy(struct dev_filter *f)
|
||||
dbg_free(f);
|
||||
}
|
||||
|
||||
|
||||
struct dev_filter *composite_filter_create(int n, ...)
|
||||
{
|
||||
struct dev_filter **filters = dbg_malloc(sizeof(*filters) * (n + 1));
|
||||
|
@@ -4,14 +4,12 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "config.h"
|
||||
#include "dev-cache.h"
|
||||
#include "hash.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "log.h"
|
||||
#include "filter-persistent.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
@@ -43,10 +41,13 @@ int persistent_filter_wipe(struct dev_filter *f)
|
||||
struct pfilter *pf = (struct pfilter *) f->private;
|
||||
|
||||
hash_wipe(pf->devices);
|
||||
/* Trigger complete device scan */
|
||||
dev_cache_scan(1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_array(struct pfilter *pf, struct config_file *cf,
|
||||
static int _read_array(struct pfilter *pf, struct config_tree *cf,
|
||||
const char *path, void *data)
|
||||
{
|
||||
struct config_node *cn;
|
||||
@@ -54,7 +55,7 @@ static int _read_array(struct pfilter *pf, struct config_file *cf,
|
||||
|
||||
if (!(cn = find_config_node(cf->root, path, '/'))) {
|
||||
log_very_verbose("Couldn't find %s array in '%s'",
|
||||
path, pf->file);
|
||||
path, pf->file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -65,13 +66,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 +84,33 @@ int persistent_filter_load(struct dev_filter *f)
|
||||
struct pfilter *pf = (struct pfilter *) f->private;
|
||||
|
||||
int r = 0;
|
||||
struct config_file *cf;
|
||||
struct config_tree *cf;
|
||||
|
||||
if (!(cf = create_config_file())) {
|
||||
if (!(cf = create_config_tree())) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!read_config(cf, pf->file)) {
|
||||
if (!read_config_file(cf, pf->file)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
_read_array(pf, cf, "persistent_filter_cache/valid_devices",
|
||||
PF_GOOD_DEVICE);
|
||||
_read_array(pf, cf, "persistent_filter_cache/invalid_devices",
|
||||
PF_BAD_DEVICE);
|
||||
/* We don't gain anything by holding invalid devices */
|
||||
/* _read_array(pf, cf, "persistent_filter_cache/invalid_devices",
|
||||
PF_BAD_DEVICE); */
|
||||
|
||||
if (hash_get_num_entries(pf->devices))
|
||||
/* Did we find anything? */
|
||||
if (hash_get_num_entries(pf->devices)) {
|
||||
/* We populated dev_cache ourselves */
|
||||
dev_cache_scan(0);
|
||||
r = 1;
|
||||
}
|
||||
|
||||
out:
|
||||
destroy_config_file(cf);
|
||||
out:
|
||||
destroy_config_tree(cf);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -141,12 +149,24 @@ int persistent_filter_dump(struct dev_filter *f)
|
||||
struct pfilter *pf = (struct pfilter *) f->private;
|
||||
|
||||
FILE *fp;
|
||||
|
||||
|
||||
if (!hash_get_num_entries(pf->devices)) {
|
||||
log_very_verbose("Internal persistent device cache empty "
|
||||
"- 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;
|
||||
}
|
||||
|
||||
@@ -154,7 +174,8 @@ int persistent_filter_dump(struct dev_filter *f)
|
||||
fprintf(fp, "persistent_filter_cache {\n");
|
||||
|
||||
_write_array(pf, fp, "valid_devices", PF_GOOD_DEVICE);
|
||||
_write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE);
|
||||
/* We don't gain anything by remembering invalid devices */
|
||||
/* _write_array(pf, fp, "invalid_devices", PF_BAD_DEVICE); */
|
||||
|
||||
fprintf(fp, "}\n");
|
||||
fclose(fp);
|
||||
@@ -170,7 +191,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);
|
||||
@@ -227,7 +248,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);
|
||||
|
@@ -4,12 +4,12 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "pool.h"
|
||||
#include "filter-regex.h"
|
||||
#include "matcher.h"
|
||||
#include "device.h"
|
||||
#include "bitset.h"
|
||||
#include "log.h"
|
||||
#include "list.h"
|
||||
|
||||
struct rfilter {
|
||||
@@ -128,8 +128,7 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
||||
* the matcher gives.
|
||||
*/
|
||||
for (v = val, i = count - 1; v; v = v->next, i--)
|
||||
if (!_extract_pattern(scratch, v->v.str,
|
||||
regex, rf->accept, i)) {
|
||||
if (!_extract_pattern(scratch, v->v.str, regex, rf->accept, i)) {
|
||||
log_info("invalid filter pattern");
|
||||
goto out;
|
||||
}
|
||||
@@ -137,12 +136,12 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
||||
/*
|
||||
* build the matcher.
|
||||
*/
|
||||
if (!(rf->engine = matcher_create(rf->mem,
|
||||
(const char **) regex, count)))
|
||||
if (!(rf->engine = matcher_create(rf->mem, (const char **) regex,
|
||||
count)))
|
||||
stack;
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
out:
|
||||
pool_destroy(scratch);
|
||||
return r;
|
||||
}
|
||||
@@ -221,8 +220,7 @@ struct dev_filter *regex_filter_create(struct config_value *patterns)
|
||||
f->private = rf;
|
||||
return f;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
pool_destroy(mem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@@ -18,17 +18,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "dbg_malloc.h"
|
||||
#include "log.h"
|
||||
#include "lib.h"
|
||||
#include "dev-cache.h"
|
||||
#include "filter.h"
|
||||
#include "lvm-string.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>
|
||||
|
||||
@@ -39,6 +37,9 @@ typedef struct {
|
||||
int max_partitions;
|
||||
} device_info_t;
|
||||
|
||||
static int _md_major = -1;
|
||||
|
||||
/* FIXME Move list into config file */
|
||||
static device_info_t device_info[] = {
|
||||
{"ide", 16}, /* IDE disk */
|
||||
{"sd", 16}, /* SCSI disk */
|
||||
@@ -50,10 +51,11 @@ static device_info_t device_info[] = {
|
||||
{"ida", 16}, /* Compaq SMART2 */
|
||||
{"cciss", 16}, /* Compaq CCISS array */
|
||||
{"ubd", 16}, /* User-mode virtual block device */
|
||||
{"ataraid", 16}, /* ATA Raid */
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
static int *scan_proc_dev(void);
|
||||
static int *scan_proc_dev(const char *proc);
|
||||
|
||||
static int passes_lvm_type_device_filter(struct dev_filter *f,
|
||||
struct device *dev)
|
||||
@@ -66,21 +68,21 @@ static int passes_lvm_type_device_filter(struct dev_filter *f,
|
||||
return 0;
|
||||
|
||||
/* Check it's accessible */
|
||||
if ((fd = open(name, O_RDONLY)) < 0) {
|
||||
log_debug("Unable to open %s: %s", name, strerror(errno));
|
||||
if ((fd = open(name, O_RDONLY)) < 0) {
|
||||
log_debug("Unable to open %s: %s", name, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
close(fd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dev_filter *lvm_type_filter_create()
|
||||
struct dev_filter *lvm_type_filter_create(const char *proc)
|
||||
{
|
||||
struct dev_filter *f;
|
||||
|
||||
if (!(f = dbg_malloc(sizeof (struct dev_filter)))) {
|
||||
if (!(f = dbg_malloc(sizeof(struct dev_filter)))) {
|
||||
log_error("LVM type filter allocation failed");
|
||||
return NULL;
|
||||
}
|
||||
@@ -88,12 +90,17 @@ struct dev_filter *lvm_type_filter_create()
|
||||
f->passes_filter = passes_lvm_type_device_filter;
|
||||
f->destroy = lvm_type_filter_destroy;
|
||||
|
||||
if (!(f->private = scan_proc_dev()))
|
||||
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);
|
||||
@@ -101,10 +108,11 @@ void lvm_type_filter_destroy(struct dev_filter *f)
|
||||
return;
|
||||
}
|
||||
|
||||
static int *scan_proc_dev(void)
|
||||
static int *scan_proc_dev(const char *proc)
|
||||
{
|
||||
char line[80];
|
||||
FILE *procdevices = NULL;
|
||||
char proc_devices[PATH_MAX];
|
||||
FILE *pd = NULL;
|
||||
int ret = 0;
|
||||
int i, j = 0;
|
||||
int line_maj = 0;
|
||||
@@ -113,18 +121,25 @@ static int *scan_proc_dev(void)
|
||||
|
||||
int *max_partitions_by_major;
|
||||
|
||||
if (!(max_partitions_by_major = dbg_malloc(sizeof (int) * NUMBER_OF_MAJORS))) {
|
||||
if (!(max_partitions_by_major =
|
||||
dbg_malloc(sizeof(int) * NUMBER_OF_MAJORS))) {
|
||||
log_error("Filter failed to allocate max_partitions_by_major");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(procdevices = fopen("/proc/devices", "r"))) {
|
||||
log_error("Failed to open /proc/devices: %s", strerror(errno));
|
||||
if (lvm_snprintf(proc_devices, sizeof(proc_devices),
|
||||
"%s/devices", proc) < 0) {
|
||||
log_error("Failed to create /proc/devices string");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(max_partitions_by_major, 0, sizeof (int) * NUMBER_OF_MAJORS);
|
||||
while (fgets(line, 80, procdevices) != NULL) {
|
||||
if (!(pd = fopen(proc_devices, "r"))) {
|
||||
log_sys_error("fopen", proc_devices);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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')
|
||||
i++;
|
||||
@@ -146,8 +161,12 @@ static int *scan_proc_dev(void)
|
||||
while (line[i] == ' ' && line[i] != '\0')
|
||||
i++;
|
||||
|
||||
/* Look for md device */
|
||||
if (!strncmp("md", line + i, 2) && isspace(*(line + i + 2)))
|
||||
_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);
|
||||
@@ -161,6 +180,6 @@ static int *scan_proc_dev(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(procdevices);
|
||||
fclose(pd);
|
||||
return max_partitions_by_major;
|
||||
}
|
||||
|
@@ -21,9 +21,11 @@
|
||||
#ifndef _LVM_FILTER_H
|
||||
#define _LVM_FILTER_H
|
||||
|
||||
struct dev_filter *lvm_type_filter_create();
|
||||
struct dev_filter *lvm_type_filter_create(const char *proc);
|
||||
|
||||
void lvm_type_filter_destroy(struct dev_filter *f);
|
||||
|
||||
int md_major(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
7
lib/format1/.export.sym
Normal file
7
lib/format1/.export.sym
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
global:
|
||||
init_format;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
31
lib/format1/Makefile.in
Normal file
31
lib/format1/Makefile.in
Normal file
@@ -0,0 +1,31 @@
|
||||
#
|
||||
# Copyright (C) 2002 Sistina Software (UK) Limited.
|
||||
#
|
||||
# This file is released under the LGPL.
|
||||
#
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
SOURCES=\
|
||||
disk-rep.c \
|
||||
format1.c \
|
||||
import-export.c \
|
||||
import-extents.c \
|
||||
layout.c \
|
||||
lvm1-label.c \
|
||||
vg_number.c
|
||||
|
||||
TARGETS=liblvm2format1.so
|
||||
|
||||
include ../../make.tmpl
|
||||
|
||||
|
||||
install: libformat1.so
|
||||
$(INSTALL) -D -o $(OWNER) -g $(GROUP) -m 555 $(STRIP) $< \
|
||||
$(libdir)/liblvm2format1.so.$(LIB_VERSION)
|
||||
$(LN_S) -f liblvm2format1.so.$(LIB_VERSION) $(libdir)/liblvm2format1.so
|
||||
|
||||
.PHONY: install
|
||||
|
@@ -4,14 +4,16 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "disk-rep.h"
|
||||
#include "pool.h"
|
||||
#include "xlate.h"
|
||||
#include "log.h"
|
||||
#include "filter.h"
|
||||
#include "cache.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)
|
||||
@@ -25,66 +27,71 @@
|
||||
*/
|
||||
static void _xlate_pvd(struct pv_disk *disk)
|
||||
{
|
||||
xx16(version);
|
||||
xx16(version);
|
||||
|
||||
xx32(pv_on_disk.base); xx32(pv_on_disk.size);
|
||||
xx32(vg_on_disk.base); xx32(vg_on_disk.size);
|
||||
xx32(pv_uuidlist_on_disk.base); xx32(pv_uuidlist_on_disk.size);
|
||||
xx32(lv_on_disk.base); xx32(lv_on_disk.size);
|
||||
xx32(pe_on_disk.base); xx32(pe_on_disk.size);
|
||||
xx32(pv_on_disk.base);
|
||||
xx32(pv_on_disk.size);
|
||||
xx32(vg_on_disk.base);
|
||||
xx32(vg_on_disk.size);
|
||||
xx32(pv_uuidlist_on_disk.base);
|
||||
xx32(pv_uuidlist_on_disk.size);
|
||||
xx32(lv_on_disk.base);
|
||||
xx32(lv_on_disk.size);
|
||||
xx32(pe_on_disk.base);
|
||||
xx32(pe_on_disk.size);
|
||||
|
||||
xx32(pv_major);
|
||||
xx32(pv_number);
|
||||
xx32(pv_status);
|
||||
xx32(pv_allocatable);
|
||||
xx32(pv_size);
|
||||
xx32(lv_cur);
|
||||
xx32(pe_size);
|
||||
xx32(pe_total);
|
||||
xx32(pe_allocated);
|
||||
xx32(pv_major);
|
||||
xx32(pv_number);
|
||||
xx32(pv_status);
|
||||
xx32(pv_allocatable);
|
||||
xx32(pv_size);
|
||||
xx32(lv_cur);
|
||||
xx32(pe_size);
|
||||
xx32(pe_total);
|
||||
xx32(pe_allocated);
|
||||
xx32(pe_start);
|
||||
}
|
||||
|
||||
static void _xlate_lvd(struct lv_disk *disk)
|
||||
{
|
||||
xx32(lv_access);
|
||||
xx32(lv_status);
|
||||
xx32(lv_open);
|
||||
xx32(lv_dev);
|
||||
xx32(lv_number);
|
||||
xx32(lv_mirror_copies);
|
||||
xx32(lv_recovery);
|
||||
xx32(lv_schedule);
|
||||
xx32(lv_size);
|
||||
xx32(lv_snapshot_minor);
|
||||
xx16(lv_chunk_size);
|
||||
xx16(dummy);
|
||||
xx32(lv_allocated_le);
|
||||
xx32(lv_stripes);
|
||||
xx32(lv_stripesize);
|
||||
xx32(lv_badblock);
|
||||
xx32(lv_allocation);
|
||||
xx32(lv_io_timeout);
|
||||
xx32(lv_read_ahead);
|
||||
xx32(lv_access);
|
||||
xx32(lv_status);
|
||||
xx32(lv_open);
|
||||
xx32(lv_dev);
|
||||
xx32(lv_number);
|
||||
xx32(lv_mirror_copies);
|
||||
xx32(lv_recovery);
|
||||
xx32(lv_schedule);
|
||||
xx32(lv_size);
|
||||
xx32(lv_snapshot_minor);
|
||||
xx16(lv_chunk_size);
|
||||
xx16(dummy);
|
||||
xx32(lv_allocated_le);
|
||||
xx32(lv_stripes);
|
||||
xx32(lv_stripesize);
|
||||
xx32(lv_badblock);
|
||||
xx32(lv_allocation);
|
||||
xx32(lv_io_timeout);
|
||||
xx32(lv_read_ahead);
|
||||
}
|
||||
|
||||
static void _xlate_vgd(struct vg_disk *disk)
|
||||
{
|
||||
xx32(vg_number);
|
||||
xx32(vg_access);
|
||||
xx32(vg_status);
|
||||
xx32(lv_max);
|
||||
xx32(lv_cur);
|
||||
xx32(lv_open);
|
||||
xx32(pv_max);
|
||||
xx32(pv_cur);
|
||||
xx32(pv_act);
|
||||
xx32(dummy);
|
||||
xx32(vgda);
|
||||
xx32(pe_size);
|
||||
xx32(pe_total);
|
||||
xx32(pe_allocated);
|
||||
xx32(pvg_total);
|
||||
xx32(vg_number);
|
||||
xx32(vg_access);
|
||||
xx32(vg_status);
|
||||
xx32(lv_max);
|
||||
xx32(lv_cur);
|
||||
xx32(lv_open);
|
||||
xx32(pv_max);
|
||||
xx32(pv_cur);
|
||||
xx32(pv_act);
|
||||
xx32(dummy);
|
||||
xx32(vgda);
|
||||
xx32(pe_size);
|
||||
xx32(pe_total);
|
||||
xx32(pe_allocated);
|
||||
xx32(pvg_total);
|
||||
}
|
||||
|
||||
static void _xlate_extents(struct pe_disk *extents, int count)
|
||||
@@ -107,12 +114,12 @@ static int _munge_formats(struct pv_disk *pvd)
|
||||
switch (pvd->version) {
|
||||
case 1:
|
||||
pvd->pe_start = ((pvd->pe_on_disk.base +
|
||||
pvd->pe_on_disk.size) / SECTOR_SIZE);
|
||||
pvd->pe_on_disk.size) >> SECTOR_SHIFT);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
pvd->version = 1;
|
||||
pe_start = pvd->pe_start * SECTOR_SIZE;
|
||||
pe_start = pvd->pe_start << SECTOR_SHIFT;
|
||||
pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base;
|
||||
break;
|
||||
|
||||
@@ -123,13 +130,28 @@ static int _munge_formats(struct pv_disk *pvd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_pvd(struct disk_list *data)
|
||||
static int _read_pvd(struct device *dev, struct pv_disk *pvd)
|
||||
{
|
||||
struct pv_disk *pvd = &data->pvd;
|
||||
if (dev_read(data->dev, 0, sizeof(*pvd), pvd) != sizeof(*pvd))
|
||||
fail;
|
||||
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;
|
||||
}
|
||||
|
||||
_xlate_pvd(pvd);
|
||||
|
||||
if (pvd->id[0] != 'H' || pvd->id[1] != 'M') {
|
||||
log_very_verbose("%s does not have a valid LVM1 PV identifier",
|
||||
dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_munge_formats(pvd)) {
|
||||
log_very_verbose("format1: Unknown metadata version %d "
|
||||
"found on %s", pvd->version, dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -146,7 +168,7 @@ 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;
|
||||
unsigned long pos = data->pvd.vg_on_disk.base;
|
||||
ulong pos = data->pvd.vg_on_disk.base;
|
||||
if (dev_read(data->dev, pos, sizeof(*vgd), vgd) != sizeof(*vgd))
|
||||
fail;
|
||||
|
||||
@@ -163,7 +185,7 @@ static int _read_uuids(struct disk_list *data)
|
||||
ulong pos = data->pvd.pv_uuidlist_on_disk.base;
|
||||
ulong end = pos + data->pvd.pv_uuidlist_on_disk.size;
|
||||
|
||||
while(pos < end && num_read < data->vgd.pv_cur) {
|
||||
while (pos < end && num_read < data->vgd.pv_cur) {
|
||||
if (dev_read(data->dev, pos, sizeof(buffer), buffer) !=
|
||||
sizeof(buffer))
|
||||
fail;
|
||||
@@ -172,7 +194,7 @@ static int _read_uuids(struct disk_list *data)
|
||||
fail;
|
||||
|
||||
memcpy(ul->uuid, buffer, NAME_LEN);
|
||||
ul->uuid[NAME_LEN] = '\0';
|
||||
ul->uuid[NAME_LEN - 1] = '\0';
|
||||
|
||||
list_add(&data->uuids, &ul->list);
|
||||
|
||||
@@ -191,11 +213,11 @@ static inline int _check_lvd(struct lv_disk *lvd)
|
||||
static int _read_lvs(struct disk_list *data)
|
||||
{
|
||||
int i, read = 0;
|
||||
unsigned long pos;
|
||||
ulong pos;
|
||||
struct lvd_list *ll;
|
||||
struct vg_disk *vgd = &data->vgd;
|
||||
|
||||
for(i = 0; (i < vgd->lv_max) && (read < vgd->lv_cur); i++) {
|
||||
for (i = 0; (i < vgd->lv_max) && (read < vgd->lv_cur); i++) {
|
||||
pos = data->pvd.lv_on_disk.base + (i * sizeof(struct lv_disk));
|
||||
ll = pool_alloc(data->mem, sizeof(*ll));
|
||||
|
||||
@@ -219,7 +241,7 @@ 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);
|
||||
unsigned long pos = data->pvd.pe_on_disk.base;
|
||||
ulong pos = data->pvd.pe_on_disk.base;
|
||||
|
||||
if (!extents)
|
||||
fail;
|
||||
@@ -233,84 +255,114 @@ static int _read_extents(struct disk_list *data)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct disk_list *__read_disk(struct device *dev, struct pool *mem,
|
||||
/*
|
||||
* 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 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 cache_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(data)) {
|
||||
log_debug("Failed to read PV data from %s", name);
|
||||
if (!_read_pvd(dev, &dl->pvd)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (data->pvd.id[0] != 'H' || data->pvd.id[1] != 'M') {
|
||||
log_very_verbose("%s does not have a valid PV identifier",
|
||||
name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_munge_formats(&data->pvd)) {
|
||||
log_very_verbose("Unknown metadata version %d found on %s",
|
||||
data->pvd.version, name);
|
||||
goto bad;
|
||||
if (!(info = cache_add(fmt->labeller, dl->pvd.pv_uuid, dev,
|
||||
dl->pvd.vg_name, NULL)))
|
||||
stack;
|
||||
else {
|
||||
info->device_size = xlate32(dl->pvd.pv_size) << SECTOR_SHIFT;
|
||||
list_init(&info->mdas);
|
||||
info->status &= ~CACHE_INVALID;
|
||||
}
|
||||
|
||||
/*
|
||||
* is it an orphan ?
|
||||
*/
|
||||
if (data->pvd.vg_name == '\0') {
|
||||
log_very_verbose("%s is not a member of any VG", name);
|
||||
return data;
|
||||
if (!*dl->pvd.vg_name) {
|
||||
log_very_verbose("%s is not a member of any format1 VG", name);
|
||||
|
||||
/* Update VG cache */
|
||||
/* vgcache_add(dl->pvd.vg_name, NULL, dev, fmt); */
|
||||
|
||||
return (vg_name) ? NULL : dl;
|
||||
}
|
||||
|
||||
if (vg_name && strcmp(vg_name, data->pvd.vg_name)) {
|
||||
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(dl);
|
||||
|
||||
/* Update VG cache with what we found */
|
||||
/* vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt); */
|
||||
|
||||
if (vg_name && strcmp(vg_name, dl->pvd.vg_name)) {
|
||||
log_very_verbose("%s is not a member of the VG %s",
|
||||
name, vg_name);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!_read_vgd(data)) {
|
||||
log_error("Failed to read VG data from PV (%s)", 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 VG %s", name, 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);
|
||||
bad:
|
||||
pool_free(dl->mem, dl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct disk_list *read_disk(struct device *dev, struct pool *mem,
|
||||
const char *vg_name)
|
||||
struct disk_list *read_disk(struct format_type *fmt, struct device *dev,
|
||||
struct pool *mem, const char *vg_name)
|
||||
{
|
||||
struct disk_list *r;
|
||||
|
||||
@@ -319,7 +371,7 @@ struct disk_list *read_disk(struct device *dev, struct pool *mem,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = __read_disk(dev, mem, vg_name);
|
||||
r = __read_disk(fmt, dev, mem, vg_name);
|
||||
|
||||
if (!dev_close(dev))
|
||||
stack;
|
||||
@@ -327,23 +379,76 @@ struct disk_list *read_disk(struct device *dev, struct pool *mem,
|
||||
return r;
|
||||
}
|
||||
|
||||
static void _add_pv_to_list(struct list *head, struct disk_list *data)
|
||||
{
|
||||
struct list *pvdh;
|
||||
struct pv_disk *pvd;
|
||||
|
||||
list_iterate(pvdh, head) {
|
||||
pvd = &list_item(pvdh, struct disk_list)->pvd;
|
||||
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,
|
||||
dev_name(data->dev));
|
||||
return;
|
||||
}
|
||||
log_very_verbose("Duplicate PV %s - using md %s",
|
||||
pvd->pv_uuid, dev_name(data->dev));
|
||||
list_del(pvdh);
|
||||
break;
|
||||
}
|
||||
}
|
||||
list_add(head, &data->list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Build a list of pv_d's structures, allocated
|
||||
* from mem. We keep track of the first object
|
||||
* allocated form the pool so we can free off all
|
||||
* the memory if something goes wrong.
|
||||
* Build a list of pv_d's structures, allocated from mem.
|
||||
* We keep track of the first object allocated form the pool
|
||||
* so we can free off all the memory if something goes wrong.
|
||||
*/
|
||||
int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
|
||||
struct pool *mem, struct list *head)
|
||||
int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
|
||||
struct dev_filter *filter, struct pool *mem,
|
||||
struct list *head)
|
||||
{
|
||||
struct dev_iter *iter = dev_iter_create(filter);
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
struct disk_list *data = NULL;
|
||||
struct list *vgih;
|
||||
struct cache_vginfo *vginfo;
|
||||
|
||||
/* Fast path if we already saw this VG and cached the list of PVs */
|
||||
if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) &&
|
||||
vginfo->infos.n) {
|
||||
list_iterate(vgih, &vginfo->infos) {
|
||||
dev = list_item(vgih, struct cache_info)->dev;
|
||||
if (dev && !(data = read_disk(fmt, dev, mem, vg_name)))
|
||||
break;
|
||||
_add_pv_to_list(head, data);
|
||||
}
|
||||
|
||||
/* Did we find the whole VG? */
|
||||
if (!vg_name || !*vg_name ||
|
||||
(data && *data->pvd.vg_name &&
|
||||
list_size(head) == data->vgd.pv_cur))
|
||||
return 1;
|
||||
|
||||
/* Failed */
|
||||
list_init(head);
|
||||
/* vgcache_del(vg_name); */
|
||||
}
|
||||
|
||||
if (!(iter = dev_iter_create(filter))) {
|
||||
log_error("read_pvs_in_vg: dev_iter_create failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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)))
|
||||
list_add(head, &data->list);
|
||||
if ((data = read_disk(fmt, dev, mem, vg_name))) {
|
||||
_add_pv_to_list(head, data);
|
||||
}
|
||||
}
|
||||
dev_iter_destroy(iter);
|
||||
|
||||
@@ -353,11 +458,10 @@ int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int _write_vgd(struct disk_list *data)
|
||||
{
|
||||
struct vg_disk *vgd = &data->vgd;
|
||||
unsigned long pos = data->pvd.vg_on_disk.base;
|
||||
ulong pos = data->pvd.vg_on_disk.base;
|
||||
|
||||
_xlate_vgd(vgd);
|
||||
if (dev_write(data->dev, pos, sizeof(*vgd), vgd) != sizeof(*vgd))
|
||||
@@ -406,23 +510,27 @@ static int _write_lvd(struct device *dev, ulong pos, struct lv_disk *disk)
|
||||
static int _write_lvs(struct disk_list *data)
|
||||
{
|
||||
struct list *lvh;
|
||||
unsigned long pos;
|
||||
ulong pos, offset;
|
||||
|
||||
pos = data->pvd.lv_on_disk.base;
|
||||
|
||||
if (!dev_zero(data->dev, pos, data->pvd.lv_on_disk.size)) {
|
||||
log_error("Couldn't zero lv area on device '%s'",
|
||||
dev_name(data->dev));
|
||||
dev_name(data->dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -432,7 +540,7 @@ 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;
|
||||
unsigned long pos = data->pvd.pe_on_disk.base;
|
||||
ulong pos = data->pvd.pe_on_disk.base;
|
||||
|
||||
_xlate_extents(extents, data->pvd.pe_total);
|
||||
if (dev_write(data->dev, pos, len, extents) != len)
|
||||
@@ -445,21 +553,41 @@ static int _write_extents(struct disk_list *data)
|
||||
|
||||
static int _write_pvd(struct disk_list *data)
|
||||
{
|
||||
struct pv_disk *disk = &data->pvd;
|
||||
char *buf;
|
||||
ulong pos = data->pvd.pv_on_disk.base;
|
||||
ulong size = data->pvd.pv_on_disk.size;
|
||||
|
||||
_xlate_pvd(disk);
|
||||
if (dev_write(data->dev, 0, sizeof(*disk), disk) != sizeof(*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
|
||||
the next one is zeroed in order to make non LVM tools
|
||||
happy (idea from AED) */
|
||||
buf = dbg_malloc(size);
|
||||
if (!buf) {
|
||||
log_err("Couldn't allocate temporary PV buffer.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
dbg_free(buf);
|
||||
fail;
|
||||
}
|
||||
|
||||
_xlate_pvd(disk);
|
||||
|
||||
dbg_free(buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* assumes the device has been opened.
|
||||
*/
|
||||
static int __write_all_pvd(struct disk_list *data)
|
||||
static int __write_all_pvd(struct format_type *fmt, struct disk_list *data)
|
||||
{
|
||||
const char *pv_name = dev_name(data->dev);
|
||||
|
||||
@@ -468,11 +596,19 @@ static int __write_all_pvd(struct disk_list *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt); */
|
||||
/*
|
||||
* Stop here for orphan pv's.
|
||||
*/
|
||||
if (data->pvd.vg_name[0] == '\0')
|
||||
if (data->pvd.vg_name[0] == '\0') {
|
||||
/* if (!test_mode())
|
||||
vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt); */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* if (!test_mode())
|
||||
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev,
|
||||
fmt); */
|
||||
|
||||
if (!_write_vgd(data)) {
|
||||
log_error("Failed to write VG data to %s", pv_name);
|
||||
@@ -500,7 +636,7 @@ static int __write_all_pvd(struct disk_list *data)
|
||||
/*
|
||||
* opens the device and hands to the above fn.
|
||||
*/
|
||||
static int _write_all_pvd(struct disk_list *data)
|
||||
static int _write_all_pvd(struct format_type *fmt, struct disk_list *data)
|
||||
{
|
||||
int r;
|
||||
|
||||
@@ -509,7 +645,7 @@ static int _write_all_pvd(struct disk_list *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = __write_all_pvd(data);
|
||||
r = __write_all_pvd(fmt, data);
|
||||
|
||||
if (!dev_close(data->dev))
|
||||
stack;
|
||||
@@ -517,23 +653,23 @@ static int _write_all_pvd(struct disk_list *data)
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Writes all the given pv's to disk. Does very
|
||||
* little sanity checking, so make sure correct
|
||||
* data is passed to here.
|
||||
*/
|
||||
int write_disks(struct list *pvs)
|
||||
int write_disks(struct format_type *fmt, struct list *pvs)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct disk_list *dl;
|
||||
|
||||
list_iterate(pvh, pvs) {
|
||||
dl = list_item(pvh, struct disk_list);
|
||||
if (!(_write_all_pvd(dl)))
|
||||
if (!(_write_all_pvd(fmt, dl)))
|
||||
fail;
|
||||
|
||||
log_debug("Successfully wrote data to %s", dev_name(dl->dev));
|
||||
log_very_verbose("Successfully wrote data to %s",
|
||||
dev_name(dl->dev));
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@@ -11,16 +11,16 @@
|
||||
#include "metadata.h"
|
||||
#include "pool.h"
|
||||
|
||||
|
||||
#define SECTOR_SIZE 512
|
||||
|
||||
#define MAX_PV 256
|
||||
#define MAX_LV 256
|
||||
#define MAX_VG 99
|
||||
|
||||
#define MIN_PE_SIZE ( 8192L / SECTOR_SIZE) /* 8 KB in sectors */
|
||||
#define MAX_PE_SIZE ( 16L * 1024L * 1024L / SECTOR_SIZE * 1024)
|
||||
#define PE_SIZE_PV_SIZE_REL 5 /* PV size must be at least 5 times PE size */
|
||||
#define MAX_PV_SIZE ((uint32_t) -1) /* 2TB in sectors - 1 */
|
||||
#define MIN_PE_SIZE (8192L >> SECTOR_SHIFT) /* 8 KB in sectors */
|
||||
#define MAX_PE_SIZE (16L * 1024L * (1024L >> SECTOR_SHIFT) * 1024L)
|
||||
#define PE_SIZE_PV_SIZE_REL 5 /* PV size must be at least 5 times PE size */
|
||||
#define MAX_LE_TOTAL 65534 /* 2^16 - 2 */
|
||||
#define MAX_PE_TOTAL ((uint32_t) -2)
|
||||
|
||||
#define UNMAPPED_EXTENT 0
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
/* logical volume */
|
||||
#define LV_ACTIVE 0x01 /* lv_status */
|
||||
#define LV_SPINDOWN 0x02 /* " */
|
||||
#define LV_PERSISTENT_MINOR 0x04 /* " */
|
||||
|
||||
#define LV_READ 0x01 /* lv_access */
|
||||
#define LV_WRITE 0x02 /* " */
|
||||
@@ -52,86 +53,87 @@
|
||||
#define PV_ACTIVE 0x01 /* pv_status */
|
||||
#define PV_ALLOCATABLE 0x02 /* pv_allocatable */
|
||||
|
||||
#define EXPORTED_TAG "PV_EXP" /* Identifier for exported PV */
|
||||
#define IMPORTED_TAG "PV_IMP" /* Identifier for imported PV */
|
||||
|
||||
struct data_area {
|
||||
uint32_t base;
|
||||
uint32_t size;
|
||||
};
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct pv_disk {
|
||||
uint8_t id[2];
|
||||
uint16_t version; /* lvm version */
|
||||
struct data_area pv_on_disk;
|
||||
struct data_area vg_on_disk;
|
||||
struct data_area pv_uuidlist_on_disk;
|
||||
struct data_area lv_on_disk;
|
||||
struct data_area pe_on_disk;
|
||||
uint8_t pv_uuid[NAME_LEN];
|
||||
uint8_t vg_name[NAME_LEN];
|
||||
uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */
|
||||
uint32_t pv_major;
|
||||
uint32_t pv_number;
|
||||
uint32_t pv_status;
|
||||
uint32_t pv_allocatable;
|
||||
uint32_t pv_size;
|
||||
uint32_t lv_cur;
|
||||
uint32_t pe_size;
|
||||
uint32_t pe_total;
|
||||
uint32_t pe_allocated;
|
||||
uint8_t id[2];
|
||||
uint16_t version; /* lvm version */
|
||||
struct data_area pv_on_disk;
|
||||
struct data_area vg_on_disk;
|
||||
struct data_area pv_uuidlist_on_disk;
|
||||
struct data_area lv_on_disk;
|
||||
struct data_area pe_on_disk;
|
||||
uint8_t pv_uuid[NAME_LEN];
|
||||
uint8_t vg_name[NAME_LEN];
|
||||
uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */
|
||||
uint32_t pv_major;
|
||||
uint32_t pv_number;
|
||||
uint32_t pv_status;
|
||||
uint32_t pv_allocatable;
|
||||
uint32_t pv_size;
|
||||
uint32_t lv_cur;
|
||||
uint32_t pe_size;
|
||||
uint32_t pe_total;
|
||||
uint32_t pe_allocated;
|
||||
|
||||
/* only present on version == 2 pv's */
|
||||
uint32_t pe_start;
|
||||
};
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct lv_disk {
|
||||
uint8_t lv_name[NAME_LEN];
|
||||
uint8_t vg_name[NAME_LEN];
|
||||
uint32_t lv_access;
|
||||
uint32_t lv_status;
|
||||
uint32_t lv_open;
|
||||
uint32_t lv_dev;
|
||||
uint32_t lv_number;
|
||||
uint32_t lv_mirror_copies; /* for future use */
|
||||
uint32_t lv_recovery; /* " */
|
||||
uint32_t lv_schedule; /* " */
|
||||
uint32_t lv_size;
|
||||
uint32_t lv_snapshot_minor; /* minor number of original */
|
||||
uint16_t lv_chunk_size; /* chunk size of snapshot */
|
||||
uint16_t dummy;
|
||||
uint32_t lv_allocated_le;
|
||||
uint32_t lv_stripes;
|
||||
uint32_t lv_stripesize;
|
||||
uint32_t lv_badblock; /* for future use */
|
||||
uint32_t lv_allocation;
|
||||
uint32_t lv_io_timeout; /* for future use */
|
||||
uint32_t lv_read_ahead;
|
||||
};
|
||||
uint8_t lv_name[NAME_LEN];
|
||||
uint8_t vg_name[NAME_LEN];
|
||||
uint32_t lv_access;
|
||||
uint32_t lv_status;
|
||||
uint32_t lv_open;
|
||||
uint32_t lv_dev;
|
||||
uint32_t lv_number;
|
||||
uint32_t lv_mirror_copies; /* for future use */
|
||||
uint32_t lv_recovery; /* " */
|
||||
uint32_t lv_schedule; /* " */
|
||||
uint32_t lv_size;
|
||||
uint32_t lv_snapshot_minor; /* minor number of original */
|
||||
uint16_t lv_chunk_size; /* chunk size of snapshot */
|
||||
uint16_t dummy;
|
||||
uint32_t lv_allocated_le;
|
||||
uint32_t lv_stripes;
|
||||
uint32_t lv_stripesize;
|
||||
uint32_t lv_badblock; /* for future use */
|
||||
uint32_t lv_allocation;
|
||||
uint32_t lv_io_timeout; /* for future use */
|
||||
uint32_t lv_read_ahead;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct vg_disk {
|
||||
uint8_t vg_uuid[ID_LEN]; /* volume group UUID */
|
||||
uint8_t vg_name_dummy[NAME_LEN - ID_LEN]; /* rest of v1 VG name */
|
||||
uint32_t vg_number; /* volume group number */
|
||||
uint32_t vg_access; /* read/write */
|
||||
uint32_t vg_status; /* active or not */
|
||||
uint32_t lv_max; /* maximum logical volumes */
|
||||
uint32_t lv_cur; /* current logical volumes */
|
||||
uint32_t lv_open; /* open logical volumes */
|
||||
uint32_t pv_max; /* maximum physical volumes */
|
||||
uint32_t pv_cur; /* current physical volumes FU */
|
||||
uint32_t pv_act; /* active physical volumes */
|
||||
uint32_t dummy;
|
||||
uint32_t vgda; /* volume group descriptor arrays FU */
|
||||
uint32_t pe_size; /* physical extent size in sectors */
|
||||
uint32_t pe_total; /* total of physical extents */
|
||||
uint32_t pe_allocated; /* allocated physical extents */
|
||||
uint32_t pvg_total; /* physical volume groups FU */
|
||||
};
|
||||
uint8_t vg_uuid[ID_LEN]; /* volume group UUID */
|
||||
uint8_t vg_name_dummy[NAME_LEN - ID_LEN]; /* rest of v1 VG name */
|
||||
uint32_t vg_number; /* volume group number */
|
||||
uint32_t vg_access; /* read/write */
|
||||
uint32_t vg_status; /* active or not */
|
||||
uint32_t lv_max; /* maximum logical volumes */
|
||||
uint32_t lv_cur; /* current logical volumes */
|
||||
uint32_t lv_open; /* open logical volumes */
|
||||
uint32_t pv_max; /* maximum physical volumes */
|
||||
uint32_t pv_cur; /* current physical volumes FU */
|
||||
uint32_t pv_act; /* active physical volumes */
|
||||
uint32_t dummy;
|
||||
uint32_t vgda; /* volume group descriptor arrays FU */
|
||||
uint32_t pe_size; /* physical extent size in sectors */
|
||||
uint32_t pe_total; /* total of physical extents */
|
||||
uint32_t pe_allocated; /* allocated physical extents */
|
||||
uint32_t pvg_total; /* physical volume groups FU */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct pe_disk {
|
||||
uint16_t lv_num;
|
||||
uint16_t le_num;
|
||||
};
|
||||
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct uuid_list {
|
||||
struct list list;
|
||||
@@ -155,69 +157,68 @@ struct disk_list {
|
||||
struct pe_disk *extents;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Layout constants.
|
||||
*/
|
||||
#define METADATA_ALIGN 4096UL
|
||||
#define PE_ALIGN (65536UL / SECTOR_SIZE)
|
||||
|
||||
#define METADATA_BASE 0UL
|
||||
#define PV_SIZE 1024UL
|
||||
#define VG_SIZE 4096UL
|
||||
|
||||
|
||||
/*
|
||||
* Functions to calculate layout info.
|
||||
*/
|
||||
int calculate_layout(struct disk_list *dl);
|
||||
int calculate_extent_count(struct physical_volume *pv);
|
||||
|
||||
int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size,
|
||||
uint32_t max_extent_count);
|
||||
|
||||
/*
|
||||
* Low level io routines which read/write
|
||||
* disk_lists.
|
||||
*/
|
||||
struct disk_list *read_disk(struct device *dev, struct pool *mem,
|
||||
const char *vg_name);
|
||||
|
||||
int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
|
||||
struct disk_list *read_disk(struct format_type *fmt, struct device *dev,
|
||||
struct pool *mem, const char *vg_name);
|
||||
|
||||
int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
|
||||
struct dev_filter *filter,
|
||||
struct pool *mem, struct list *results);
|
||||
|
||||
int write_disks(struct list *pvds);
|
||||
|
||||
int write_disks(struct format_type *fmt, struct list *pvds);
|
||||
|
||||
/*
|
||||
* Functions to translate to between disk and in
|
||||
* core structures.
|
||||
*/
|
||||
int import_pv(struct pool *mem, struct device *dev,
|
||||
struct volume_group *vg,
|
||||
struct physical_volume *pv, struct pv_disk *pvd);
|
||||
int export_pv(struct pv_disk *pvd, struct physical_volume *pv);
|
||||
int export_pv(struct pool *mem, struct volume_group *vg,
|
||||
struct pv_disk *pvd, struct physical_volume *pv);
|
||||
|
||||
int import_vg(struct pool *mem,
|
||||
struct volume_group *vg, struct disk_list *dl);
|
||||
struct volume_group *vg, struct disk_list *dl, int partial);
|
||||
int export_vg(struct vg_disk *vgd, struct volume_group *vg);
|
||||
|
||||
int import_lv(struct pool *mem, struct logical_volume *lv,
|
||||
struct lv_disk *lvd);
|
||||
void export_lv(struct lv_disk *lvd, struct volume_group *vg,
|
||||
struct logical_volume *lv, const char *dev_dir);
|
||||
int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd);
|
||||
|
||||
int import_extents(struct pool *mem, struct volume_group *vg,
|
||||
int import_extents(struct pool *mem, struct volume_group *vg,
|
||||
struct list *pvds);
|
||||
int export_extents(struct disk_list *dl, int lv_num,
|
||||
struct logical_volume *lv,
|
||||
struct physical_volume *pv);
|
||||
struct logical_volume *lv, struct physical_volume *pv);
|
||||
|
||||
int import_pvs(struct pool *mem, struct list *pvds,
|
||||
struct list *results, int *count);
|
||||
int import_pvs(struct format_type *fmt, struct pool *mem,
|
||||
struct volume_group *vg,
|
||||
struct list *pvds, struct list *results, int *count);
|
||||
|
||||
int import_lvs(struct pool *mem, struct volume_group *vg,
|
||||
struct list *pvds);
|
||||
int import_lvs(struct pool *mem, struct volume_group *vg, struct list *pvds);
|
||||
int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||
struct physical_volume *pv, const char *dev_dir);
|
||||
|
||||
int import_snapshots(struct pool *mem, struct volume_group *vg,
|
||||
struct list *pvds);
|
||||
|
||||
int export_uuids(struct disk_list *dl, struct volume_group *vg);
|
||||
|
||||
void export_numbers(struct list *pvds, struct volume_group *vg);
|
||||
@@ -225,10 +226,9 @@ void export_numbers(struct list *pvds, struct volume_group *vg);
|
||||
void export_pv_act(struct list *pvds);
|
||||
|
||||
/* blech */
|
||||
int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
|
||||
int *result);
|
||||
int export_vg_number(struct list *pvds, const char *vg_name,
|
||||
struct dev_filter *filter);
|
||||
|
||||
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
|
||||
const char *candidate_vg, int *result);
|
||||
int export_vg_number(struct format_instance *fid, struct list *pvds,
|
||||
const char *vg_name, struct dev_filter *filter);
|
||||
|
||||
#endif
|
||||
|
@@ -4,52 +4,93 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "disk-rep.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "pool.h"
|
||||
#include "hash.h"
|
||||
#include "limits.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "display.h"
|
||||
#include "toolcontext.h"
|
||||
#include "cache.h"
|
||||
#include "lvm1-label.h"
|
||||
#include "format1.h"
|
||||
|
||||
/* VG consistency checks */
|
||||
static int _check_vgs(struct list *pvs)
|
||||
static int _check_vgs(struct list *pvs, int *partial)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct list *pvh, *t;
|
||||
struct disk_list *dl = NULL;
|
||||
struct disk_list *first = NULL;
|
||||
|
||||
int pv_count = 0;
|
||||
int exported = -1;
|
||||
|
||||
/* check all the vg's are the same */
|
||||
*partial = 0;
|
||||
|
||||
/*
|
||||
* If there are exported and unexported PVs, ignore exported ones.
|
||||
* This means an active VG won't be affected if disks are inserted
|
||||
* bearing an exported VG with the same name.
|
||||
*/
|
||||
list_iterate(pvh, pvs) {
|
||||
dl = list_item(pvh, struct disk_list);
|
||||
|
||||
if (exported < 0) {
|
||||
exported = dl->pvd.pv_status & VG_EXPORTED;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (exported != (dl->pvd.pv_status & VG_EXPORTED)) {
|
||||
/* Remove exported PVs */
|
||||
list_iterate_safe(pvh, t, pvs) {
|
||||
dl = list_item(pvh, struct disk_list);
|
||||
if (dl->pvd.pv_status & VG_EXPORTED)
|
||||
list_del(pvh);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove any PVs with VG structs that differ from the first */
|
||||
list_iterate_safe(pvh, t, pvs) {
|
||||
dl = list_item(pvh, struct disk_list);
|
||||
|
||||
if (!first)
|
||||
first = dl;
|
||||
|
||||
else if (memcmp(&first->vgd, &dl->vgd, sizeof(first->vgd))) {
|
||||
log_err("VG data differs between PVs %s and %s",
|
||||
dev_name(first->dev), dev_name(dl->dev));
|
||||
log_error("VG data differs between PVs %s and %s",
|
||||
dev_name(first->dev), dev_name(dl->dev));
|
||||
list_del(pvh);
|
||||
if (partial_mode()) {
|
||||
*partial = 1;
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
pv_count++;
|
||||
}
|
||||
|
||||
/* On entry to fn, list known to be non-empty */
|
||||
if (!(pv_count == dl->vgd.pv_cur)) {
|
||||
log_error("Only %d out of %d PV(s) found for VG %s",
|
||||
pv_count, dl->vgd.pv_cur, dl->pvd.vg_name);
|
||||
return 0;
|
||||
if (pv_count != dl->vgd.pv_cur) {
|
||||
log_error("%d PV(s) found for VG %s: expected %d",
|
||||
pv_count, dl->pvd.vg_name, dl->vgd.pv_cur);
|
||||
if (!partial_mode())
|
||||
return 0;
|
||||
*partial = 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct volume_group *_build_vg(struct pool *mem, struct list *pvs)
|
||||
static struct volume_group *_build_vg(struct format_instance *fid,
|
||||
struct list *pvs)
|
||||
{
|
||||
struct pool *mem = fid->fmt->cmd->mem;
|
||||
struct volume_group *vg = pool_alloc(mem, sizeof(*vg));
|
||||
struct disk_list *dl;
|
||||
int partial;
|
||||
|
||||
if (!vg)
|
||||
goto bad;
|
||||
@@ -57,20 +98,24 @@ static struct volume_group *_build_vg(struct pool *mem, struct list *pvs)
|
||||
if (list_empty(pvs))
|
||||
goto bad;
|
||||
|
||||
dl = list_item(pvs->n, struct disk_list);
|
||||
|
||||
memset(vg, 0, sizeof(*vg));
|
||||
|
||||
vg->cmd = fid->fmt->cmd;
|
||||
vg->fid = fid;
|
||||
vg->seqno = 0;
|
||||
list_init(&vg->pvs);
|
||||
list_init(&vg->lvs);
|
||||
list_init(&vg->snapshots);
|
||||
|
||||
if (!_check_vgs(pvs))
|
||||
if (!_check_vgs(pvs, &partial))
|
||||
goto bad;
|
||||
|
||||
if (!import_vg(mem, vg, dl))
|
||||
dl = list_item(pvs->n, struct disk_list);
|
||||
|
||||
if (!import_vg(mem, vg, dl, partial))
|
||||
goto bad;
|
||||
|
||||
if (!import_pvs(mem, pvs, &vg->pvs, &vg->pv_count))
|
||||
if (!import_pvs(fid->fmt, mem, vg, pvs, &vg->pvs, &vg->pv_count))
|
||||
goto bad;
|
||||
|
||||
if (!import_lvs(mem, vg, pvs))
|
||||
@@ -79,16 +124,20 @@ static struct volume_group *_build_vg(struct pool *mem, struct list *pvs)
|
||||
if (!import_extents(mem, vg, pvs))
|
||||
goto bad;
|
||||
|
||||
if (!import_snapshots(mem, vg, pvs))
|
||||
goto bad;
|
||||
|
||||
return vg;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
stack;
|
||||
pool_free(mem, vg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct volume_group *_vg_read(struct format_instance *fi,
|
||||
const char *vg_name)
|
||||
static struct volume_group *_vg_read(struct format_instance *fid,
|
||||
const char *vg_name,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
struct pool *mem = pool_create(1024 * 10);
|
||||
struct list pvs;
|
||||
@@ -100,22 +149,21 @@ static struct volume_group *_vg_read(struct format_instance *fi,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Strip dev_dir if present */
|
||||
vg_name = strip_dir(vg_name, fi->cmd->dev_dir);
|
||||
/* Strip dev_dir if present */
|
||||
vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir);
|
||||
|
||||
if (!read_pvs_in_vg(vg_name, fi->cmd->filter, mem, &pvs)) {
|
||||
if (!read_pvs_in_vg
|
||||
(fid->fmt, vg_name, fid->fmt->cmd->filter, mem, &pvs)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(vg = _build_vg(fi->cmd->mem, &pvs))) {
|
||||
if (!(vg = _build_vg(fid, &pvs))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
vg->cmd = fi->cmd;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
pool_destroy(mem);
|
||||
return vg;
|
||||
}
|
||||
@@ -137,11 +185,10 @@ static struct disk_list *_flatten_pv(struct pool *mem, struct volume_group *vg,
|
||||
list_init(&dl->uuids);
|
||||
list_init(&dl->lvds);
|
||||
|
||||
if (!export_pv(&dl->pvd, pv) ||
|
||||
if (!export_pv(mem, vg, &dl->pvd, pv) ||
|
||||
!export_vg(&dl->vgd, vg) ||
|
||||
!export_uuids(dl, vg) ||
|
||||
!export_lvs(dl, vg, pv, dev_dir) ||
|
||||
!calculate_layout(dl)) {
|
||||
!export_lvs(dl, vg, pv, dev_dir) || !calculate_layout(dl)) {
|
||||
stack;
|
||||
pool_free(mem, dl);
|
||||
return NULL;
|
||||
@@ -150,7 +197,8 @@ static struct disk_list *_flatten_pv(struct pool *mem, struct volume_group *vg,
|
||||
return dl;
|
||||
}
|
||||
|
||||
static int _flatten_vg(struct pool *mem, struct volume_group *vg,
|
||||
static int _flatten_vg(struct format_instance *fid, struct pool *mem,
|
||||
struct volume_group *vg,
|
||||
struct list *pvds, const char *dev_dir,
|
||||
struct dev_filter *filter)
|
||||
{
|
||||
@@ -161,7 +209,7 @@ static int _flatten_vg(struct pool *mem, struct volume_group *vg,
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pvl = list_item(pvh, struct pv_list);
|
||||
|
||||
if (!(data = _flatten_pv(mem, vg, &pvl->pv, dev_dir))) {
|
||||
if (!(data = _flatten_pv(mem, vg, pvl->pv, dev_dir))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -172,7 +220,7 @@ static int _flatten_vg(struct pool *mem, struct volume_group *vg,
|
||||
export_numbers(pvds, vg);
|
||||
export_pv_act(pvds);
|
||||
|
||||
if (!export_vg_number(pvds, vg->name, filter)) {
|
||||
if (!export_vg_number(fid, pvds, vg->name, filter)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -180,7 +228,8 @@ static int _flatten_vg(struct pool *mem, struct volume_group *vg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _vg_write(struct format_instance *fi, struct volume_group *vg)
|
||||
static int _vg_write(struct format_instance *fid, struct volume_group *vg,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
struct pool *mem = pool_create(1024 * 10);
|
||||
struct list pvds;
|
||||
@@ -193,192 +242,169 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg)
|
||||
|
||||
list_init(&pvds);
|
||||
|
||||
r = (_flatten_vg(mem, vg, &pvds, fi->cmd->dev_dir, fi->cmd->filter) &&
|
||||
write_disks(&pvds));
|
||||
r = (_flatten_vg(fid, mem, vg, &pvds, fid->fmt->cmd->dev_dir,
|
||||
fid->fmt->cmd->filter) &&
|
||||
write_disks(fid->fmt, &pvds));
|
||||
|
||||
cache_update_vg(vg);
|
||||
pool_destroy(mem);
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct physical_volume *_pv_read(struct format_instance *fi,
|
||||
const char *name)
|
||||
int _pv_read(struct format_type *fmt, const char *pv_name,
|
||||
struct physical_volume *pv, struct list *mdas)
|
||||
{
|
||||
struct pool *mem = pool_create(1024);
|
||||
struct physical_volume *pv = NULL;
|
||||
struct disk_list *dl;
|
||||
struct device *dev;
|
||||
int r = 0;
|
||||
|
||||
log_very_verbose("Reading physical volume data %s from disk", name);
|
||||
log_very_verbose("Reading physical volume data %s from disk", pv_name);
|
||||
|
||||
if (!mem) {
|
||||
stack;
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(dev = dev_cache_get(name, fi->cmd->filter))) {
|
||||
if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(dl = read_disk(dev, mem, NULL))) {
|
||||
if (!(dl = read_disk(fmt, dev, mem, NULL))) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(pv = pool_alloc(fi->cmd->mem, sizeof(*pv)))) {
|
||||
if (!import_pv(fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!import_pv(fi->cmd->mem, dl->dev, pv, &dl->pvd)) {
|
||||
stack;
|
||||
pool_free(fi->cmd->mem, pv);
|
||||
pv = NULL;
|
||||
}
|
||||
pv->fmt = fmt;
|
||||
|
||||
out:
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
pool_destroy(mem);
|
||||
return pv;
|
||||
return r;
|
||||
}
|
||||
|
||||
static struct list *_get_pvs(struct format_instance *fi)
|
||||
static int _pv_setup(struct format_type *fmt,
|
||||
uint64_t pe_start, uint32_t extent_count,
|
||||
uint32_t extent_size,
|
||||
int pvmetadatacopies,
|
||||
uint64_t pvmetadatasize, struct list *mdas,
|
||||
struct physical_volume *pv, struct volume_group *vg)
|
||||
{
|
||||
struct pool *mem = pool_create(1024 * 10);
|
||||
struct list pvs, *results;
|
||||
uint32_t count;
|
||||
char *sz;
|
||||
|
||||
if (!mem) {
|
||||
stack;
|
||||
return NULL;
|
||||
if (pv->size > MAX_PV_SIZE)
|
||||
pv->size--;
|
||||
if (pv->size > MAX_PV_SIZE) {
|
||||
log_error("Physical volumes cannot be bigger than %s",
|
||||
sz = display_size(MAX_PV_SIZE / 2, SIZE_SHORT));
|
||||
dbg_free(sz);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(results = pool_alloc(fi->cmd->mem, sizeof(*results)))) {
|
||||
stack;
|
||||
pool_destroy(mem);
|
||||
return NULL;
|
||||
}
|
||||
/* Nothing more to do if extent size isn't provided */
|
||||
if (!extent_size)
|
||||
return 1;
|
||||
|
||||
list_init(&pvs);
|
||||
list_init(results);
|
||||
|
||||
if (!read_pvs_in_vg(NULL, fi->cmd->filter, mem, &pvs)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!import_pvs(fi->cmd->mem, &pvs, results, &count)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
pool_destroy(mem);
|
||||
return results;
|
||||
|
||||
bad:
|
||||
pool_free(fi->cmd->mem, results);
|
||||
pool_destroy(mem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _find_vg_name(struct list *names, const char *vg)
|
||||
{
|
||||
struct list *nh;
|
||||
struct name_list *nl;
|
||||
|
||||
list_iterate(nh, names) {
|
||||
nl = list_item(nh, struct name_list);
|
||||
if (!strcmp(nl->name, vg))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct list *_get_vgs(struct format_instance *fi)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct list *pvs, *names = pool_alloc(fi->cmd->mem, sizeof(*names));
|
||||
struct name_list *nl;
|
||||
|
||||
if (!names) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_init(names);
|
||||
|
||||
if (!(pvs = _get_pvs(fi))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
list_iterate(pvh, pvs) {
|
||||
struct pv_list *pvl = list_item(pvh, struct pv_list);
|
||||
|
||||
if (!(*pvl->pv.vg_name) ||
|
||||
_find_vg_name(names, pvl->pv.vg_name))
|
||||
continue;
|
||||
|
||||
if (!(nl = pool_alloc(fi->cmd->mem, sizeof(*nl)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(nl->name = pool_strdup(fi->cmd->mem, pvl->pv.vg_name))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
list_add(names, &nl->list);
|
||||
}
|
||||
|
||||
if (list_empty(names))
|
||||
goto bad;
|
||||
|
||||
return names;
|
||||
|
||||
bad:
|
||||
pool_free(fi->cmd->mem, names);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _pv_setup(struct format_instance *fi, struct physical_volume *pv,
|
||||
struct volume_group *vg)
|
||||
{
|
||||
/*
|
||||
* This works out pe_start and pe_count.
|
||||
*/
|
||||
if (!calculate_extent_count(pv)) {
|
||||
if (!calculate_extent_count(pv, extent_size, extent_count)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Retain existing extent locations exactly */
|
||||
/* FIXME Relax this so a non-overlapping existing pe_start can also
|
||||
* be used in place of the calculated one */
|
||||
if (((pe_start || extent_count) && (pe_start != pv->pe_start)) ||
|
||||
(extent_count && (extent_count != pv->pe_count))) {
|
||||
log_error("Metadata would overwrite physical extents");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
|
||||
static int _find_free_lvnum(struct logical_volume *lv)
|
||||
{
|
||||
int lvnum_used[MAX_LV];
|
||||
int i = 0;
|
||||
struct list *lvh;
|
||||
struct lv_list *lvl;
|
||||
|
||||
memset(&lvnum_used, 0, sizeof(lvnum_used));
|
||||
|
||||
list_iterate(lvh, &lv->vg->lvs) {
|
||||
lvl = list_item(lvh, struct lv_list);
|
||||
lvnum_used[lvnum_from_lvid(&lvl->lv->lvid)] = 1;
|
||||
}
|
||||
|
||||
while (lvnum_used[i])
|
||||
i++;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
|
||||
{
|
||||
uint64_t max_size = UINT_MAX;
|
||||
|
||||
if (!*lv->lvid.s)
|
||||
lvid_from_lvnum(&lv->lvid, &lv->vg->id, _find_free_lvnum(lv));
|
||||
|
||||
if (lv->le_count > MAX_LE_TOTAL) {
|
||||
log_error("logical volumes cannot contain more than "
|
||||
"%d extents.", MAX_LE_TOTAL);
|
||||
return 0;
|
||||
}
|
||||
if (lv->size > max_size) {
|
||||
char *dummy = display_size(max_size, SIZE_SHORT);
|
||||
log_error("logical volumes cannot be larger than %s", dummy);
|
||||
dbg_free(dummy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _pv_write(struct format_type *fmt, struct physical_volume *pv,
|
||||
struct list *mdas, int64_t sector)
|
||||
{
|
||||
struct pool *mem;
|
||||
struct disk_list *dl;
|
||||
struct list pvs;
|
||||
struct label *label;
|
||||
struct cache_info *info;
|
||||
|
||||
if (!(info = cache_add(fmt->labeller, (char *) &pv->id, pv->dev,
|
||||
pv->vg_name, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
label = info->label;
|
||||
info->device_size = pv->size << SECTOR_SHIFT;
|
||||
info->fmt = fmt;
|
||||
|
||||
list_init(&info->mdas);
|
||||
|
||||
list_init(&pvs);
|
||||
|
||||
if (*pv->vg_name || pv->pe_allocated ) {
|
||||
log_error("Assertion failed: can't _pv_write non-orphan PV "
|
||||
"(in VG %s)", pv->vg_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Ensure any residual PE structure is gone */
|
||||
pv->pe_size = pv->pe_count = pv->pe_start = 0;
|
||||
pv->status &= ~ALLOCATED_PV;
|
||||
pv->pe_size = pv->pe_count = 0;
|
||||
pv->pe_start = PE_ALIGN;
|
||||
|
||||
if (!(mem = pool_create(1024))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (!(dl = pool_alloc(mem, sizeof(*dl)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
@@ -386,13 +412,19 @@ static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
|
||||
dl->mem = mem;
|
||||
dl->dev = pv->dev;
|
||||
|
||||
if (!export_pv(&dl->pvd, pv)) {
|
||||
if (!export_pv(mem, NULL, &dl->pvd, pv)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* must be set to be able to zero gap after PV structure in
|
||||
dev_write in order to make other disk tools happy */
|
||||
dl->pvd.pv_on_disk.base = METADATA_BASE;
|
||||
dl->pvd.pv_on_disk.size = PV_SIZE;
|
||||
dl->pvd.pe_on_disk.base = PE_ALIGN << SECTOR_SHIFT;
|
||||
|
||||
list_add(&pvs, &dl->list);
|
||||
if (!write_disks(&pvs)) {
|
||||
if (!write_disks(fmt, &pvs)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
@@ -400,26 +432,26 @@ static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
|
||||
pool_destroy(mem);
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
bad:
|
||||
pool_destroy(mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _vg_setup(struct format_instance *fi, struct volume_group *vg)
|
||||
int _vg_setup(struct format_instance *fid, struct volume_group *vg)
|
||||
{
|
||||
/* just check max_pv and max_lv */
|
||||
if (vg->max_lv >= MAX_LV)
|
||||
vg->max_lv = MAX_LV - 1;
|
||||
|
||||
if (vg->max_pv >= MAX_PV)
|
||||
if (vg->max_pv >= MAX_PV)
|
||||
vg->max_pv = MAX_PV - 1;
|
||||
|
||||
if (vg->extent_size > MAX_PE_SIZE || vg->extent_size < MIN_PE_SIZE) {
|
||||
char *dummy, *dummy2;
|
||||
|
||||
log_error("Extent size must be between %s and %s",
|
||||
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)),
|
||||
(dummy2 = display_size(MAX_PE_SIZE / 2, SIZE_SHORT)));
|
||||
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)),
|
||||
(dummy2 = display_size(MAX_PE_SIZE / 2, SIZE_SHORT)));
|
||||
|
||||
dbg_free(dummy);
|
||||
dbg_free(dummy2);
|
||||
@@ -429,7 +461,7 @@ int _vg_setup(struct format_instance *fi, struct volume_group *vg)
|
||||
if (vg->extent_size % MIN_PE_SIZE) {
|
||||
char *dummy;
|
||||
log_error("Extent size must be multiple of %s",
|
||||
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)));
|
||||
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)));
|
||||
dbg_free(dummy);
|
||||
return 0;
|
||||
}
|
||||
@@ -443,36 +475,89 @@ int _vg_setup(struct format_instance *fi, struct volume_group *vg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void _destroy(struct format_instance *fi)
|
||||
{
|
||||
dbg_free(fi);
|
||||
}
|
||||
|
||||
|
||||
static struct format_handler _format1_ops = {
|
||||
get_vgs: _get_vgs,
|
||||
get_pvs: _get_pvs,
|
||||
pv_read: _pv_read,
|
||||
pv_setup: _pv_setup,
|
||||
pv_write: _pv_write,
|
||||
vg_read: _vg_read,
|
||||
vg_setup: _vg_setup,
|
||||
vg_write: _vg_write,
|
||||
destroy: _destroy,
|
||||
static struct metadata_area_ops _metadata_format1_ops = {
|
||||
vg_read:_vg_read,
|
||||
vg_write:_vg_write,
|
||||
};
|
||||
|
||||
struct format_instance *create_lvm1_format(struct cmd_context *cmd)
|
||||
struct format_instance *_create_instance(struct format_type *fmt,
|
||||
const char *vgname, void *private)
|
||||
{
|
||||
struct format_instance *fi = dbg_malloc(sizeof(*fi));
|
||||
struct format_instance *fid;
|
||||
struct metadata_area *mda;
|
||||
|
||||
if (!fi) {
|
||||
if (!(fid = pool_alloc(fmt->cmd->mem, sizeof(*fid)))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fi->cmd = cmd;
|
||||
fi->ops = &_format1_ops;
|
||||
fi->private = NULL;
|
||||
fid->fmt = fmt;
|
||||
list_init(&fid->metadata_areas);
|
||||
|
||||
return fi;
|
||||
/* Define a NULL metadata area */
|
||||
if (!(mda = pool_alloc(fmt->cmd->mem, sizeof(*mda)))) {
|
||||
stack;
|
||||
pool_free(fmt->cmd->mem, fid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mda->ops = &_metadata_format1_ops;
|
||||
mda->metadata_locn = NULL;
|
||||
list_add(&fid->metadata_areas, &mda->list);
|
||||
|
||||
return fid;
|
||||
}
|
||||
|
||||
void _destroy_instance(struct format_instance *fid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void _destroy(struct format_type *fmt)
|
||||
{
|
||||
dbg_free(fmt);
|
||||
}
|
||||
|
||||
static struct format_handler _format1_ops = {
|
||||
pv_read:_pv_read,
|
||||
pv_setup:_pv_setup,
|
||||
pv_write:_pv_write,
|
||||
lv_setup:_lv_setup,
|
||||
vg_setup:_vg_setup,
|
||||
create_instance:_create_instance,
|
||||
destroy_instance:_destroy_instance,
|
||||
destroy:_destroy,
|
||||
};
|
||||
|
||||
#ifdef LVM1_INTERNAL
|
||||
struct format_type *init_lvm1_format(struct cmd_context *cmd)
|
||||
#else /* Shared */
|
||||
struct format_type *init_format(struct cmd_context *cmd)
|
||||
#endif
|
||||
{
|
||||
struct format_type *fmt = dbg_malloc(sizeof(*fmt));
|
||||
|
||||
if (!fmt) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fmt->cmd = cmd;
|
||||
fmt->ops = &_format1_ops;
|
||||
fmt->name = FMT_LVM1_NAME;
|
||||
fmt->alias = NULL;
|
||||
fmt->features = 0;
|
||||
fmt->private = NULL;
|
||||
|
||||
if (!(fmt->labeller = lvm1_labeller_create(fmt))) {
|
||||
log_error("Couldn't create lvm1 label handler.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(label_register_handler(FMT_LVM1_NAME, fmt->labeller))) {
|
||||
log_error("Couldn't register lvm1 label handler.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fmt;
|
||||
}
|
||||
|
@@ -9,6 +9,10 @@
|
||||
|
||||
#include "metadata.h"
|
||||
|
||||
struct format_instance *create_lvm1_format(struct cmd_context *cmd);
|
||||
#define FMT_LVM1_NAME "lvm1"
|
||||
|
||||
#ifdef LVM1_INTERNAL
|
||||
struct format_type *init_lvm1_format(struct cmd_context *cmd);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@@ -6,15 +6,16 @@
|
||||
* This file is released under the LGPL.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "disk-rep.h"
|
||||
#include "dbg_malloc.h"
|
||||
#include "pool.h"
|
||||
#include "hash.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <linux/kdev_t.h>
|
||||
|
||||
static int _check_vg_name(const char *name)
|
||||
{
|
||||
@@ -36,29 +37,8 @@ static char *_create_lv_name(struct pool *mem, const char *full_name)
|
||||
return pool_strdup(mem, ptr);
|
||||
}
|
||||
|
||||
static int _fill_lv_array(struct logical_volume **lvs,
|
||||
struct volume_group *vg, struct disk_list *dl)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
int i = 0;
|
||||
|
||||
list_iterate(lvh, &dl->lvds) {
|
||||
struct lvd_list *ll = list_item(lvh, struct lvd_list);
|
||||
|
||||
if (!(lv = find_lv(vg, ll->lvd.lv_name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lvs[i] = lv;
|
||||
i++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int import_pv(struct pool *mem, struct device *dev,
|
||||
struct volume_group *vg,
|
||||
struct physical_volume *pv, struct pv_disk *pvd)
|
||||
{
|
||||
memset(pv, 0, sizeof(*pv));
|
||||
@@ -70,21 +50,36 @@ int import_pv(struct pool *mem, struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pvd->pv_status & PV_ACTIVE)
|
||||
pv->status |= ACTIVE;
|
||||
/* Store system_id from first PV if PV belongs to a VG */
|
||||
if (vg && !*vg->system_id)
|
||||
strncpy(vg->system_id, pvd->system_id, NAME_LEN);
|
||||
|
||||
if (vg &&
|
||||
strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id)))
|
||||
log_very_verbose("System ID %s on %s differs from %s for "
|
||||
"volume group", pvd->system_id,
|
||||
dev_name(pv->dev), vg->system_id);
|
||||
|
||||
/*
|
||||
* If exported, we still need to flag in pv->status too because
|
||||
* we don't always have a struct volume_group when we need this.
|
||||
*/
|
||||
if (pvd->pv_status & VG_EXPORTED)
|
||||
pv->status |= EXPORTED_VG;
|
||||
|
||||
if (pvd->pv_allocatable)
|
||||
pv->status |= ALLOCATED_PV;
|
||||
pv->status |= ALLOCATABLE_PV;
|
||||
|
||||
pv->size = pvd->pv_size;
|
||||
pv->pe_size = pvd->pe_size;
|
||||
pv->pe_start = pvd->pe_start;
|
||||
pv->pe_count = pvd->pe_total;
|
||||
pv->pe_allocated = pvd->pe_allocated;
|
||||
pv->pe_alloc_count = pvd->pe_allocated;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _system_id(char *system_id)
|
||||
int _system_id(char *s, const char *prefix)
|
||||
{
|
||||
struct utsname uts;
|
||||
|
||||
@@ -93,11 +88,17 @@ static int _system_id(char *system_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
sprintf(system_id, "%s%lu", uts.nodename, time(NULL));
|
||||
if (lvm_snprintf(s, NAME_LEN, "%s%s%lu",
|
||||
prefix, uts.nodename, time(NULL)) < 0) {
|
||||
log_error("Generated system_id too long");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int export_pv(struct pv_disk *pvd, struct physical_volume *pv)
|
||||
int export_pv(struct pool *mem, struct volume_group *vg,
|
||||
struct pv_disk *pvd, struct physical_volume *pv)
|
||||
{
|
||||
memset(pvd, 0, sizeof(*pvd));
|
||||
|
||||
@@ -117,31 +118,72 @@ int export_pv(struct pv_disk *pvd, struct physical_volume *pv)
|
||||
if (pv->vg_name)
|
||||
strncpy(pvd->vg_name, pv->vg_name, sizeof(pvd->vg_name));
|
||||
|
||||
/* Preserve existing system_id if it exists */
|
||||
if (vg && *vg->system_id)
|
||||
strncpy(pvd->system_id, vg->system_id, sizeof(pvd->system_id));
|
||||
|
||||
/* Is VG already exported or being exported? */
|
||||
if (vg && (vg->status & EXPORTED_VG)) {
|
||||
/* Does system_id need setting? */
|
||||
if (!*vg->system_id ||
|
||||
strncmp(vg->system_id, EXPORTED_TAG,
|
||||
sizeof(EXPORTED_TAG) - 1)) {
|
||||
if (!_system_id(pvd->system_id, EXPORTED_TAG)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (strlen(pvd->vg_name) + sizeof(EXPORTED_TAG) >
|
||||
sizeof(pvd->vg_name)) {
|
||||
log_error("Volume group name %s too long to export",
|
||||
pvd->vg_name);
|
||||
return 0;
|
||||
}
|
||||
strcat(pvd->vg_name, EXPORTED_TAG);
|
||||
}
|
||||
|
||||
/* Is VG being imported? */
|
||||
if (vg && !(vg->status & EXPORTED_VG) && *vg->system_id &&
|
||||
!strncmp(vg->system_id, EXPORTED_TAG, sizeof(EXPORTED_TAG) - 1)) {
|
||||
if (!_system_id(pvd->system_id, IMPORTED_TAG)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate system_id if PV is in VG */
|
||||
if (!pvd->system_id || !*pvd->system_id)
|
||||
if (!_system_id(pvd->system_id, "")) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Update internal system_id if we changed it */
|
||||
if (vg &&
|
||||
(!*vg->system_id ||
|
||||
strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id))))
|
||||
strncpy(vg->system_id, pvd->system_id, NAME_LEN);
|
||||
|
||||
//pvd->pv_major = MAJOR(pv->dev);
|
||||
|
||||
if (pv->status & ACTIVE)
|
||||
pvd->pv_status |= PV_ACTIVE;
|
||||
|
||||
if (pv->status & ALLOCATED_PV)
|
||||
if (pv->status & ALLOCATABLE_PV)
|
||||
pvd->pv_allocatable = PV_ALLOCATABLE;
|
||||
|
||||
pvd->pv_size = pv->size;
|
||||
pvd->lv_cur = 0; /* this is set when exporting the lv list */
|
||||
pvd->pe_size = pv->pe_size;
|
||||
if (vg)
|
||||
pvd->pe_size = vg->extent_size;
|
||||
else
|
||||
pvd->pe_size = pv->pe_size;
|
||||
pvd->pe_total = pv->pe_count;
|
||||
pvd->pe_allocated = pv->pe_allocated;
|
||||
pvd->pe_allocated = pv->pe_alloc_count;
|
||||
pvd->pe_start = pv->pe_start;
|
||||
|
||||
if (!_system_id(pvd->system_id)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int import_vg(struct pool *mem,
|
||||
struct volume_group *vg, struct disk_list *dl)
|
||||
struct volume_group *vg, struct disk_list *dl, int partial)
|
||||
{
|
||||
struct vg_disk *vgd = &dl->vgd;
|
||||
memcpy(vg->id.uuid, vgd->vg_uuid, ID_LEN);
|
||||
@@ -156,19 +198,23 @@ int import_vg(struct pool *mem,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vgd->vg_status & VG_ACTIVE)
|
||||
vg->status |= ACTIVE;
|
||||
if (!(vg->system_id = pool_alloc(mem, NAME_LEN))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*vg->system_id = '\0';
|
||||
|
||||
if (vgd->vg_status & VG_EXPORTED)
|
||||
vg->status |= EXPORTED_VG;
|
||||
|
||||
if (vgd->vg_status & VG_EXTENDABLE)
|
||||
vg->status |= EXTENDABLE_VG;
|
||||
vg->status |= RESIZEABLE_VG;
|
||||
|
||||
if (vgd->vg_access & VG_READ)
|
||||
if (partial || (vgd->vg_access & VG_READ))
|
||||
vg->status |= LVM_READ;
|
||||
|
||||
if (vgd->vg_access & VG_WRITE)
|
||||
if (!partial && (vgd->vg_access & VG_WRITE))
|
||||
vg->status |= LVM_WRITE;
|
||||
|
||||
if (vgd->vg_access & VG_CLUSTERED)
|
||||
@@ -182,6 +228,10 @@ int import_vg(struct pool *mem,
|
||||
vg->free_count = vgd->pe_total - vgd->pe_allocated;
|
||||
vg->max_lv = vgd->lv_max;
|
||||
vg->max_pv = vgd->pv_max;
|
||||
|
||||
if (partial)
|
||||
vg->status |= PARTIAL_VG;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -202,13 +252,10 @@ int export_vg(struct vg_disk *vgd, struct volume_group *vg)
|
||||
if (vg->status & SHARED)
|
||||
vgd->vg_access |= VG_SHARED;
|
||||
|
||||
if (vg->status & ACTIVE)
|
||||
vgd->vg_status |= VG_ACTIVE;
|
||||
|
||||
if (vg->status & EXPORTED_VG)
|
||||
vgd->vg_status |= VG_EXPORTED;
|
||||
|
||||
if (vg->status & EXTENDABLE_VG)
|
||||
if (vg->status & RESIZEABLE_VG)
|
||||
vgd->vg_status |= VG_EXTENDABLE;
|
||||
|
||||
vgd->lv_max = vg->max_lv;
|
||||
@@ -226,67 +273,55 @@ int export_vg(struct vg_disk *vgd, struct volume_group *vg)
|
||||
|
||||
int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
|
||||
{
|
||||
int len;
|
||||
memset(&lv->id, 0, sizeof(lv->id));
|
||||
if (!(lv->name = _create_lv_name(mem, lvd->lv_name))) {
|
||||
lvid_from_lvnum(&lv->lvid, &lv->vg->id, lvd->lv_number);
|
||||
|
||||
if (!(lv->name = _create_lv_name(mem, lvd->lv_name))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvd->lv_status & LV_ACTIVE)
|
||||
lv->status |= ACTIVE;
|
||||
lv->status |= VISIBLE_LV;
|
||||
|
||||
if (lvd->lv_status & LV_SPINDOWN)
|
||||
lv->status |= SPINDOWN_LV;
|
||||
|
||||
if (lvd->lv_status & LV_PERSISTENT_MINOR) {
|
||||
lv->status |= FIXED_MINOR;
|
||||
lv->minor = MINOR(lvd->lv_dev);
|
||||
} else
|
||||
lv->minor = -1;
|
||||
|
||||
if (lvd->lv_access & LV_READ)
|
||||
lv->status |= LVM_READ;
|
||||
|
||||
if (lvd->lv_access & LV_WRITE)
|
||||
lv->status |= LVM_WRITE;
|
||||
|
||||
if (lvd->lv_access & LV_SNAPSHOT)
|
||||
lv->status |= SNAPSHOT;
|
||||
|
||||
if (lvd->lv_access & LV_SNAPSHOT_ORG)
|
||||
lv->status |= SNAPSHOT_ORG;
|
||||
|
||||
if (lvd->lv_badblock)
|
||||
lv->status |= BADBLOCK_ON;
|
||||
|
||||
if (lvd->lv_allocation & LV_STRICT)
|
||||
lv->status |= ALLOC_STRICT;
|
||||
|
||||
/* Drop the unused LV_STRICT here */
|
||||
if (lvd->lv_allocation & LV_CONTIGUOUS)
|
||||
lv->status |= ALLOC_CONTIGUOUS;
|
||||
lv->alloc = ALLOC_CONTIGUOUS;
|
||||
else
|
||||
lv->status |= ALLOC_SIMPLE;
|
||||
lv->alloc = ALLOC_NEXT_FREE;
|
||||
|
||||
lv->read_ahead = lvd->lv_read_ahead;
|
||||
lv->stripes = lvd->lv_stripes;
|
||||
lv->size = lvd->lv_size;
|
||||
lv->le_count = lvd->lv_allocated_le;
|
||||
|
||||
lv->size = lvd->lv_size;
|
||||
lv->le_count = lvd->lv_allocated_le;
|
||||
|
||||
len = sizeof(struct pe_specifier) * lv->le_count;
|
||||
if (!(lv->map = pool_alloc(mem, len))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
memset(lv->map, 0, len);
|
||||
list_init(&lv->segments);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void export_lv(struct lv_disk *lvd, struct volume_group *vg,
|
||||
struct logical_volume *lv, const char *dev_dir)
|
||||
static void _export_lv(struct lv_disk *lvd, struct volume_group *vg,
|
||||
struct logical_volume *lv, const char *dev_dir)
|
||||
{
|
||||
memset(lvd, 0, sizeof(*lvd));
|
||||
snprintf(lvd->lv_name, sizeof(lvd->lv_name), "%s%s/%s",
|
||||
dev_dir, vg->name, lv->name);
|
||||
|
||||
/* FIXME: Add 'if' test */
|
||||
_check_vg_name(vg->name);
|
||||
strcpy(lvd->vg_name, vg->name);
|
||||
|
||||
if (lv->status & LVM_READ)
|
||||
@@ -295,78 +330,49 @@ void export_lv(struct lv_disk *lvd, struct volume_group *vg,
|
||||
if (lv->status & LVM_WRITE)
|
||||
lvd->lv_access |= LV_WRITE;
|
||||
|
||||
if (lv->status & SNAPSHOT)
|
||||
lvd->lv_access |= LV_SNAPSHOT;
|
||||
|
||||
if (lv->status & SNAPSHOT_ORG)
|
||||
lvd->lv_access |= LV_SNAPSHOT_ORG;
|
||||
|
||||
if (lv->status & ACTIVE)
|
||||
lvd->lv_status |= LV_ACTIVE;
|
||||
|
||||
if (lv->status & SPINDOWN_LV)
|
||||
lvd->lv_status |= LV_SPINDOWN;
|
||||
|
||||
lvd->lv_read_ahead = lv->read_ahead;
|
||||
lvd->lv_stripes = lv->stripes;
|
||||
if (lv->status & FIXED_MINOR) {
|
||||
lvd->lv_status |= LV_PERSISTENT_MINOR;
|
||||
lvd->lv_dev = MKDEV(0, lv->minor);
|
||||
}
|
||||
|
||||
lvd->lv_size = lv->size;
|
||||
lvd->lv_allocated_le = lv->le_count;
|
||||
lvd->lv_read_ahead = lv->read_ahead;
|
||||
lvd->lv_stripes = list_item(lv->segments.n, struct lv_segment)->stripes;
|
||||
lvd->lv_stripesize = list_item(lv->segments.n,
|
||||
struct lv_segment)->stripe_size;
|
||||
|
||||
lvd->lv_size = lv->size;
|
||||
lvd->lv_allocated_le = lv->le_count;
|
||||
|
||||
if (lv->status & BADBLOCK_ON)
|
||||
lvd->lv_badblock = LV_BADBLOCK_ON;
|
||||
|
||||
if (lv->status & ALLOC_STRICT)
|
||||
lvd->lv_allocation |= LV_STRICT;
|
||||
|
||||
if (lv->status & ALLOC_CONTIGUOUS)
|
||||
if (lv->alloc == ALLOC_CONTIGUOUS)
|
||||
lvd->lv_allocation |= LV_CONTIGUOUS;
|
||||
}
|
||||
|
||||
int import_extents(struct pool *mem, struct volume_group *vg, struct list *pvds)
|
||||
int export_extents(struct disk_list *dl, int lv_num,
|
||||
struct logical_volume *lv, struct physical_volume *pv)
|
||||
{
|
||||
struct disk_list *dl;
|
||||
struct logical_volume *lv, *lvs[MAX_LV];
|
||||
struct physical_volume *pv;
|
||||
struct pe_disk *e;
|
||||
int i;
|
||||
uint32_t lv_num, le;
|
||||
struct list *pvdh;
|
||||
struct list *segh;
|
||||
struct pe_disk *ped;
|
||||
struct lv_segment *seg;
|
||||
uint32_t pe, s;
|
||||
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
pv = _find_pv(vg, dl->dev);
|
||||
e = dl->extents;
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
|
||||
/* build an array of lv's for this pv */
|
||||
if (!_fill_lv_array(lvs, vg, dl)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
for (s = 0; s < seg->stripes; s++) {
|
||||
if (seg->area[s].pv != pv)
|
||||
continue; /* not our pv */
|
||||
|
||||
for (i = 0; i < dl->pvd.pe_total; i++) {
|
||||
lv_num = e[i].lv_num;
|
||||
|
||||
if (lv_num == UNMAPPED_EXTENT)
|
||||
continue;
|
||||
|
||||
else if(lv_num > dl->pvd.lv_cur) {
|
||||
log_err("invalid lv in extent map\n");
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
lv_num--;
|
||||
lv = lvs[lv_num];
|
||||
le = e[i].le_num;
|
||||
|
||||
if (le >= lv->le_count) {
|
||||
log_err("logical extent number "
|
||||
"out of bounds");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv->map[le].pv = pv;
|
||||
lv->map[le].pe = i;
|
||||
for (pe = 0; pe < (seg->len / seg->stripes); pe++) {
|
||||
ped = &dl->extents[pe + seg->area[s].pe];
|
||||
ped->lv_num = lv_num;
|
||||
ped->le_num = (seg->le / seg->stripes) + pe +
|
||||
s * (lv->le_count / seg->stripes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -374,25 +380,9 @@ int import_extents(struct pool *mem, struct volume_group *vg, struct list *pvds)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int export_extents(struct disk_list *dl, int lv_num,
|
||||
struct logical_volume *lv,
|
||||
struct physical_volume *pv)
|
||||
{
|
||||
struct pe_disk *ped;
|
||||
int le;
|
||||
|
||||
for (le = 0; le < lv->le_count; le++) {
|
||||
if (lv->map[le].pv == pv) {
|
||||
ped = &dl->extents[lv->map[le].pe];
|
||||
ped->lv_num = lv_num;
|
||||
ped->le_num = le;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int import_pvs(struct pool *mem, struct list *pvds,
|
||||
struct list *results, int *count)
|
||||
int import_pvs(struct format_type *fmt, struct pool *mem,
|
||||
struct volume_group *vg,
|
||||
struct list *pvds, struct list *results, int *count)
|
||||
{
|
||||
struct list *pvdh;
|
||||
struct disk_list *dl;
|
||||
@@ -400,19 +390,21 @@ int import_pvs(struct pool *mem, struct list *pvds,
|
||||
|
||||
*count = 0;
|
||||
list_iterate(pvdh, pvds) {
|
||||
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
pvl = pool_alloc(mem, sizeof(*pvl));
|
||||
|
||||
if (!pvl) {
|
||||
if (!(pvl = pool_alloc(mem, sizeof(*pvl))) ||
|
||||
!(pvl->pv = pool_alloc(mem, sizeof(*pvl->pv)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!import_pv(mem, dl->dev, &pvl->pv, &dl->pvd)) {
|
||||
if (!import_pv(mem, dl->dev, vg, pvl->pv, &dl->pvd)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pvl->pv->fmt = fmt;
|
||||
list_add(results, &pvl->list);
|
||||
(*count)++;
|
||||
}
|
||||
@@ -424,29 +416,29 @@ static struct logical_volume *_add_lv(struct pool *mem,
|
||||
struct volume_group *vg,
|
||||
struct lv_disk *lvd)
|
||||
{
|
||||
struct lv_list *ll = pool_zalloc(mem, sizeof(*ll));
|
||||
struct lv_list *ll;
|
||||
struct logical_volume *lv;
|
||||
|
||||
if (!ll) {
|
||||
if (!(ll = pool_zalloc(mem, sizeof(*ll))) ||
|
||||
!(ll->lv = pool_zalloc(mem, sizeof(*ll->lv)))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
lv = &ll->lv;
|
||||
lv = ll->lv;
|
||||
lv->vg = vg;
|
||||
|
||||
if (!import_lv(mem, &ll->lv, lvd)) {
|
||||
if (!import_lv(mem, lv, lvd)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_add(&vg->lvs, &ll->list);
|
||||
lv->vg = vg;
|
||||
vg->lv_count++;
|
||||
|
||||
return lv;
|
||||
}
|
||||
|
||||
int import_lvs(struct pool *mem, struct volume_group *vg,
|
||||
struct list *pvds)
|
||||
int import_lvs(struct pool *mem, struct volume_group *vg, struct list *pvds)
|
||||
{
|
||||
struct disk_list *dl;
|
||||
struct lvd_list *ll;
|
||||
@@ -470,13 +462,26 @@ int import_lvs(struct pool *mem, struct volume_group *vg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME: tidy */
|
||||
int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||
struct physical_volume *pv, const char *dev_dir)
|
||||
{
|
||||
struct list *lvh;
|
||||
int r = 0;
|
||||
struct list *lvh, *sh;
|
||||
struct lv_list *ll;
|
||||
struct lvd_list *lvdl;
|
||||
int lv_num = 0, len;
|
||||
int lv_num, len;
|
||||
struct hash_table *lvd_hash;
|
||||
|
||||
if (!_check_vg_name(vg->name)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(lvd_hash = hash_create(32))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* setup the pv's extents array
|
||||
@@ -484,29 +489,142 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||
len = sizeof(struct pe_disk) * dl->pvd.pe_total;
|
||||
if (!(dl->extents = pool_alloc(dl->mem, len))) {
|
||||
stack;
|
||||
return 0;
|
||||
goto out;
|
||||
}
|
||||
memset(dl->extents, 0, len);
|
||||
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
ll = list_item(lvh, struct lv_list);
|
||||
if (!(lvdl = pool_alloc(dl->mem, sizeof(*lvdl)))) {
|
||||
stack;
|
||||
return 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
export_lv(&lvdl->lvd, vg, &ll->lv, dev_dir);
|
||||
_export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
|
||||
|
||||
lv_num = lvnum_from_lvid(&ll->lv->lvid);
|
||||
|
||||
lvdl->lvd.lv_number = lv_num;
|
||||
if (!export_extents(dl, lv_num + 1, &ll->lv, pv)) {
|
||||
|
||||
if (!hash_insert(lvd_hash, ll->lv->name, &lvdl->lvd)) {
|
||||
stack;
|
||||
return 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!export_extents(dl, lv_num + 1, ll->lv, pv)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
list_add(&dl->lvds, &lvdl->list);
|
||||
dl->pvd.lv_cur++;
|
||||
lv_num++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we need to run through the snapshots, exporting
|
||||
* the SNAPSHOT_ORG flags etc.
|
||||
*/
|
||||
list_iterate(sh, &vg->snapshots) {
|
||||
struct lv_disk *org, *cow;
|
||||
struct snapshot *s = list_item(sh,
|
||||
struct snapshot_list)->snapshot;
|
||||
|
||||
if (!(org = hash_lookup(lvd_hash, s->origin->name))) {
|
||||
log_err("Couldn't find snapshot origin '%s'.",
|
||||
s->origin->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(cow = hash_lookup(lvd_hash, s->cow->name))) {
|
||||
log_err("Couldn't find snapshot cow store '%s'.",
|
||||
s->cow->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
org->lv_access |= LV_SNAPSHOT_ORG;
|
||||
cow->lv_access |= LV_SNAPSHOT;
|
||||
cow->lv_snapshot_minor = org->lv_number;
|
||||
cow->lv_chunk_size = s->chunk_size;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
hash_destroy(lvd_hash);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: More inefficient code.
|
||||
*/
|
||||
int import_snapshots(struct pool *mem, struct volume_group *vg,
|
||||
struct list *pvds)
|
||||
{
|
||||
struct logical_volume *lvs[MAX_LV];
|
||||
struct list *pvdh, *lvdh;
|
||||
struct disk_list *dl;
|
||||
struct lv_disk *lvd;
|
||||
int lvnum;
|
||||
struct logical_volume *org, *cow;
|
||||
|
||||
/* build an index of lv numbers */
|
||||
memset(lvs, 0, sizeof(lvs));
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
|
||||
list_iterate(lvdh, &dl->lvds) {
|
||||
lvd = &(list_item(lvdh, struct lvd_list)->lvd);
|
||||
|
||||
lvnum = lvd->lv_number;
|
||||
|
||||
if (lvnum > MAX_LV) {
|
||||
log_err("Logical volume number "
|
||||
"out of bounds.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lvs[lvnum] &&
|
||||
!(lvs[lvnum] = find_lv(vg, lvd->lv_name))) {
|
||||
log_err("Couldn't find logical volume '%s'.",
|
||||
lvd->lv_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now iterate through yet again adding the snapshots.
|
||||
*/
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
|
||||
list_iterate(lvdh, &dl->lvds) {
|
||||
lvd = &(list_item(lvdh, struct lvd_list)->lvd);
|
||||
|
||||
if (!(lvd->lv_access & LV_SNAPSHOT))
|
||||
continue;
|
||||
|
||||
lvnum = lvd->lv_number;
|
||||
cow = lvs[lvnum];
|
||||
if (!(org = lvs[lvd->lv_snapshot_minor])) {
|
||||
log_err("Couldn't find origin logical volume "
|
||||
"for snapshot '%s'.", lvd->lv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we may have already added this snapshot */
|
||||
if (lv_is_cow(cow))
|
||||
continue;
|
||||
|
||||
/* insert the snapshot */
|
||||
if (!vg_add_snapshot(org, cow, 1, NULL,
|
||||
lvd->lv_chunk_size)) {
|
||||
log_err("Couldn't add snapshot.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -524,7 +642,7 @@ int export_uuids(struct disk_list *dl, struct volume_group *vg)
|
||||
}
|
||||
|
||||
memset(ul->uuid, 0, sizeof(ul->uuid));
|
||||
memcpy(ul->uuid, pvl->pv.id.uuid, ID_LEN);
|
||||
memcpy(ul->uuid, pvl->pv->id.uuid, ID_LEN);
|
||||
|
||||
list_add(&dl->uuids, &ul->list);
|
||||
}
|
||||
@@ -532,9 +650,8 @@ int export_uuids(struct disk_list *dl, struct volume_group *vg)
|
||||
}
|
||||
|
||||
/*
|
||||
* This calculates the nasty pv_number and
|
||||
* lv_number fields used by LVM1. Very
|
||||
* inefficient code.
|
||||
* This calculates the nasty pv_number field
|
||||
* used by LVM1.
|
||||
*/
|
||||
void export_numbers(struct list *pvds, struct volume_group *vg)
|
||||
{
|
||||
@@ -569,14 +686,14 @@ void export_pv_act(struct list *pvds)
|
||||
}
|
||||
}
|
||||
|
||||
int export_vg_number(struct list *pvds, const char *vg_name,
|
||||
struct dev_filter *filter)
|
||||
int export_vg_number(struct format_instance *fid, struct list *pvds,
|
||||
const char *vg_name, struct dev_filter *filter)
|
||||
{
|
||||
struct list *pvdh;
|
||||
struct disk_list *dl;
|
||||
int vg_num;
|
||||
|
||||
if (!get_free_vg_number(filter, vg_name, &vg_num)) {
|
||||
if (!get_free_vg_number(fid, filter, vg_name, &vg_num)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -588,4 +705,3 @@ int export_vg_number(struct list *pvds, const char *vg_name,
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user